From 86b3877a9da7ac0e8828c18b4614c79c63d57dd8 Mon Sep 17 00:00:00 2001 From: leo-barreto Date: Tue, 5 Sep 2023 17:18:22 -0300 Subject: [PATCH 001/324] TRD: implementation of DCS Chamber Status processing TRD: setup for config and processing of missing DPs TRD: changed type of run DPs for processing TRD: expanded read DCS macro to include Env and Run objects TRD: setup of FED objects to CCDB TRD: update trd_fed* and trd_cavernHumidity to CCDB TRD: fixed processor-verbosity to enable more verbosity options TRD: trd_cavernHumidity CCDB update interval changed to 2 hours TRD: trd_fedEnvTemp CCDB update interval changed to 0.5 hours TRD: setup for processing logic between trd_fedChamberStatus and trd_fedCFGtag TRD: added runNo to metadata of ChamberStatus and CFGtag TRD: changed runType and fedChamberStatus to more realistic values TRD: new fedChamberStatus and fedCFGtag logic for CCDB update/logging TRD: alarm/warn log setup for changes in fedChamberStatus and fedCFGtag TRD: read fedChamberStatus and fedCFGtag DPs TRD: formatting and clean up TRD: minor changes to follow format TRD: formatting comments TRD: clean up and ordering of variables TRD: differentiated message name for trd_fed* objects TRD: set alarm for FED changes as configurable TRD: better message name for trd_FedEnvTemp TRD: changed type of trd_fedEnvTemp and trd_cavernHumidity objects TRD: removed processing of trd_runType TRD: setup of minimum number of ChamberStatus/CFGtag DPs for CCDB update TRD: new logic for processing of ChamberStatus and CFGtag DPs TRD: deactivated upload of Run DPs to CCDB TRD: comment clean up TRD: new run for update ChamberStatus/CFGtag flag divided in two variables, reset after ChamberStatus/CFGtag update TRD: enabled option of no alarms for ChamberStatus/CFGtag TRD: assumed no duplicated DPs in Processor, changed variable names --- .../include/TRDCalibration/DCSProcessor.h | 62 ++- .../macros/makeTRDCCDBEntryForDCS.C | 8 +- .../calibration/macros/readTRDDCSentries.C | 41 ++ .../TRD/calibration/src/DCSProcessor.cxx | 364 ++++++++++++++++-- .../workflow/TRDDCSDataProcessorSpec.h | 180 ++++++++- .../workflow/trd-dcs-sim-workflow.cxx | 10 +- 6 files changed, 612 insertions(+), 53 deletions(-) diff --git a/Detectors/TRD/calibration/include/TRDCalibration/DCSProcessor.h b/Detectors/TRD/calibration/include/TRDCalibration/DCSProcessor.h index 5b5323ada0e9a..c7620ae6944c3 100644 --- a/Detectors/TRD/calibration/include/TRDCalibration/DCSProcessor.h +++ b/Detectors/TRD/calibration/include/TRDCalibration/DCSProcessor.h @@ -64,10 +64,18 @@ class DCSProcessor bool updateCurrentsDPsCCDB(); bool updateEnvDPsCCDB(); bool updateRunDPsCCDB(); + // LB: new DPs for Fed and Cavern + bool updateFedChamberStatusDPsCCDB(); + bool updateFedCFGtagDPsCCDB(); + bool updateFedEnvTempDPsCCDB(); + bool updateCavernDPsCCDB(); // signal that the CCDB object for the voltages should be updated due to change exceeding threshold bool shouldUpdateVoltages() const { return mShouldUpdateVoltages; } bool shouldUpdateRun() const { return mShouldUpdateRun; } + // LB: Only update ChamberStatus/CFGtag if both conditions are met (complete DPs and new run) + bool shouldUpdateFedChamberStatus() const { return mFedChamberStatusCompleteDPs && mFirstRunEntryForFedChamberStatusUpdate; } + bool shouldUpdateFedCFGtag() const { return mFedCFGtagCompleteDPs && mFirstRunEntryForFedCFGtagUpdate; } // allow access to the CCDB objects from DPL processor CcdbObjectInfo& getccdbGasDPsInfo() { return mCcdbGasDPsInfo; } @@ -75,15 +83,25 @@ class DCSProcessor CcdbObjectInfo& getccdbCurrentsDPsInfo() { return mCcdbCurrentsDPsInfo; } CcdbObjectInfo& getccdbEnvDPsInfo() { return mCcdbEnvDPsInfo; } CcdbObjectInfo& getccdbRunDPsInfo() { return mCcdbRunDPsInfo; } + CcdbObjectInfo& getccdbFedChamberStatusDPsInfo() { return mCcdbFedChamberStatusDPsInfo; } + CcdbObjectInfo& getccdbFedCFGtagDPsInfo() { return mCcdbFedCFGtagDPsInfo; } + CcdbObjectInfo& getccdbFedEnvTempDPsInfo() { return mCcdbFedEnvTempDPsInfo; } + CcdbObjectInfo& getccdbCavernDPsInfo() { return mCcdbCavernDPsInfo; } const std::unordered_map& getTRDGasDPsInfo() const { return mTRDDCSGas; } const std::unordered_map& getTRDVoltagesDPsInfo() const { return mTRDDCSVoltages; } const std::unordered_map& getTRDCurrentsDPsInfo() const { return mTRDDCSCurrents; } const std::unordered_map& getTRDEnvDPsInfo() const { return mTRDDCSEnv; } const std::unordered_map& getTRDRunDPsInfo() const { return mTRDDCSRun; } + const std::unordered_map& getTRDFedChamberStatusDPsInfo() const { return mTRDDCSFedChamberStatus; } + const std::unordered_map& getTRDFedCFGtagDPsInfo() const { return mTRDDCSFedCFGtag; } + const std::unordered_map& getTRDFedEnvTempDPsInfo() const { return mTRDDCSFedEnvTemp; } + const std::unordered_map& getTRDCavernDPsInfo() const { return mTRDDCSCavern; } // settings void setCurrentTS(TFType tf) { mCurrentTS = tf; } void setVerbosity(int v) { mVerbosity = v; } + void setMaxCounterAlarmFed(int alarmfed) { mFedAlarmCounterMax = alarmfed; } + void setFedMinimunDPsForUpdate(int minupdatefed) { mFedMinimunDPsForUpdate = minupdatefed; } // reset methods void clearGasDPsInfo(); @@ -91,6 +109,11 @@ class DCSProcessor void clearCurrentsDPsInfo(); void clearEnvDPsInfo(); void clearRunDPsInfo(); + // LB: new DPs for Fed and Cavern + void clearFedChamberStatusDPsInfo(); + void clearFedCFGtagDPsInfo(); + void clearFedEnvTempDPsInfo(); + void clearCavernDPsInfo(); // helper functions int getChamberIdFromAlias(const char* alias) const; @@ -102,12 +125,11 @@ class DCSProcessor std::unordered_map mTRDDCSVoltages; ///< anode and drift voltages std::unordered_map mTRDDCSEnv; ///< environment parameters (temperatures, pressures) std::unordered_map mTRDDCSRun; ///< run number and run type - // TODO - // Possibly add CFG tag and chamber status here? - // Or send errors to the InfoLogger in case CFG tag mismatches are detected for chamber which have the same FSM state? - // For this I need more information on the chamber status - which status indicates all good and included in data taking? - // not TODO - // I don't think the FED ENV temperature is needed at analysis level at any point in time so I am leaving it out for now + // LB: new DPs for Fed and Cavern + std::unordered_map mTRDDCSFedChamberStatus; ///< fed chamber status + std::unordered_map mTRDDCSFedCFGtag; ///< fed config tag + std::unordered_map mTRDDCSFedEnvTemp; ///< fed env temperature + std::unordered_map mTRDDCSCavern; ///< cavern humidity // helper variables std::unordered_map mPids; ///< flag for each DP whether it has been processed at least once @@ -117,24 +139,52 @@ class DCSProcessor CcdbObjectInfo mCcdbCurrentsDPsInfo; CcdbObjectInfo mCcdbEnvDPsInfo; CcdbObjectInfo mCcdbRunDPsInfo; + // LB: new DPs for Fed and Cavern + CcdbObjectInfo mCcdbFedChamberStatusDPsInfo; + CcdbObjectInfo mCcdbFedCFGtagDPsInfo; + CcdbObjectInfo mCcdbFedEnvTempDPsInfo; + CcdbObjectInfo mCcdbCavernDPsInfo; + TFType mGasStartTS; ///< the time stamp of the first TF which was processesd for the current GAS CCDB object TFType mVoltagesStartTS; ///< the time stamp of the first TF which was processesd for the current voltages CCDB object TFType mCurrentsStartTS; ///< the time stamp of the first TF which was processesd for the current voltages CCDB object TFType mEnvStartTS; TFType mRunStartTS; TFType mRunEndTS; + // LB: new DPs for Fed and Cavern + TFType mFedChamberStatusStartTS; + TFType mFedCFGtagStartTS; + TFType mFedEnvTempStartTS; + TFType mCavernStartTS; TFType mCurrentTS{0}; ///< the time stamp of the TF currently being processed bool mGasStartTSset{false}; bool mVoltagesStartTSSet{false}; bool mCurrentsStartTSSet{false}; bool mEnvStartTSSet{false}; bool mRunStartTSSet{false}; + // LB: new DPs for Fed and Cavern + bool mFedChamberStatusStartTSSet{false}; + bool mFedCFGtagStartTSSet{false}; + bool mFedEnvTempStartTSSet{false}; + bool mCavernStartTSSet{false}; std::bitset mVoltageSet{}; bool mShouldUpdateVoltages{false}; bool mShouldUpdateRun{false}; + // LB: FedChamberStatus and FedCFGtag logic + bool mFedChamberStatusCompleteDPs{false}; + bool mFedCFGtagCompleteDPs{false}; + bool mFirstRunEntryForFedChamberStatusUpdate{false}; + bool mFirstRunEntryForFedCFGtagUpdate{false}; + int mCurrentRunNumber{-1}; + int mFedChamberStatusAlarmCounter{0}; + int mFedCFGtagAlarmCounter{0}; + // LB: for testing runNo object, turned off for now + // int mFinishedRunNumber; // settings int mVerbosity{0}; + int mFedAlarmCounterMax{1}; + int mFedMinimunDPsForUpdate{540}; ClassDefNV(DCSProcessor, 0); }; diff --git a/Detectors/TRD/calibration/macros/makeTRDCCDBEntryForDCS.C b/Detectors/TRD/calibration/macros/makeTRDCCDBEntryForDCS.C index 55de2e0759aa1..f99f0a3822f49 100644 --- a/Detectors/TRD/calibration/macros/makeTRDCCDBEntryForDCS.C +++ b/Detectors/TRD/calibration/macros/makeTRDCCDBEntryForDCS.C @@ -36,9 +36,11 @@ int makeTRDCCDBEntryForDCS(const std::string url = "http://localhost:8080") aliasesFloat.insert(aliasesFloat.end(), {"trd_aliEnvTempCavern", "trd_aliEnvTempP2"}); aliasesFloat.insert(aliasesFloat.end(), {"trd_aliEnvPressure00", "trd_aliEnvPressure01", "trd_aliEnvPressure02"}); aliasesInt.insert(aliasesInt.end(), {"trd_runNo", "trd_runType"}); - // aliasesFloat.insert(aliasesFloat.end(), {"trd_cavernHumidity", "trd_fedEnvTemp[00..539]"}); - // aliasesInt.insert(aliasesInt.end(), {"trd_fedChamberStatus[00..539]"}); - // aliasesString.insert(aliasesString.end(), {"trd_fedCFGtag[00..539]"}); + + // New DPs + aliasesFloat.insert(aliasesFloat.end(), {"trd_cavernHumidity", "trd_fedEnvTemp[00..539]"}); + aliasesInt.insert(aliasesInt.end(), {"trd_fedChamberStatus[00..539]"}); + aliasesString.insert(aliasesString.end(), {"trd_fedCFGtag[00..539]"}); DPID dpidTmp; for (const auto& ali : o2::dcs::expandAliases(aliasesFloat)) { diff --git a/Detectors/TRD/calibration/macros/readTRDDCSentries.C b/Detectors/TRD/calibration/macros/readTRDDCSentries.C index 76bc14b340a1b..2942b9bf14443 100644 --- a/Detectors/TRD/calibration/macros/readTRDDCSentries.C +++ b/Detectors/TRD/calibration/macros/readTRDDCSentries.C @@ -31,6 +31,7 @@ void readTRDDCSentries(std::string ccdb = "http://localhost:8080", long ts = -1) ccdbmgr.setURL(ccdb.c_str()); // comment out this line to read from production CCDB instead of a local one, or adapt ccdb string if (ts < 0) { ts = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + std::cout << "Timestamp: " << ts << std::endl; } ccdbmgr.setTimestamp(ts); @@ -60,5 +61,45 @@ void readTRDDCSentries(std::string ccdb = "http://localhost:8080", long ts = -1) } std::cout << std::endl; + // LB: also read FedChamberStatus and FedCFGtag for testing + // There seems to be an issue with the validity timestamp of Run DPs, ignoring them at the moment + // Access FedChamberStatus DPs + auto calchamberstatus = ccdbmgr.get>("TRD/Calib/DCSDPsFedChamberStatus"); + + std::cout << "Print all objects from the map (DCSDPsFedChamberStatus), together with their DataPointIdentifier:" << std::endl; + for (const auto& entry : *calchamberstatus) { + std::cout << "id = " << entry.first << ",\tvalue = " << entry.second << std::endl; + } + std::cout << std::endl; + + // Access FedCFGtag DPs + auto calcfgtag = ccdbmgr.get>("TRD/Calib/DCSDPsFedCFGtag"); + + std::cout << "Print all objects from the map (DCSDPsFedCFGtag), together with their DataPointIdentifier:" << std::endl; + for (const auto& entry : *calcfgtag) { + std::cout << "id = " << entry.first << ",\tvalue = " << entry.second << std::endl; + } + std::cout << std::endl; + + // Access FedEnvTemp DPs + auto calfedenvtemp = ccdbmgr.get>("TRD/Calib/DCSDPsFedEnvTemp"); + + for (const auto& entry : *calfedenvtemp) { + std::cout << entry.first << std::endl; + entry.second.print(); + std::cout << std::endl; + } + + // Access Cavern DPs + auto calcavern = ccdbmgr.get>("TRD/Calib/DCSDPsCavern"); + + for (const auto& entry : *calcavern) { + std::cout << entry.first << std::endl; + entry.second.print(); + std::cout << std::endl; + } + + std::cout << std::endl; + return; } diff --git a/Detectors/TRD/calibration/src/DCSProcessor.cxx b/Detectors/TRD/calibration/src/DCSProcessor.cxx index 2ef3ca1dd673d..12097a8e20c49 100644 --- a/Detectors/TRD/calibration/src/DCSProcessor.cxx +++ b/Detectors/TRD/calibration/src/DCSProcessor.cxx @@ -43,12 +43,41 @@ int DCSProcessor::process(const gsl::span dps) LOG(info) << "\n\n\nProcessing new TF\n-----------------"; } - if (mVerbosity > 1) { - std::unordered_map mapin; - for (auto& it : dps) { - mapin[it.id] = it.data; + // LB: setup counters for ChamberStatus/CFGtag logic + int ChamberStatusDPsCounter = 0; + int CFGtagDPsCounter = 0; + + std::unordered_map mapin; + for (auto& it : dps) { + mapin[it.id] = it.data; + + // LB: check if all ChamberStatus/CFGtag DPs were sent in dps + // if counter is equal to 540 => all DPs were sent + if (std::strstr(it.id.get_alias(), "trd_fedChamberStatus") != nullptr) { + ChamberStatusDPsCounter++; + } else if (std::strstr(it.id.get_alias(), "trd_fedCFGtag") != nullptr) { + CFGtagDPsCounter++; + } + } + + if (ChamberStatusDPsCounter >= mFedMinimunDPsForUpdate) { + mFedChamberStatusCompleteDPs = true; + if (mVerbosity > 1) { + LOG(info) << "Minimum number of required DPs (" << mFedMinimunDPsForUpdate << ") for ChamberStatus update were found."; } + } + if (CFGtagDPsCounter >= mFedMinimunDPsForUpdate) { + mFedCFGtagCompleteDPs = true; + if (mVerbosity > 1) { + LOG(info) << "Minimum number of required DPs (" << mFedMinimunDPsForUpdate << ") for CFGtag update were found."; + } + } + if (mVerbosity > 1) { + LOG(info) << "Number of ChamberStatus DPs = " << ChamberStatusDPsCounter; + LOG(info) << "Number of CFGtag DPs = " << CFGtagDPsCounter; + } + if (mVerbosity > 1) { for (auto& it : mPids) { const auto& el = mapin.find(it.first); if (el == mapin.end()) { @@ -96,8 +125,10 @@ int DCSProcessor::processDP(const DPCOM& dpcom) } auto flags = dpcom.data.get_flags(); if (processFlags(flags, dpid.get_alias()) == 0) { + auto etime = dpcom.data.get_epoch_time(); + + // DPs are sorted by type variable if (type == DPVAL_DOUBLE) { - auto etime = dpcom.data.get_epoch_time(); // check if DP is one of the gas values if (std::strstr(dpid.get_alias(), "trd_gas") != nullptr) { @@ -163,42 +194,116 @@ int DCSProcessor::processDP(const DPCOM& dpcom) mLastDPTimeStamps[dpid] = etime; } } + + if (std::strstr(dpid.get_alias(), "trd_fedEnvTemp") != nullptr) { // DP is trd_fedEnvTemp + if (!mFedEnvTempStartTSSet) { + mFedEnvTempStartTS = mCurrentTS; + mFedEnvTempStartTSSet = true; + } + auto& dpInfoFedEnvTemp = mTRDDCSFedEnvTemp[dpid]; + if (dpInfoFedEnvTemp.nPoints == 0 || etime != mLastDPTimeStamps[dpid]) { + // only add data point in case last one was not already read before + dpInfoFedEnvTemp.addPoint(o2::dcs::getValue(dpcom), etime); + mLastDPTimeStamps[dpid] = etime; + } + } + + if (std::strstr(dpid.get_alias(), "trd_cavernHumidity") != nullptr) { // DP is trd_cavernHumidity + if (!mCavernStartTSSet) { + mCavernStartTS = mCurrentTS; + mCavernStartTSSet = true; + } + auto& dpInfoCavern = mTRDDCSCavern[dpid]; + if (dpInfoCavern.nPoints == 0 || etime != mLastDPTimeStamps[dpid]) { + // only add data point in case last one was not already read before + dpInfoCavern.addPoint(o2::dcs::getValue(dpcom), etime); + mLastDPTimeStamps[dpid] = etime; + } + } } + if (type == DPVAL_INT) { if (std::strstr(dpid.get_alias(), "trd_runNo") != nullptr) { // DP is trd_runNo if (!mRunStartTSSet) { mRunStartTS = mCurrentTS; mRunStartTSSet = true; } + auto& runNumber = mTRDDCSRun[dpid]; - if (mPids[dpid] && runNumber != o2::dcs::getValue(dpcom)) { - LOGF(info, "Run number has already been processed and the new one %i differs from the old one %i", runNumber, o2::dcs::getValue(dpcom)); - mShouldUpdateRun = true; - mRunEndTS = mCurrentTS; - } else { - runNumber = o2::dcs::getValue(dpcom); - } - } else if (std::strstr(dpid.get_alias(), "trd_runType") != nullptr) { // DP is trd_runType - if (!mRunStartTSSet) { - mRunStartTS = mCurrentTS; - mRunStartTSSet = true; + + // LB: Check if new value is a valid run number (0 = cleared variable) + if (o2::dcs::getValue(dpcom) > 0) { + // If value has changed from previous one, new run has begun and update + if (o2::dcs::getValue(dpcom) != mCurrentRunNumber) { + LOG(info) << "New run number " << o2::dcs::getValue(dpcom) << " differs from the old one " << mCurrentRunNumber; + mShouldUpdateRun = true; + // LB: two different flags as they reset separately, after upload of CCDB, for each object + mFirstRunEntryForFedChamberStatusUpdate = true; + mFirstRunEntryForFedCFGtagUpdate = true; + mRunEndTS = mCurrentTS; + } + + // LB: Save current run number + mCurrentRunNumber = o2::dcs::getValue(dpcom); + // Save to mTRDDCSRun + runNumber = mCurrentRunNumber; + } + + if (mVerbosity > 2) { + LOG(info) << "Current Run Number: " << mCurrentRunNumber; + } + + } else if (std::strstr(dpid.get_alias(), "trd_fedChamberStatus") != nullptr) { // DP is trd_fedChamberStatus + if (!mFedChamberStatusStartTSSet) { + mFedChamberStatusStartTS = mCurrentTS; + mFedChamberStatusStartTSSet = true; } - auto& runType = mTRDDCSRun[dpid]; - if (mPids[dpid] && runType != o2::dcs::getValue(dpcom)) { - LOGF(info, "Run type has already been processed and the new one %i differs from the old one %i", runType, o2::dcs::getValue(dpcom)); - mShouldUpdateRun = true; - mRunEndTS = mCurrentTS; - } else { - runType = o2::dcs::getValue(dpcom); + + auto& dpInfoFedChamberStatus = mTRDDCSFedChamberStatus[dpid]; + if (etime != mLastDPTimeStamps[dpid]) { + if (dpInfoFedChamberStatus != o2::dcs::getValue(dpcom)) { + // If value changes after processing and DPs should not be updated, log change as warning (for now) + if (mPids[dpid] && !(mFedChamberStatusCompleteDPs && mFirstRunEntryForFedChamberStatusUpdate)) { + // Issue an alarm if counter is lower than maximum, warning otherwise + if (mFedChamberStatusAlarmCounter < mFedAlarmCounterMax) { + LOG(alarm) << "ChamberStatus change " << dpid.get_alias() << " : " << dpInfoFedChamberStatus << " -> " << o2::dcs::getValue(dpcom) << ", run = " << mCurrentRunNumber; + mFedChamberStatusAlarmCounter++; + } else if (mVerbosity > 0) { + LOG(warn) << "ChamberStatus change " << dpid.get_alias() << " : " << dpInfoFedChamberStatus << " -> " << o2::dcs::getValue(dpcom) << ", run = " << mCurrentRunNumber; + } + } + } + + dpInfoFedChamberStatus = o2::dcs::getValue(dpcom); + mLastDPTimeStamps[dpid] = etime; } } } if (type == DPVAL_STRING) { if (std::strstr(dpid.get_alias(), "trd_fedCFGtag") != nullptr) { // DP is trd_fedCFGtag - auto cfgTag = o2::dcs::getValue(dpcom); - if (mVerbosity > 1) { - LOG(info) << "CFG tag " << dpid.get_alias() << " is " << cfgTag; + if (!mFedCFGtagStartTSSet) { + mFedCFGtagStartTS = mCurrentTS; + mFedCFGtagStartTSSet = true; + } + + auto& dpInfoFedCFGtag = mTRDDCSFedCFGtag[dpid]; + if (etime != mLastDPTimeStamps[dpid]) { + if (dpInfoFedCFGtag != o2::dcs::getValue(dpcom)) { + // If value changes after processing and DPs should not be updated, log change as warning (for now) + if (mPids[dpid] && !(mFedCFGtagCompleteDPs && mFirstRunEntryForFedCFGtagUpdate)) { + // Issue an alarm if counter is lower than maximum, warning otherwise + if (mFedCFGtagAlarmCounter < mFedAlarmCounterMax) { + LOG(alarm) << "CFGtag change " << dpid.get_alias() << " : " << dpInfoFedCFGtag << " -> " << o2::dcs::getValue(dpcom) << ", run = " << mCurrentRunNumber; + mFedCFGtagAlarmCounter++; + } else if (mVerbosity > 0) { + LOG(warn) << "CFGtag change " << dpid.get_alias() << " : " << dpInfoFedCFGtag << " -> " << o2::dcs::getValue(dpcom) << ", run = " << mCurrentRunNumber; + } + } + } + + dpInfoFedCFGtag = o2::dcs::getValue(dpcom); + mLastDPTimeStamps[dpid] = etime; } } } @@ -349,7 +454,7 @@ bool DCSProcessor::updateVoltagesDPsCCDB() retVal = true; } if (mVerbosity > 1) { - LOG(info) << "PID = " << it.first.get_alias() << " Value = " << mTRDDCSVoltages[it.first]; + LOG(info) << "PID = " << it.first.get_alias() << ". Value = " << mTRDDCSVoltages[it.first]; } } } @@ -375,7 +480,7 @@ bool DCSProcessor::updateEnvDPsCCDB() if (it.second == true) { // we processed the DP at least 1x retVal = true; } - if (mVerbosity > 0) { + if (mVerbosity > 1) { LOG(info) << "PID = " << it.first.get_alias(); mTRDDCSEnv[it.first].print(); } @@ -398,7 +503,7 @@ bool DCSProcessor::updateRunDPsCCDB() for (const auto& it : mPids) { const auto& type = it.first.get_type(); - if (type == o2::dcs::DPVAL_DOUBLE) { + if (type == o2::dcs::DPVAL_INT) { if (std::strstr(it.first.get_alias(), "trd_run") != nullptr) { if (it.second == true) { // we processed the DP at least 1x retVal = true; @@ -410,9 +515,135 @@ bool DCSProcessor::updateRunDPsCCDB() } } std::map md; - md["responsible"] = "Ole Schmidt"; + md["responsible"] = "Leonardo Barreto"; + // Redundancy for testing, this object is updated after run ended, so need to write old run number, not current + // md["runNumber"] = std::to_string(mFinishedRunNumber); o2::calibration::Utils::prepareCCDBobjectInfo(mTRDDCSRun, mCcdbRunDPsInfo, "TRD/Calib/DCSDPsRun", md, mRunStartTS, mRunEndTS); + // LB: Deactivated upload of Run DPs to CCDB even if processed + // To turn it back on just comment the next line + retVal = false; + return retVal; +} + +bool DCSProcessor::updateFedChamberStatusDPsCCDB() +{ + // here we create the object containing the fedChamberStatus data points to then be sent to CCDB + LOG(info) << "Preparing CCDB object for TRD fedChamberStatus DPs"; + + bool retVal = false; // set to 'true' in case at least one DP for run has been processed + + for (const auto& it : mPids) { + const auto& type = it.first.get_type(); + if (type == o2::dcs::DPVAL_INT) { + if (std::strstr(it.first.get_alias(), "trd_fedChamberStatus") != nullptr) { + if (it.second == true) { // we processed the DP at least 1x + retVal = true; + } + if (mVerbosity > 1) { + LOG(info) << "PID = " << it.first.get_alias() << ". Value = " << mTRDDCSFedChamberStatus[it.first]; + } + } + } + } + + std::map md; + md["responsible"] = "Leonardo Barreto"; + md["runNumber"] = std::to_string(mCurrentRunNumber); + // TODO: define mFedStartTS and mFedEndTS, use same setup as env for now + o2::calibration::Utils::prepareCCDBobjectInfo(mTRDDCSFedChamberStatus, mCcdbFedChamberStatusDPsInfo, "TRD/Calib/DCSDPsFedChamberStatus", md, mFedChamberStatusStartTS, mFedChamberStatusStartTS + 3 * o2::ccdb::CcdbObjectInfo::DAY); + + return retVal; +} + +bool DCSProcessor::updateFedCFGtagDPsCCDB() +{ + // here we create the object containing the fedCFGtag data points to then be sent to CCDB + LOG(info) << "Preparing CCDB object for TRD fedCFGtag DPs"; + + bool retVal = false; // set to 'true' in case at least one DP for run has been processed + + for (const auto& it : mPids) { + const auto& type = it.first.get_type(); + if (type == o2::dcs::DPVAL_STRING) { + if (std::strstr(it.first.get_alias(), "trd_fedCFGtag") != nullptr) { + if (it.second == true) { // we processed the DP at least 1x + retVal = true; + } + if (mVerbosity > 1) { + LOG(info) << "PID = " << it.first.get_alias() << ". Value = " << mTRDDCSFedCFGtag[it.first]; + } + } + } + } + + std::map md; + md["responsible"] = "Leonardo Barreto"; + md["runNumber"] = std::to_string(mCurrentRunNumber); + // TODO: define mFedStartTS and mFedEndTS, use same setup as env for now + o2::calibration::Utils::prepareCCDBobjectInfo(mTRDDCSFedCFGtag, mCcdbFedCFGtagDPsInfo, + "TRD/Calib/DCSDPsFedCFGtag", md, mFedCFGtagStartTS, mFedCFGtagStartTS + 3 * o2::ccdb::CcdbObjectInfo::DAY); + + return retVal; +} + +bool DCSProcessor::updateFedEnvTempDPsCCDB() +{ + // here we create the object containing the fedEnvTemp data points to then be sent to CCDB + LOG(info) << "Preparing CCDB object for TRD fedEnvTemp DPs"; + + bool retVal = false; // set to 'true' in case at least one DP for run has been processed + + for (const auto& it : mPids) { + const auto& type = it.first.get_type(); + if (type == o2::dcs::DPVAL_DOUBLE) { + if (std::strstr(it.first.get_alias(), "trd_fedEnvTemp") != nullptr) { + if (it.second == true) { // we processed the DP at least 1x + retVal = true; + } + if (mVerbosity > 1) { + LOG(info) << "PID = " << it.first.get_alias(); + mTRDDCSFedEnvTemp[it.first].print(); + } + } + } + } + + std::map md; + md["responsible"] = "Leonardo Barreto"; + // TODO: define mFedStartTS and mFedEndTS, use same setup as env for now + o2::calibration::Utils::prepareCCDBobjectInfo(mTRDDCSFedEnvTemp, mCcdbFedEnvTempDPsInfo, + "TRD/Calib/DCSDPsFedEnvTemp", md, mFedEnvTempStartTS, mFedEnvTempStartTS + 3 * o2::ccdb::CcdbObjectInfo::DAY); + + return retVal; +} + +bool DCSProcessor::updateCavernDPsCCDB() +{ + // here we create the object containing the cavern data points to then be sent to CCDB + LOG(info) << "Preparing CCDB object for TRD cavern DPs"; + + bool retVal = false; // set to 'true' in case at least one DP for env has been processed + + for (const auto& it : mPids) { + const auto& type = it.first.get_type(); + if (type == o2::dcs::DPVAL_DOUBLE) { + if (std::strstr(it.first.get_alias(), "trd_cavern") != nullptr) { + if (it.second == true) { // we processed the DP at least 1x + retVal = true; + } + if (mVerbosity > 1) { + LOG(info) << "PID = " << it.first.get_alias(); + mTRDDCSCavern[it.first].print(); + } + } + } + } + std::map md; + md["responsible"] = "Leonardo Barreto"; + // TODO: define mCavernStartTS and mCavernEndTS, use same setup as env for now + o2::calibration::Utils::prepareCCDBobjectInfo(mTRDDCSCavern, mCcdbCavernDPsInfo, "TRD/Calib/DCSDPsCavern", md, mCavernStartTS, mCavernStartTS + 3 * o2::ccdb::CcdbObjectInfo::DAY); + return retVal; } @@ -453,7 +684,6 @@ void DCSProcessor::clearGasDPsInfo() // reset the data and the gas CCDB object itself mTRDDCSGas.clear(); mGasStartTSset = false; // the next object will be valid from the first processed time stamp - // reset the 'processed' flags for the gas DPs for (auto& it : mPids) { const auto& type = it.first.get_type(); @@ -469,7 +699,7 @@ void DCSProcessor::clearEnvDPsInfo() { mTRDDCSEnv.clear(); mEnvStartTSSet = false; - // reset the 'processed' flags for the gas DPs + // reset the 'processed' flags for the env DPs for (auto& it : mPids) { const auto& type = it.first.get_type(); if (type == o2::dcs::DPVAL_DOUBLE) { @@ -485,13 +715,79 @@ void DCSProcessor::clearRunDPsInfo() mTRDDCSRun.clear(); mRunStartTSSet = false; mShouldUpdateRun = false; - // reset the 'processed' flags for the gas DPs + // reset the 'processed' flags for the run DPs for (auto& it : mPids) { const auto& type = it.first.get_type(); - if (type == o2::dcs::DPVAL_DOUBLE) { + if (type == o2::dcs::DPVAL_INT) { if (std::strstr(it.first.get_alias(), "trd_run") != nullptr) { it.second = false; } } } } + +void DCSProcessor::clearFedChamberStatusDPsInfo() +{ + mTRDDCSFedChamberStatus.clear(); + mFedChamberStatusStartTSSet = false; + mFedChamberStatusCompleteDPs = false; + mFirstRunEntryForFedChamberStatusUpdate = false; + mFedChamberStatusAlarmCounter = 0; + // reset the 'processed' flags for the fed DPs + for (auto& it : mPids) { + const auto& type = it.first.get_type(); + if (type == o2::dcs::DPVAL_INT) { + if (std::strstr(it.first.get_alias(), "trd_fedChamberStatus") != nullptr) { + it.second = false; + } + } + } +} + +void DCSProcessor::clearFedCFGtagDPsInfo() +{ + mTRDDCSFedCFGtag.clear(); + mFedCFGtagStartTSSet = false; + mFedCFGtagCompleteDPs = false; + mFirstRunEntryForFedCFGtagUpdate = false; + mFedCFGtagAlarmCounter = 0; + // reset the 'processed' flags for the fed DPs + for (auto& it : mPids) { + const auto& type = it.first.get_type(); + if (type == o2::dcs::DPVAL_STRING) { + if (std::strstr(it.first.get_alias(), "trd_fedCFGtag") != nullptr) { + it.second = false; + } + } + } +} + +void DCSProcessor::clearFedEnvTempDPsInfo() +{ + mTRDDCSFedEnvTemp.clear(); + mFedEnvTempStartTSSet = false; + // reset the 'processed' flags for the fed DPs + for (auto& it : mPids) { + const auto& type = it.first.get_type(); + if (type == o2::dcs::DPVAL_DOUBLE) { + if (std::strstr(it.first.get_alias(), "trd_fedEnvTemp") != nullptr) { + it.second = false; + } + } + } +} + +void DCSProcessor::clearCavernDPsInfo() +{ + mTRDDCSCavern.clear(); + mCavernStartTSSet = false; + // reset the 'processed' flags for the fed DPs + for (auto& it : mPids) { + const auto& type = it.first.get_type(); + if (type == o2::dcs::DPVAL_DOUBLE) { + if (std::strstr(it.first.get_alias(), "trd_cavern") != nullptr) { + it.second = false; + } + } + } +} diff --git a/Detectors/TRD/calibration/workflow/TRDDCSDataProcessorSpec.h b/Detectors/TRD/calibration/workflow/TRDDCSDataProcessorSpec.h index 456d1af4328e2..7a7af3c5e889d 100644 --- a/Detectors/TRD/calibration/workflow/TRDDCSDataProcessorSpec.h +++ b/Detectors/TRD/calibration/workflow/TRDDCSDataProcessorSpec.h @@ -73,6 +73,18 @@ class TRDDCSDataProcessor : public o2::framework::Task LOG(error) << "TRD DPs update interval set to zero seconds --> changed to 1800s"; mEnvDPsUpdateInterval = 1800; } + // LB: FedEnvTemp DPs, only update every 30 minutes + mFedEnvTempDPsUpdateInterval = ic.options().get("DPs-update-interval-fedenv"); + if (mFedEnvTempDPsUpdateInterval == 0) { + LOG(error) << "TRD DPs update interval set to zero seconds --> changed to 1800s"; + mFedEnvTempDPsUpdateInterval = 1800; + } + // LB: Cavern DPs, only update every 2 hours + mCavernDPsUpdateInterval = ic.options().get("DPs-update-interval-cavern"); + if (mCavernDPsUpdateInterval == 0) { + LOG(error) << "TRD DPs update interval set to zero seconds --> changed to 7200s"; + mCavernDPsUpdateInterval = 7200; + } bool useCCDBtoConfigure = ic.options().get("use-ccdb-to-configure"); if (useCCDBtoConfigure) { LOG(info) << "Configuring via CCDB"; @@ -94,10 +106,10 @@ class TRDDCSDataProcessor : public o2::framework::Task aliasesFloat.insert(aliasesFloat.end(), {"trd_hvAnodeImon[00..539]", "trd_hvAnodeUmon[00..539]", "trd_hvDriftImon[00..539]", "trd_hvDriftUmon[00..539]"}); aliasesFloat.insert(aliasesFloat.end(), {"trd_aliEnvTempCavern", "trd_aliEnvTempP2"}); aliasesFloat.insert(aliasesFloat.end(), {"trd_aliEnvPressure00", "trd_aliEnvPressure01", "trd_aliEnvPressure02"}); - // aliasesFloat.insert(aliasesFloat.end(), {"trd_cavernHumidity", "trd_fedEnvTemp[00..539]"}); + aliasesFloat.insert(aliasesFloat.end(), {"trd_cavernHumidity", "trd_fedEnvTemp[00..539]"}); aliasesInt.insert(aliasesInt.end(), {"trd_runNo", "trd_runType"}); - // aliasesInt.insert(aliasesInt.end(), {"trd_fedChamberStatus[00..539]"}); - // aliasesString.insert(aliasesString.end(), {"trd_fedCFGtag[00..539]"}); + aliasesInt.insert(aliasesInt.end(), {"trd_fedChamberStatus[00..539]"}); + aliasesString.insert(aliasesString.end(), {"trd_fedCFGtag[00..539]"}); for (const auto& i : o2::dcs::expandAliases(aliasesFloat)) { vect.emplace_back(i, o2::dcs::DPVAL_DOUBLE); @@ -116,16 +128,40 @@ class TRDDCSDataProcessor : public o2::framework::Task } mProcessor = std::make_unique(); - int verbosity = ic.options().get("processor-verbosity"); + int verbosity = ic.options().get("processor-verbosity"); if (verbosity > 0) { LOG(info) << "Using verbose mode for TRD DCS processor"; mProcessor->setVerbosity(verbosity); } + + // LB: set maximum number of alarms in change in FedChamberStatus and FedCFGtag + int alarmfed = ic.options().get("DPs-max-counter-alarm-fed"); + if (alarmfed >= 0) { + LOG(info) << "Setting max number of alarms in FED objects changes to " << alarmfed; + mProcessor->setMaxCounterAlarmFed(alarmfed); + } else { + LOG(info) << "Invalid max number of alarms in FED objects changes " << alarmfed << ", using default value of 1"; + } + + // LB: set minimum number of DPs in DCS Processor to update ChamberStatus/CFGtag + int minupdatefed = ic.options().get("DPs-min-counter-update-fed"); + if (minupdatefed >= 0 && minupdatefed <= 540) { + LOG(info) << "Setting min number of DPs to update ChamberStatus/CFGtag to " << minupdatefed; + mProcessor->setFedMinimunDPsForUpdate(minupdatefed); + } else { + LOG(info) << "Invalid min number of DPs to update ChamberStatus/CFGtag " << alarmfed << ", using default value of 540"; + } + mProcessor->init(vect); mTimerGas = std::chrono::high_resolution_clock::now(); mTimerVoltages = mTimerGas; mTimerCurrents = mTimerGas; mTimerEnv = mTimerGas; + // LB: new DPs for Fed and Cavern + mTimerFedChamberStatus = mTimerGas; + mTimerFedCFGtag = mTimerGas; + mTimerFedEnvTemp = mTimerGas; + mTimerCavern = mTimerGas; mReportTiming = ic.options().get("report-timing") || verbosity > 0; } @@ -169,6 +205,29 @@ class TRDDCSDataProcessor : public o2::framework::Task mTimerEnv = timeNow; } + // LB: processing logic for FedChamberStatus and FedCFGtag + if (mProcessor->shouldUpdateFedChamberStatus()) { + sendDPsoutputFedChamberStatus(pc.outputs()); + } + + if (mProcessor->shouldUpdateFedCFGtag()) { + sendDPsoutputFedCFGtag(pc.outputs()); + } + + // LB: new DP for FedEnvTemp + auto elapsedTimeFedEnvTemp = timeNow - mTimerFedEnvTemp; // in ns + if (elapsedTimeFedEnvTemp.count() * 1e-9 >= mFedEnvTempDPsUpdateInterval) { + sendDPsoutputFedEnvTemp(pc.outputs()); + mTimerFedEnvTemp = timeNow; + } + + // LB: new DP for Cavern + auto elapsedTimeCavern = timeNow - mTimerCavern; // in ns + if (elapsedTimeCavern.count() * 1e-9 >= mCavernDPsUpdateInterval) { + sendDPsoutputCavern(pc.outputs()); + mTimerCavern = timeNow; + } + if (mProcessor->shouldUpdateRun()) { sendDPsoutputRun(pc.outputs()); } @@ -185,6 +244,11 @@ class TRDDCSDataProcessor : public o2::framework::Task sendDPsoutputCurrents(ec.outputs()); sendDPsoutputEnv(ec.outputs()); sendDPsoutputRun(ec.outputs()); + // LB: new DPs for Fed and Cavern + sendDPsoutputFedChamberStatus(ec.outputs()); + sendDPsoutputFedCFGtag(ec.outputs()); + sendDPsoutputFedEnvTemp(ec.outputs()); + sendDPsoutputCavern(ec.outputs()); } private: @@ -194,11 +258,22 @@ class TRDDCSDataProcessor : public o2::framework::Task std::chrono::high_resolution_clock::time_point mTimerVoltages; std::chrono::high_resolution_clock::time_point mTimerCurrents; std::chrono::high_resolution_clock::time_point mTimerEnv; + // LB: new DPs for Fed and Cavern + std::chrono::high_resolution_clock::time_point mTimerFedChamberStatus; + std::chrono::high_resolution_clock::time_point mTimerFedCFGtag; + std::chrono::high_resolution_clock::time_point mTimerFedEnvTemp; + std::chrono::high_resolution_clock::time_point mTimerCavern; + int64_t mGasDPsUpdateInterval; int64_t mVoltagesDPsUpdateInterval; int64_t mCurrentsDPsUpdateInterval; int64_t mMinUpdateIntervalU; int64_t mEnvDPsUpdateInterval; + // LB: new DPs for Fed and Cavern + int64_t mFedChamberStatusDPsUpdateInterval; + int64_t mFedCFGtagDPsUpdateInterval; + int64_t mFedEnvTempDPsUpdateInterval; + int64_t mCavernDPsUpdateInterval; void sendDPsoutputVoltages(DataAllocator& output) { @@ -289,6 +364,87 @@ class TRDDCSDataProcessor : public o2::framework::Task mProcessor->clearRunDPsInfo(); } else { auto& info = mProcessor->getccdbRunDPsInfo(); + // LOG(info) << "Not sending object " << info.getPath() << "/" << info.getFileName() << " since no DPs were processed for it"; + LOG(info) << "Not sending object " << info.getPath() << "/" << info.getFileName() << " as upload of Run DPs was deactivated"; + } + } + + // LB: new DP for FedChamberStatus + //________________________________________________________________ + void sendDPsoutputFedChamberStatus(DataAllocator& output) + { + // extract CCDB infos and calibration object for DPs + if (mProcessor->updateFedChamberStatusDPsCCDB()) { + const auto& payload = mProcessor->getTRDFedChamberStatusDPsInfo(); + auto& info = mProcessor->getccdbFedChamberStatusDPsInfo(); + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TRD_ChamberStat", 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TRD_ChamberStat", 0}, info); + mProcessor->clearFedChamberStatusDPsInfo(); + } else { + auto& info = mProcessor->getccdbFedChamberStatusDPsInfo(); + LOG(info) << "Not sending object " << info.getPath() << "/" << info.getFileName() << " since no DPs were processed for it"; + } + } + + // LB: new DP for FedCFGtag + //________________________________________________________________ + void sendDPsoutputFedCFGtag(DataAllocator& output) + { + // extract CCDB infos and calibration object for DPs + if (mProcessor->updateFedCFGtagDPsCCDB()) { + const auto& payload = mProcessor->getTRDFedCFGtagDPsInfo(); + auto& info = mProcessor->getccdbFedCFGtagDPsInfo(); + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TRD_CFGtag", 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TRD_CFGtag", 0}, info); + mProcessor->clearFedCFGtagDPsInfo(); + } else { + auto& info = mProcessor->getccdbFedCFGtagDPsInfo(); + LOG(info) << "Not sending object " << info.getPath() << "/" << info.getFileName() << " since no DPs were processed for it"; + } + } + + // LB: new DP for FedEnvTemp + //________________________________________________________________ + void sendDPsoutputFedEnvTemp(DataAllocator& output) + { + // extract CCDB infos and calibration object for DPs + if (mProcessor->updateFedEnvTempDPsCCDB()) { + const auto& payload = mProcessor->getTRDFedEnvTempDPsInfo(); + auto& info = mProcessor->getccdbFedEnvTempDPsInfo(); + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TRD_FedTemp", 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TRD_FedTemp", 0}, info); + mProcessor->clearFedEnvTempDPsInfo(); + } else { + auto& info = mProcessor->getccdbFedEnvTempDPsInfo(); + LOG(info) << "Not sending object " << info.getPath() << "/" << info.getFileName() << " since no DPs were processed for it"; + } + } + + // LB: new DP for Cavern + //________________________________________________________________ + void sendDPsoutputCavern(DataAllocator& output) + { + // extract CCDB infos and calibration object for DPs + if (mProcessor->updateCavernDPsCCDB()) { + const auto& payload = mProcessor->getTRDCavernDPsInfo(); + auto& info = mProcessor->getccdbCavernDPsInfo(); + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TRD_DCSCavernDPs", 0}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TRD_DCSCavernDPs", 0}, info); + mProcessor->clearCavernDPsInfo(); + } else { + auto& info = mProcessor->getccdbCavernDPsInfo(); LOG(info) << "Not sending object " << info.getPath() << "/" << info.getFileName() << " since no DPs were processed for it"; } } @@ -314,6 +470,16 @@ DataProcessorSpec getTRDDCSDataProcessorSpec() outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TRD_DCSRunDPs"}); outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TRD_DCSEnvDPs"}); outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TRD_DCSEnvDPs"}); + // LB: new DPs for Fed and Cavern + // Must use reduced names due to initializer string cannot exceed descriptor size in Data Format + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TRD_ChamberStat"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TRD_ChamberStat"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TRD_CFGtag"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TRD_CFGtag"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TRD_FedTemp"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TRD_FedTemp"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TRD_DCSCavernDPs"}); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TRD_DCSCavernDPs"}); return DataProcessorSpec{ "trd-dcs-data-processor", @@ -328,7 +494,11 @@ DataProcessorSpec getTRDDCSDataProcessorSpec() {"DPs-update-interval-voltages", VariantType::Int64, 600ll, {"Interval (in s) after which to update the DPs CCDB entry for voltage parameters"}}, {"DPs-update-interval-env", VariantType::Int64, 1800ll, {"Interval (in s) after which to update the DPs CCDB entry for environment parameters"}}, {"DPs-min-update-interval-voltages", VariantType::Int64, 120ll, {"Minimum range to be covered by voltage CCDB object"}}, - {"DPs-update-interval-gas", VariantType::Int64, 900ll, {"Interval (in s) after which to update the DPs CCDB entry for gas parameters"}}}}; + {"DPs-update-interval-gas", VariantType::Int64, 900ll, {"Interval (in s) after which to update the DPs CCDB entry for gas parameters"}}, + {"DPs-update-interval-fedenv", VariantType::Int64, 1800ll, {"Interval (in s) after which to update the DPs CCDB entry for front end device environment parameters"}}, + {"DPs-update-interval-cavern", VariantType::Int64, 7200ll, {"Interval (in s) after which to update the DPs CCDB entry for cavern parameters"}}, + {"DPs-max-counter-alarm-fed", VariantType::Int, 1, {"Maximum number of alarms after FedChamberStatus and FedCFGtag changes, following changes are logged as warnings"}}, + {"DPs-min-counter-update-fed", VariantType::Int, 540, {"Minimum number of DPs to update FedChamberStatus and FedCFGtag objects"}}}}; } } // namespace framework diff --git a/Detectors/TRD/calibration/workflow/trd-dcs-sim-workflow.cxx b/Detectors/TRD/calibration/workflow/trd-dcs-sim-workflow.cxx index 41cf22208100c..6bb6ecf0a96b9 100644 --- a/Detectors/TRD/calibration/workflow/trd-dcs-sim-workflow.cxx +++ b/Detectors/TRD/calibration/workflow/trd-dcs-sim-workflow.cxx @@ -32,19 +32,19 @@ o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext co dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_hvDriftUmon[00..539]", 2249., 2250.}); // temperatures, pressures, config and other - // dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_fedCFGtag[00..539]", "foo", "bar"}); + dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_fedCFGtag[00..539]", "foo", "bar"}); // FIXME if I put a longer string here, e.g. "cf2_krypton_tb30:r5927" then dcs-random-data-generator crashes (std::bad_alloc or std::length_error) - // dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_fedChamberStatus[00..539]", 0, 255}); - // dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_fedEnvTemp[00..539]", 10., 40.}); + dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_fedChamberStatus[00..539]", 1, 5}); + dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_fedEnvTemp[00..539]", 10., 40.}); dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_aliEnvTempCavern", 0, 100.}); dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_aliEnvTempP2", 0, 100.}); dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_aliEnvPressure00", 0, 100.}); dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_aliEnvPressure01", 0, 100.}); dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_aliEnvPressure02", 0, 100.}); - // dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_cavernHumidity", 0, 100.}); + dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_cavernHumidity", 0, 100.}); dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_runNo", 254, 255}); - dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_runType", 254, 255}); + dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_runType", 1, 3}); return o2::framework::WorkflowSpec{o2::dcs::test::getDCSRandomDataGeneratorSpec(dphints, "TRD")}; } From 3536447592b4b98bf06649ced131cf01e24fccca Mon Sep 17 00:00:00 2001 From: swenzel Date: Mon, 4 Sep 2023 18:00:29 +0200 Subject: [PATCH 002/324] Account for first-orbit in collision-context creation --- Steer/src/CollisionContextTool.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Steer/src/CollisionContextTool.cxx b/Steer/src/CollisionContextTool.cxx index b59ca220af118..3f78959dd627c 100644 --- a/Steer/src/CollisionContextTool.cxx +++ b/Steer/src/CollisionContextTool.cxx @@ -45,6 +45,7 @@ struct Options { bool printContext = false; std::string bcpatternfile; int tfid = 0; // tfid -> used to calculate start orbit for collisions + int firstOrbit = 0; // first orbit in run (orbit offset) int orbitsPerTF = 256; // number of orbits per timeframe --> used to calculate start orbit for collisions bool useexistingkinematics = false; bool noEmptyTF = false; // prevent empty timeframes; the first interaction will be shifted backwards to fall within the range given by Options.orbits @@ -195,6 +196,7 @@ bool parseOptions(int argc, char* argv[], Options& optvalues) "orbitsPerTF", bpo::value(&optvalues.orbitsPerTF)->default_value(256), "Orbits per timeframes")( "use-existing-kine", "Read existing kinematics to adjust event counts")( "timeframeID", bpo::value(&optvalues.tfid)->default_value(0), "Timeframe id of the first timeframe int this context. Allows to generate contexts for different start orbits")( + "first-orbit", bpo::value(&optvalues.firstOrbit)->default_value(0), "First orbit in the run (HBFUtils.firstOrbit)")( "maxCollsPerTF", bpo::value(&optvalues.maxCollsPerTF)->default_value(-1), "Maximal number of MC collisions to put into one timeframe. By default no constraint.")( "noEmptyTF", bpo::bool_switch(&optvalues.noEmptyTF), "Enforce to have at least one collision")("configKeyValues", bpo::value(&optvalues.configKeyValues)->default_value(""), "Semicolon separated key=value strings (e.g.: 'TPC.gasDensity=1;...')")("with-vertices", "Assign vertices to collisions.")("timestamp", bpo::value(&optvalues.timestamp)->default_value(-1L), "Timestamp for CCDB queries / anchoring"); @@ -279,7 +281,7 @@ int main(int argc, char* argv[]) if (!options.bcpatternfile.empty()) { setBCFillingHelper(sampler, options.bcpatternfile); } - auto orbitstart = options.tfid * options.orbitsPerTF; + auto orbitstart = options.firstOrbit + options.tfid * options.orbitsPerTF; o2::InteractionTimeRecord record; // this loop makes sure that the first collision is within the range of orbits asked (if noEmptyTF is enabled) do { From 679e84a35d2c3f0b27becb24ec05f07142a8b146 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 5 Sep 2023 23:31:57 +0200 Subject: [PATCH 003/324] Disable rANS benchmarks unless required (#11864) --- Utilities/rANS/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Utilities/rANS/CMakeLists.txt b/Utilities/rANS/CMakeLists.txt index 1e929d204c3a7..608485ac601a0 100644 --- a/Utilities/rANS/CMakeLists.txt +++ b/Utilities/rANS/CMakeLists.txt @@ -183,7 +183,7 @@ o2_add_test(Serialize target_compile_options(${TEST_SERIALIZE} PRIVATE ${RANS_TEST_ARCH}) if(${RANS_ENABLE_JSON}) - if (TARGET benchmark::benchmark) + if (${ENABLE_RANS_BENCHMARK}) o2_add_header_only_library(libransBenchmark TARGETVARNAME LIB_RANS_BENCHMARK From 168bc6b6821c086467400c2843f50c9dcf89f0cb Mon Sep 17 00:00:00 2001 From: ppillot Date: Wed, 23 Aug 2023 19:08:08 +0200 Subject: [PATCH 004/324] shift MC digits by the same time offset as in data --- Steer/DigitizerWorkflow/CMakeLists.txt | 3 ++- Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Steer/DigitizerWorkflow/CMakeLists.txt b/Steer/DigitizerWorkflow/CMakeLists.txt index 43f84726dbe7c..fce6103573609 100644 --- a/Steer/DigitizerWorkflow/CMakeLists.txt +++ b/Steer/DigitizerWorkflow/CMakeLists.txt @@ -47,8 +47,8 @@ o2_add_executable(digitizer-workflow O2::ITSMFTWorkflow O2::MCHSimulation O2::MCHMappingImpl4 - O2::DataFormatsMCH O2::MCHIO + O2::MCHDigitFiltering O2::MFTSimulation O2::MIDSimulation O2::PHOSSimulation @@ -106,6 +106,7 @@ o2_add_executable(digitizer-workflow O2::MCHSimulation O2::MCHMappingImpl4 O2::MCHIO + O2::MCHDigitFiltering O2::MFTSimulation O2::MIDSimulation O2::PHOSSimulation diff --git a/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx index bd9e607950189..fc92020f25b21 100644 --- a/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx @@ -21,6 +21,7 @@ #include "Framework/DataRefUtils.h" #include "Framework/Lifetime.h" #include "Framework/Task.h" +#include "MCHDigitFiltering/DigitFilterParam.h" #include "MCHSimulation/Detector.h" #include "MCHSimulation/Digitizer.h" #include "MCHSimulation/DigitizerParam.h" @@ -79,12 +80,18 @@ class MCHDPLDigitizerTask : public o2::base::BaseDPLDigitizer auto context = pc.inputs().get("collisioncontext"); context->initSimChains(o2::detectors::DetID::MCH, mSimChains); const auto& eventRecords = context->getEventRecords(); + auto timeOffset = DigitFilterParam::Instance().timeOffset; // generate signals produced by every hits if (!DigitizerParam::Instance().onlyNoise) { const auto& eventParts = context->getEventParts(); for (auto i = 0; i < eventRecords.size(); i++) { auto ir = eventRecords[i]; + // apply time offset, discarding events going to negative IR + if (ir.toLong() < timeOffset) { + continue; + } + ir -= timeOffset; for (const auto& part : eventParts[i]) { std::vector hits{}; context->retrieveHits(mSimChains, "MCHHit", part.sourceID, part.entryID, &hits); @@ -94,8 +101,8 @@ class MCHDPLDigitizerTask : public o2::base::BaseDPLDigitizer } // generate noise-only signals between first and last collisions ± 100 BC (= 25 ADC samples) - auto firstIR = InteractionRecord::long2IR(std::max(int64_t(0), eventRecords.front().toLong() - 100)); - auto lastIR = eventRecords.back() + 100; + auto firstIR = InteractionRecord::long2IR(std::max(int64_t(0), eventRecords.front().toLong() - timeOffset - 100)); + auto lastIR = InteractionRecord::long2IR(std::max(int64_t(0), eventRecords.back().toLong() - timeOffset + 100)); mDigitizer->addNoise(firstIR, lastIR); // digitize From f51b74ee404973bebe80cb4b329e7ccaf02cb3c4 Mon Sep 17 00:00:00 2001 From: fmazzasc Date: Tue, 5 Sep 2023 15:52:57 +0200 Subject: [PATCH 005/324] Update Li4 values according to the iaea database --- .../include/SimulationDataFormat/O2DatabasePDG.h | 8 ++++---- Steer/src/O2MCApplication.cxx | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DataFormats/simulation/include/SimulationDataFormat/O2DatabasePDG.h b/DataFormats/simulation/include/SimulationDataFormat/O2DatabasePDG.h index 89494127ee7b7..3225f3536f1cf 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/O2DatabasePDG.h +++ b/DataFormats/simulation/include/SimulationDataFormat/O2DatabasePDG.h @@ -300,14 +300,14 @@ inline void O2DatabasePDG::addALICEParticles(TDatabasePDG* db) // Lithium 4 ground state ionCode = 1000030040; if (!db->GetParticle(ionCode)) { - db->AddParticle("Lithium4", "Lithium4", 3.74976, kFALSE, - 0.005, 9, "Ion", ionCode); + db->AddParticle("Lithium4", "Lithium4", 3.7513, kFALSE, + 0.003, 9, "Ion", ionCode); } // anti Lithium 4 ground state ionCode = -1000030040; if (!db->GetParticle(ionCode)) { - db->AddParticle("AntiLithium4", "AntiLithium4", 3.74976, kFALSE, - 0.005, 9, "Ion", ionCode); + db->AddParticle("AntiLithium4", "AntiLithium4", 3.7513, kFALSE, + 0.003, 9, "Ion", ionCode); } ionCode = 1010020050; diff --git a/Steer/src/O2MCApplication.cxx b/Steer/src/O2MCApplication.cxx index 118374751ee69..8594de2c860a8 100644 --- a/Steer/src/O2MCApplication.cxx +++ b/Steer/src/O2MCApplication.cxx @@ -265,9 +265,9 @@ void addSpecialParticles() TVirtualMC::GetMC()->DefineParticle(-1010020041, "AntiHyperhelium4*", kPTHadron, 3.9231, 2.0, 2.632e-10, "Ion", 0.0, 0, 1, 0, 0, 0, 0, 0, 4, kFALSE); // Lithium 4 ground state - TVirtualMC::GetMC()->DefineParticle(1000030040, "Lithium4", kPTHadron, 3.74976, 3.0, 9.1e-23, "Ion", 0.005, 0, 1, 0, 0, 0, 0, 0, 4, kFALSE); + TVirtualMC::GetMC()->DefineParticle(1000030040, "Lithium4", kPTHadron, 3.7513, 3.0, 9.1e-23, "Ion", 0.003, 0, 1, 0, 0, 0, 0, 0, 4, kFALSE); // Anti-Lithium 4 ground state - TVirtualMC::GetMC()->DefineParticle(-1000030040, "AntiLithium4", kPTHadron, 3.74976, 3.0, 9.1e-23, "Ion", 0.005, 0, 1, 0, 0, 0, 0, 0, 4, kFALSE); + TVirtualMC::GetMC()->DefineParticle(-1000030040, "AntiLithium4", kPTHadron, 3.7513, 3.0, 9.1e-23, "Ion", 0.003, 0, 1, 0, 0, 0, 0, 0, 4, kFALSE); //Hyper helium 5 TVirtualMC::GetMC()->DefineParticle(1010020050, "Hyperhelium5", kPTHadron, 4.841, 2.0, 2.632e-10, "Ion", 0.0, 0, 1, 0, 0, 0, 0, 0, 5, kFALSE); From 8d4eb4492affdf1c7f2824daa92c2584d4267c61 Mon Sep 17 00:00:00 2001 From: shahoian Date: Wed, 6 Sep 2023 21:11:53 +0200 Subject: [PATCH 006/324] TPCTrackStudy wf can process limited TFs, optionally use GPU track model in refit --- .../study/src/TPCTrackStudy.cxx | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx index 47c19c0ffc7a9..7d5b132ec7f3a 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx @@ -23,6 +23,7 @@ #include "CommonUtils/NameConf.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/CCDBParamSpec.h" +#include "Framework/ControlService.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsBase/GRPGeomHelper.h" #include "GlobalTrackingStudy/TPCTrackStudy.h" @@ -67,8 +68,12 @@ class TPCTrackStudySpec : public Task o2::tpc::VDriftHelper mTPCVDriftHelper{}; o2::tpc::CorrectionMapsLoader mTPCCorrMapsLoader{}; bool mUseMC{false}; ///< MC flag + bool mUseGPUModel{false}; float mXRef = 0.; int mNMoves = 6; + int mTFStart = 0; + int mTFEnd = 999999999; + int mTFCount = -1; bool mUseR = false; std::unique_ptr mDBGOut; std::unique_ptr mDBGOutCl; @@ -91,6 +96,9 @@ void TPCTrackStudySpec::init(InitContext& ic) mXRef = ic.options().get("target-x"); mNMoves = std::max(2, ic.options().get("n-moves")); mUseR = ic.options().get("use-r-as-x"); + mUseGPUModel = ic.options().get("use-gpu-fitter"); + mTFStart = ic.options().get("tf-start"); + mTFEnd = ic.options().get("tf-end"); if (mXRef < 0.) { mXRef = 0.; } @@ -103,10 +111,22 @@ void TPCTrackStudySpec::init(InitContext& ic) void TPCTrackStudySpec::run(ProcessingContext& pc) { + mTFCount++; + if (mTFCount < mTFStart || mTFCount > mTFEnd) { + LOGP(info, "Skipping TF {}", mTFCount); + return; + } + o2::globaltracking::RecoContainer recoData; recoData.collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions process(recoData); + + if (mTFCount > mTFEnd) { + LOGP(info, "Stopping processing after TF {}", mTFCount); + pc.services().get().endOfStream(); + return; + } } void TPCTrackStudySpec::updateTimeDependentParams(ProcessingContext& pc) @@ -205,7 +225,7 @@ void TPCTrackStudySpec::process(o2::globaltracking::RecoContainer& recoData) // create refitted copy auto trackRefit = [itr, this](o2::track::TrackParCov& trc, float t) -> bool { float chi2Out = 0; - int retVal = this->mTPCRefitter->RefitTrackAsTrackParCov(trc, this->mTPCTracksArray[itr].getClusterRef(), t, &chi2Out, false, true); + int retVal = mUseGPUModel ? this->mTPCRefitter->RefitTrackAsGPU(trc, this->mTPCTracksArray[itr].getClusterRef(), t, &chi2Out, false, true) : this->mTPCRefitter->RefitTrackAsTrackParCov(trc, this->mTPCTracksArray[itr].getClusterRef(), t, &chi2Out, false, true); if (retVal < 0) { LOGP(warn, "Refit failed ({}) with time={}: track#{}[{}]", retVal, t, counter, trc.asString()); return false; @@ -391,6 +411,9 @@ DataProcessorSpec getTPCTrackStudySpec(GTrackID::mask_t srcTracks, GTrackID::mas {"target-x", VariantType::Float, 70.f, {"Try to propagate to this radius"}}, {"n-moves", VariantType::Int, 6, {"Number of moves in allow range"}}, {"dump-clusters", VariantType::Bool, false, {"dump clusters"}}, + {"tf-start", VariantType::Int, 0, {"1st TF to process"}}, + {"tf-end", VariantType::Int, 999999999, {"last TF to process"}}, + {"use-gpu-fitter", VariantType::Bool, false, {"use GPU track model for refit instead of TrackParCov"}}, {"use-r-as-x", VariantType::Bool, false, {"Use radius instead of target sector X"}}}; auto dataRequest = std::make_shared(); From 3d88d787f6c3c7c0978afbb6552ecc26a314fec3 Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 7 Sep 2023 20:53:52 +0200 Subject: [PATCH 007/324] Set default min.stat of tpc-vdrift-tgl calib to 10000 --- .../TPC/workflow/src/tpc-vdrift-tgl-calibration-workflow.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/TPC/workflow/src/tpc-vdrift-tgl-calibration-workflow.cxx b/Detectors/TPC/workflow/src/tpc-vdrift-tgl-calibration-workflow.cxx index e7d969445a9d4..26e5278c479ad 100644 --- a/Detectors/TPC/workflow/src/tpc-vdrift-tgl-calibration-workflow.cxx +++ b/Detectors/TPC/workflow/src/tpc-vdrift-tgl-calibration-workflow.cxx @@ -24,7 +24,7 @@ void customize(std::vector& workflowOptions) {"max-tgl-its", o2::framework::VariantType::Float, 2.f, {"max range for tgL of ITS tracks"}}, {"nbins-dtgl", o2::framework::VariantType::Int, 50, {"number of bins in tgL_ITS - tgl_TPC"}}, {"max-dtgl-itstpc", o2::framework::VariantType::Float, 0.15f, {"max range for tgL_ITS - tgl_TPC"}}, - {"min-entries-per-slot", o2::framework::VariantType::Int, 1000, {"mininal number of entries per slot"}}, + {"min-entries-per-slot", o2::framework::VariantType::Int, 10000, {"mininal number of entries per slot"}}, {"time-slot-seconds", o2::framework::VariantType::Int, 600, {"time slot length in seconds"}}, {"max-slots-delay", o2::framework::VariantType::Float, 0.1f, {"difference in slot units between the current TF and oldest slot (end TF) to account for the TF"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; From 5cbdf634a52a018c9e5c473d14330ebecc3afeb4 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 7 Sep 2023 21:59:01 +0200 Subject: [PATCH 008/324] Add support for thread sanitizer (#11828) --- Framework/Foundation/CMakeLists.txt | 6 ++++ .../Foundation/test/test_ThreadSanitizer.cxx | 34 +++++++++++++++++++ dependencies/O2CompileFlags.cmake | 12 +++++++ 3 files changed, 52 insertions(+) create mode 100644 Framework/Foundation/test/test_ThreadSanitizer.cxx diff --git a/Framework/Foundation/CMakeLists.txt b/Framework/Foundation/CMakeLists.txt index 1024dbebb1eae..aa7a073fca581 100644 --- a/Framework/Foundation/CMakeLists.txt +++ b/Framework/Foundation/CMakeLists.txt @@ -38,7 +38,12 @@ target_link_libraries(o2-test-framework-foundation PRIVATE O2::Catch2) add_executable(o2-test-framework-Signpost test/test_Signpost.cxx) +add_executable(o2-test-framework-ThreadSanitizer + test/test_ThreadSanitizer.cxx) + target_link_libraries(o2-test-framework-Signpost PRIVATE O2::FrameworkFoundation) +target_link_libraries(o2-test-framework-ThreadSanitizer + PRIVATE O2::FrameworkFoundation Threads::Threads) add_executable(o2-test-framework-SignpostLogger test/test_SignpostLogger.cxx @@ -50,6 +55,7 @@ get_filename_component(outdir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/../tests ABSOLUT set_property(TARGET o2-test-framework-foundation PROPERTY RUNTIME_OUTPUT_DIRECTORY ${outdir}) set_property(TARGET o2-test-framework-Signpost PROPERTY RUNTIME_OUTPUT_DIRECTORY ${outdir}) set_property(TARGET o2-test-framework-SignpostLogger PROPERTY RUNTIME_OUTPUT_DIRECTORY ${outdir}) +set_property(TARGET o2-test-framework-ThreadSanitizer PROPERTY RUNTIME_OUTPUT_DIRECTORY ${outdir}) add_test(NAME framework:foundation COMMAND o2-test-framework-foundation) diff --git a/Framework/Foundation/test/test_ThreadSanitizer.cxx b/Framework/Foundation/test/test_ThreadSanitizer.cxx new file mode 100644 index 0000000000000..16b6f39b8d59e --- /dev/null +++ b/Framework/Foundation/test/test_ThreadSanitizer.cxx @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include +#include + +using map_t = std::map; + +void* threadfunc(void* p) +{ + map_t& m = *(map_t*)p; + m["foo"] = "bar"; + return nullptr; +} + +int main() +{ + map_t m; + // Create a thread in C++11 mode, which executes threadfunc(&m) + std::thread thread(threadfunc, &m); + // Start + printf("foo=%s\n", m["foo"].c_str()); + thread.join(); +} diff --git a/dependencies/O2CompileFlags.cmake b/dependencies/O2CompileFlags.cmake index 4c01d4bd8f5f6..e52260ed74455 100644 --- a/dependencies/O2CompileFlags.cmake +++ b/dependencies/O2CompileFlags.cmake @@ -80,6 +80,18 @@ MARK_AS_ADVANCED( CMAKE_Fortran_FLAGS_COVERAGE CMAKE_LINK_FLAGS_COVERAGE) +# Options to enable the thread sanitizer +set(CMAKE_CXX_FLAGS_THREADSANITIZER "-g -O2 -fsanitize=thread -fPIC") +set(CMAKE_C_FLAGS_THREADSANITIZER "${CMAKE_CXX_FLAGS_THREADSANITIZER}") +set(CMAKE_Fortran_FLAGS_THREADSANITIZER "-g -O2 -fsanitize=thread -fPIC") +set(CMAKE_LINK_FLAGS_THREADSANITIZER "-fsanitize=thread -fPIC") + +MARK_AS_ADVANCED( + CMAKE_CXX_FLAGS_THREADSANITIZER + CMAKE_C_FLAGS_THREADSANITIZER + CMAKE_Fortran_FLAGS_THREADSANITIZER + CMAKE_LINK_FLAGS_THREADSANITIZER) + #Check the compiler and set the compile and link flags IF (NOT CMAKE_BUILD_TYPE) Message(STATUS "Set BuildType to DEBUG") From 87adb73d031927dfe60d571ed3b3edd31b5b6304 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 6 Sep 2023 16:51:26 +0200 Subject: [PATCH 009/324] GPU QA: Do not run tasks that need MC without MC + improve debug messages --- GPU/GPUTracking/qa/GPUQA.cxx | 10 ++++++++-- GPU/GPUTracking/qa/GPUQA.h | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/GPU/GPUTracking/qa/GPUQA.cxx b/GPU/GPUTracking/qa/GPUQA.cxx index 9abec1139b80c..7df17011078fa 100644 --- a/GPU/GPUTracking/qa/GPUQA.cxx +++ b/GPU/GPUTracking/qa/GPUQA.cxx @@ -570,6 +570,9 @@ int GPUQA::loadHistograms(std::vector& i1, std::vector& i2, std::vec mHist1Dd_pos.clear(); mHistGraph_pos.clear(); mHaveExternalHists = true; + if (mConfig.noMC) { + tasks &= tasksNoQC; + } mQATasks = tasks; if (InitQACreateHistograms()) { return 1; @@ -751,6 +754,9 @@ int GPUQA::InitQA(int tasks) mHist2D = new std::vector; mHist1Dd = new std::vector; mHistGraph = new std::vector; + if (mConfig.noMC) { + tasks &= tasksNoQC; + } mQATasks = tasks; if (mTracking->GetProcessingSettings().qcRunFraction != 100.f && mQATasks != taskClusterCounts) { @@ -822,7 +828,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx throw std::runtime_error("QA not initialized"); } if (mTracking && mTracking->GetProcessingSettings().debugLevel >= 2) { - printf("Running QA\n"); + GPUInfo("Running QA - Mask %d, Efficiency %d, Resolution %d, Pulls %d, Cluster Attachment %d, Track Statistics %d, Cluster Counts %d", mQATasks, (int)(mQATasks & taskTrackingEff), (int)(mQATasks & taskTrackingRes), (int)(mQATasks & taskTrackingResPull), (int)(mQATasks & taskClusterAttach), (int)(mQATasks & taskTrackStatistics), (int)(mQATasks & taskClusterCounts)); } if (!clNative && mTracking) { clNative = mTracking->mIOPtrs.clustersNative; @@ -2030,7 +2036,7 @@ int GPUQA::DrawQAHistograms(TObjArray* qcout) } } - if (mConfig.enableLocalOutput && !mConfig.inputHistogramsOnly && (mQATasks & taskTrackingEff)) { + if (mConfig.enableLocalOutput && !mConfig.inputHistogramsOnly && (mQATasks & taskTrackingEff) && mcPresent()) { GPUInfo("QA Stats: Eff: Tracks Prim %d (Eta %d, Pt %d) %f%% (%f%%) Sec %d (Eta %d, Pt %d) %f%% (%f%%) - Res: Tracks %d (Eta %d, Pt %d)", (int)mEff[3][1][0][0]->GetEntries(), (int)mEff[3][1][0][3]->GetEntries(), (int)mEff[3][1][0][4]->GetEntries(), mEff[0][0][0][0]->GetSumOfWeights() / std::max(1., mEff[3][0][0][0]->GetSumOfWeights()), mEff[0][1][0][0]->GetSumOfWeights() / std::max(1., mEff[3][1][0][0]->GetSumOfWeights()), (int)mEff[3][1][1][0]->GetEntries(), (int)mEff[3][1][1][3]->GetEntries(), (int)mEff[3][1][1][4]->GetEntries(), mEff[0][0][1][0]->GetSumOfWeights() / std::max(1., mEff[3][0][1][0]->GetSumOfWeights()), mEff[0][1][1][0]->GetSumOfWeights() / std::max(1., mEff[3][1][1][0]->GetSumOfWeights()), (int)mRes2[0][0]->GetEntries(), diff --git a/GPU/GPUTracking/qa/GPUQA.h b/GPU/GPUTracking/qa/GPUQA.h index a7e45f8fa4d3d..0084c6dfff290 100644 --- a/GPU/GPUTracking/qa/GPUQA.h +++ b/GPU/GPUTracking/qa/GPUQA.h @@ -135,7 +135,8 @@ class GPUQA taskTrackStatistics = 16, taskClusterCounts = 32, taskDefault = 63, - taskDefaultPostprocess = 31 + taskDefaultPostprocess = 31, + tasksNoQC = 56 }; private: From 918f2824aa663ffb5a03671d0c02c532e6e3c334 Mon Sep 17 00:00:00 2001 From: gvolpe79 <39517882+gvolpe79@users.noreply.github.com> Date: Thu, 7 Sep 2023 15:44:38 +0200 Subject: [PATCH 010/324] Update HMPMatcherSpec.cxx --- .../GlobalTrackingWorkflow/src/HMPMatcherSpec.cxx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Detectors/GlobalTrackingWorkflow/src/HMPMatcherSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/HMPMatcherSpec.cxx index e282de9ea46e0..4ea565525bfaa 100644 --- a/Detectors/GlobalTrackingWorkflow/src/HMPMatcherSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/HMPMatcherSpec.cxx @@ -62,6 +62,7 @@ class HMPMatcherSpec : public Task void init(InitContext& ic) final; void run(ProcessingContext& pc) final; void endOfStream(framework::EndOfStreamContext& ec) final; + void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final; private: std::shared_ptr mDataRequest; @@ -79,9 +80,14 @@ void HMPMatcherSpec::init(InitContext& ic) mTimer.Stop(); mTimer.Reset(); //-------- init geometry and field --------// - o2::base::GeometryManager::loadGeometry(); - o2::base::Propagator::initFieldFromGRP(); - std::unique_ptr grp{o2::parameters::GRPObject::loadFrom()}; + o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); +} + +void HMPMatcherSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) +{ + if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + return; + } } void HMPMatcherSpec::run(ProcessingContext& pc) @@ -90,6 +96,7 @@ void HMPMatcherSpec::run(ProcessingContext& pc) RecoContainer recoData; recoData.collectData(pc, *mDataRequest.get()); + o2::base::GRPGeomHelper::instance().checkUpdates(pc); auto creationTime = DataRefUtils::getHeader(pc.inputs().getFirstValid(true))->creation; From d07b4a2dbe651f5c501e3bcd631d795516d9f672 Mon Sep 17 00:00:00 2001 From: rcaron Date: Thu, 7 Sep 2023 17:03:15 +0200 Subject: [PATCH 011/324] add time shift (ROF bias in BC) and chi2vspT histo --- .../include/GlobalTracking/MatchGlobalFwd.h | 6 ++++++ Detectors/GlobalTracking/src/MatchGlobalFwd.cxx | 14 +++++++++++--- .../src/GlobalFwdMatchingSpec.cxx | 4 ++++ .../include/MFTAssessment/MFTAssessment.h | 1 + .../ITSMFT/MFT/assessment/src/MFTAssessment.cxx | 7 +++++++ .../base/include/ITSMFTBase/DPLAlpideParam.h | 2 +- 6 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchGlobalFwd.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchGlobalFwd.h index 9f7e740322cd5..06cab0e501aac 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchGlobalFwd.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchGlobalFwd.h @@ -134,6 +134,9 @@ class MatchGlobalFwd void setMFTROFrameLengthMUS(float fums); ///< set MFT ROFrame duration in BC (continuous mode only) void setMFTROFrameLengthInBC(int nbc); + ///< set MFT ROFrame bias in BC (continuous mode only) or time shift applied already as MFTAlpideParam.roFrameBiasInBC + void setMFTROFrameBiasInBC(int nbc); + const std::vector& getMatchedFwdTracks() const { return mMatchedTracks; } const std::vector& getMFTMatchingPlaneParams() const { return mMFTMatchPlaneParams; } const std::vector& getMCHMatchingPlaneParams() const { return mMCHMatchPlaneParams; } @@ -288,6 +291,9 @@ class MatchGlobalFwd int mMFTROFrameLengthInBC = 0; ///< MFT RO frame in BC (for MFT cont. mode only) float mMFTROFrameLengthMUS = -1.; ///< MFT RO frame in \mus float mMFTROFrameLengthMUSInv = -1.; ///< MFT RO frame in \mus inverse + int mMFTROFrameBiasInBC = 0; ///< MFT ROF bias in BC wrt to orbit start + float mMFTROFrameBiasMUS = -1.; ///< MFT ROF bias in \mus + float mMFTROFrameBiasMUSInv = -1.; ///< MFT ROF bias in \mus inverse std::map mMatchingFunctionMap; ///< MFT-MCH Matching function std::map mCutFunctionMap; ///< MFT-MCH Candidate cut function diff --git a/Detectors/GlobalTracking/src/MatchGlobalFwd.cxx b/Detectors/GlobalTracking/src/MatchGlobalFwd.cxx index 90c8c08fa6d70..4639e830e6415 100644 --- a/Detectors/GlobalTracking/src/MatchGlobalFwd.cxx +++ b/Detectors/GlobalTracking/src/MatchGlobalFwd.cxx @@ -262,10 +262,10 @@ bool MatchGlobalFwd::prepareMFTData() } return false; } - float tMin = nBC * o2::constants::lhc::LHCBunchSpacingMUS; - float tMax = (nBC + mMFTROFrameLengthInBC) * o2::constants::lhc::LHCBunchSpacingMUS; + float tMin = (nBC + mMFTROFrameBiasInBC) * o2::constants::lhc::LHCBunchSpacingMUS; + float tMax = (nBC + mMFTROFrameLengthInBC + mMFTROFrameBiasInBC) * o2::constants::lhc::LHCBunchSpacingMUS; if (!mMFTTriggered) { - auto irofCont = nBC / mMFTROFrameLengthInBC; + auto irofCont = (nBC + mMFTROFrameBiasInBC) / mMFTROFrameLengthInBC; if (mMFTTrackROFContMapping.size() <= irofCont) { // there might be gaps in the non-empty rofs, this will map continuous ROFs index to non empty ones mMFTTrackROFContMapping.resize((1 + irofCont / 128) * 128, 0); } @@ -651,6 +651,14 @@ void MatchGlobalFwd::setMFTROFrameLengthInBC(int nbc) mMFTROFrameLengthMUSInv = 1. / mMFTROFrameLengthMUS; } +//_________________________________________________________ +void MatchGlobalFwd::setMFTROFrameBiasInBC(int nbc) +{ + mMFTROFrameBiasInBC = nbc; + mMFTROFrameBiasMUS = nbc * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; + mMFTROFrameBiasMUSInv = 1. / mMFTROFrameBiasMUS; +} + //_________________________________________________________ void MatchGlobalFwd::setBunchFilling(const o2::BunchFilling& bf) { diff --git a/Detectors/GlobalTrackingWorkflow/src/GlobalFwdMatchingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/GlobalFwdMatchingSpec.cxx index c4aa880f414c5..582f2be3c5f84 100644 --- a/Detectors/GlobalTrackingWorkflow/src/GlobalFwdMatchingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/GlobalFwdMatchingSpec.cxx @@ -157,6 +157,10 @@ void GlobalFwdMatchingDPL::updateTimeDependentParams(ProcessingContext& pc) } else { mMatching.setMFTROFrameLengthInBC(alpParams.roFrameLengthInBC); // MFT ROFrame duration in \mus } + if (alpParams.roFrameBiasInBC != 0) { + mMatching.setMFTROFrameBiasInBC(alpParams.roFrameBiasInBC); // MFT ROFrame bias in BCs wrt orbit start + LOG(info) << "Setting MFT ROF bias to " << alpParams.roFrameBiasInBC << " BCs"; + } mMatching.init(); } diff --git a/Detectors/ITSMFT/MFT/assessment/include/MFTAssessment/MFTAssessment.h b/Detectors/ITSMFT/MFT/assessment/include/MFTAssessment/MFTAssessment.h index 132a58722eb5b..3c7238980cf23 100644 --- a/Detectors/ITSMFT/MFT/assessment/include/MFTAssessment/MFTAssessment.h +++ b/Detectors/ITSMFT/MFT/assessment/include/MFTAssessment/MFTAssessment.h @@ -138,6 +138,7 @@ class MFTAssessment std::unique_ptr mPositiveTrackPhi = nullptr; std::unique_ptr mNegativeTrackPhi = nullptr; std::unique_ptr mTrackEta = nullptr; + std::unique_ptr mTrackChi2pT = nullptr; std::unique_ptr mMFTClsZ = nullptr; std::unique_ptr mMFTClsOfTracksZ = nullptr; diff --git a/Detectors/ITSMFT/MFT/assessment/src/MFTAssessment.cxx b/Detectors/ITSMFT/MFT/assessment/src/MFTAssessment.cxx index 0967f314e8b51..2184bcaef0cde 100644 --- a/Detectors/ITSMFT/MFT/assessment/src/MFTAssessment.cxx +++ b/Detectors/ITSMFT/MFT/assessment/src/MFTAssessment.cxx @@ -46,6 +46,7 @@ void MFTAssessment::reset() mPositiveTrackPhi->Reset(); mNegativeTrackPhi->Reset(); mTrackEta->Reset(); + mTrackChi2pT->Reset(); mMFTClsZ->Reset(); mMFTClsOfTracksZ->Reset(); @@ -151,6 +152,8 @@ void MFTAssessment::createHistos() mTrackEta = std::make_unique("mMFTTrackEta", "Track #eta; #eta; # entries", 50, -4, -2); + mTrackChi2pT = std::make_unique("mMFTTrackChi2pT", "Track #chi^{2}/NDF vs p_{T}; #it{p}_{T} (GeV/c); #chi^{2}/NDF", 210, -0.5, 20.5, 210, -0.5, 20.5); + //---------------------------------------------------------------------------- mMFTClsZ = std::make_unique("mMFTClsZ", "Z of all clusters; Z (cm); # entries", 400, -80, -40); @@ -368,6 +371,7 @@ void MFTAssessment::runASyncQC(o2::framework::ProcessingContext& ctx) mTrackPhi->Fill(oneTrack.getPhi()); mTrackEta->Fill(oneTrack.getEta()); mTrackCotl->Fill(1. / oneTrack.getTanl()); + mTrackChi2pT->Fill(oneTrack.getPt(), oneTrack.getChi2OverNDF()); for (auto idisk = 0; idisk < 5; idisk++) { clsEntriesForRedundancy[idisk] = {-1, -1}; @@ -676,6 +680,7 @@ void MFTAssessment::getHistos(TObjArray& objar) objar.Add(mPositiveTrackPhi.get()); objar.Add(mNegativeTrackPhi.get()); objar.Add(mTrackEta.get()); + objar.Add(mTrackChi2pT.get()); //------ objar.Add(mMFTClsZ.get()); @@ -870,6 +875,8 @@ bool MFTAssessment::loadHistos() mTrackEta = std::unique_ptr((TH1F*)f->Get("mMFTTrackEta")); + mTrackChi2pT = std::unique_ptr((TH2F*)f->Get("mMFTTrackChi2pT")); + //--------------------------------------------------------------------------- mMFTClsZ = std::unique_ptr((TH1F*)f->Get("mMFTClsZ")); diff --git a/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h b/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h index d60dba79a6345..bc3b3dbde53b0 100644 --- a/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h +++ b/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h @@ -59,7 +59,7 @@ struct DPLAlpideParam : public o2::conf::ConfigurableParamHelper Date: Wed, 23 Aug 2023 19:11:18 +0200 Subject: [PATCH 012/324] PV extended class, use in the TrackStudy wf --- DataFormats/Reconstruction/CMakeLists.txt | 2 + .../PrimaryVertexExt.h | 58 +++++++++++++++++++ .../ReconstructionDataFormats/Vertex.h | 3 - .../Reconstruction/src/PrimaryVertexExt.cxx | 51 ++++++++++++++++ .../src/ReconstructionDataFormatsLinkDef.h | 2 + DataFormats/Reconstruction/src/Vertex.cxx | 3 + DataFormats/common/CMakeLists.txt | 1 + DataFormats/common/src/TimeStamp.cxx | 19 ++++++ .../study/src/TrackingStudy.cxx | 45 +++++++++++++- 9 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h create mode 100644 DataFormats/Reconstruction/src/PrimaryVertexExt.cxx create mode 100644 DataFormats/common/src/TimeStamp.cxx diff --git a/DataFormats/Reconstruction/CMakeLists.txt b/DataFormats/Reconstruction/CMakeLists.txt index 57c0b29a8f04f..86c0831d2134e 100644 --- a/DataFormats/Reconstruction/CMakeLists.txt +++ b/DataFormats/Reconstruction/CMakeLists.txt @@ -17,6 +17,7 @@ o2_add_library(ReconstructionDataFormats src/TrackTPCITS.cxx src/Vertex.cxx src/PrimaryVertex.cxx + src/PrimaryVertexExt.cxx src/MatchInfoTOF.cxx src/MatchInfoTOFReco.cxx src/TrackLTIntegral.cxx @@ -51,6 +52,7 @@ o2_target_root_dictionary( include/ReconstructionDataFormats/GlobalFwdTrack.h include/ReconstructionDataFormats/Vertex.h include/ReconstructionDataFormats/PrimaryVertex.h + include/ReconstructionDataFormats/PrimaryVertexExt.h include/ReconstructionDataFormats/MatchInfoTOF.h include/ReconstructionDataFormats/MatchInfoTOFReco.h include/ReconstructionDataFormats/TrackLTIntegral.h diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h new file mode 100644 index 0000000000000..9037066884da6 --- /dev/null +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h @@ -0,0 +1,58 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_PRIMARYVERTEX_EXT_H +#define ALICEO2_PRIMARYVERTEX_EXT_H + +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" + +namespace o2 +{ +namespace dataformats +{ + +// extended primary vertex info + +struct PrimaryVertexExt : public PrimaryVertex { + using PrimaryVertex::PrimaryVertex; + std::array nSrc{}; // N contributors for each source type + float FT0Amp = 0; // amplitude of closest FT0 trigger + float FT0Time = 0.; // time of closest FT0 trigger + + int getNSrc(int i) const { return nSrc[i]; } + +#ifndef GPUCA_ALIGPUCODE + void print() const; + std::string asString() const; +#endif + + ClassDefNV(PrimaryVertexExt, 1); +}; + +#ifndef GPUCA_ALIGPUCODE +std::ostream& operator<<(std::ostream& os, const o2::dataformats::PrimaryVertexExt& v); +#endif + +} // namespace dataformats + +/// Defining PrimaryVertexExt explicitly as messageable +namespace framework +{ +template +struct is_messageable; +template <> +struct is_messageable : std::true_type { +}; +} // namespace framework + +} // namespace o2 +#endif diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h index fd7ea85b7bbbe..bbc2c01359276 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h @@ -178,9 +178,6 @@ template <> struct is_messageable>> : std::true_type { }; template <> -struct is_messageable>> : std::true_type { -}; -template <> struct is_messageable>> : std::true_type { }; } // namespace framework diff --git a/DataFormats/Reconstruction/src/PrimaryVertexExt.cxx b/DataFormats/Reconstruction/src/PrimaryVertexExt.cxx new file mode 100644 index 0000000000000..2f77c10f937a9 --- /dev/null +++ b/DataFormats/Reconstruction/src/PrimaryVertexExt.cxx @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ReconstructionDataFormats/PrimaryVertexExt.h" +#include +#include +#include "CommonUtils/StringUtils.h" + +namespace o2 +{ +namespace dataformats +{ + +#ifndef GPUCA_ALIGPUCODE +using GTrackID = o2::dataformats::GlobalTrackID; + +std::string PrimaryVertexExt::asString() const +{ + auto str = o2::utils::Str::concat_string(PrimaryVertex::asString(), fmt::format(" FT0Amp={} FT0T={}", FT0Amp, FT0Time)); + for (int i = 0; i < GTrackID::Source::NSources; i++) { + if (getNSrc(i) > 0) { + str += fmt::format(" {}={}", GTrackID::getSourceName(i), getNSrc(i)); + } + } + return str; +} + +std::ostream& operator<<(std::ostream& os, const o2::dataformats::PrimaryVertexExt& v) +{ + // stream itself + os << v.asString(); + return os; +} + +void PrimaryVertexExt::print() const +{ + std::cout << *this << std::endl; +} + +#endif + +} // namespace dataformats +} // namespace o2 diff --git a/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h b/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h index 29b8156caf872..dba8990e169ea 100644 --- a/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h +++ b/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h @@ -73,10 +73,12 @@ #pragma link C++ class o2::dataformats::Vertex < o2::dataformats::TimeStamp < int>> + ; #pragma link C++ class o2::dataformats::Vertex < o2::dataformats::TimeStampWithError < float, float>> + ; #pragma link C++ class o2::dataformats::PrimaryVertex + ; +#pragma link C++ class o2::dataformats::PrimaryVertexExt + ; #pragma link C++ class std::vector < o2::dataformats::Vertex < o2::dataformats::TimeStamp < int>>> + ; #pragma link C++ class std::vector < o2::dataformats::Vertex < o2::dataformats::TimeStampWithError < float, float>>> + ; #pragma link C++ class std::vector < o2::dataformats::PrimaryVertex> + ; +#pragma link C++ class std::vector < o2::dataformats::PrimaryVertexExt> + ; #pragma link C++ class o2::dataformats::GlobalTrackID + ; #pragma link C++ class std::vector < o2::dataformats::GlobalTrackID> + ; diff --git a/DataFormats/Reconstruction/src/Vertex.cxx b/DataFormats/Reconstruction/src/Vertex.cxx index dfbc5eac281e8..b902e9972a13d 100644 --- a/DataFormats/Reconstruction/src/Vertex.cxx +++ b/DataFormats/Reconstruction/src/Vertex.cxx @@ -56,5 +56,8 @@ bool VertexBase::operator==(const VertexBase& other) const #endif +template class o2::dataformats::Vertex>; +template class o2::dataformats::Vertex>; + } // namespace dataformats } // namespace o2 diff --git a/DataFormats/common/CMakeLists.txt b/DataFormats/common/CMakeLists.txt index 0e0e4076eb000..6b0081a920c8d 100644 --- a/DataFormats/common/CMakeLists.txt +++ b/DataFormats/common/CMakeLists.txt @@ -16,6 +16,7 @@ o2_add_library(CommonDataFormat src/FlatHisto2D.cxx src/AbstractRefAccessor.cxx src/TFIDInfo.cxx + src/TimeStamp.cxx PUBLIC_LINK_LIBRARIES O2::CommonConstants O2::GPUCommon ROOT::Core O2::MathUtils Microsoft.GSL::GSL) diff --git a/DataFormats/common/src/TimeStamp.cxx b/DataFormats/common/src/TimeStamp.cxx new file mode 100644 index 0000000000000..2681c9721ba42 --- /dev/null +++ b/DataFormats/common/src/TimeStamp.cxx @@ -0,0 +1,19 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonDataFormat/TimeStamp.h" + +template class o2::dataformats::TimeStamp; +template class o2::dataformats::TimeStamp; +template class o2::dataformats::TimeStamp; +template class o2::dataformats::TimeStampWithError; +template class o2::dataformats::TimeStampWithError; +template class o2::dataformats::TimeStampWithError; diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx index 3a0290a9c0b0d..22eb1111aed5b 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx @@ -31,6 +31,8 @@ #include "GlobalTrackingStudy/TrackingStudy.h" #include "TPCBase/ParameterElectronics.h" #include "ReconstructionDataFormats/PrimaryVertex.h" +#include "ReconstructionDataFormats/PrimaryVertexExt.h" +#include "DataFormatsFT0/RecPoints.h" #include "CommonUtils/TreeStreamRedirector.h" #include "ReconstructionDataFormats/VtxTrackRef.h" #include "ReconstructionDataFormats/DCA.h" @@ -69,6 +71,7 @@ class TrackingStudySpec : public Task std::shared_ptr mGGCCDBRequest; bool mUseMC{false}; ///< MC flag std::unique_ptr mDBGOut; + std::unique_ptr mDBGOutVtx; float mITSROFrameLengthMUS = 0.; GTrackID::mask_t mTracksSrc{}; o2::steer::MCKinematicsReader mcReader; // reader of MC information @@ -78,6 +81,7 @@ void TrackingStudySpec::init(InitContext& ic) { o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); mDBGOut = std::make_unique("trackStudy.root", "recreate"); + mDBGOutVtx = std::make_unique("trackStudyVtx.root", "recreate"); } void TrackingStudySpec::run(ProcessingContext& pc) @@ -111,19 +115,44 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) auto trackIndex = recoData.getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks auto vtxRefs = recoData.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs auto prop = o2::base::Propagator::Instance(); - + auto FITInfo = recoData.getFT0RecPoints(); int nv = vtxRefs.size() - 1; + o2::dataformats::PrimaryVertexExt pveDummy; + std::vector pveVec; + for (int iv = 0; iv < nv; iv++) { + LOGP(debug, "processing PV {} of {}", iv, nv); + const auto& vtref = vtxRefs[iv]; auto pv = pvvec[iv]; + auto& pve = pveVec.emplace_back(); + static_cast(pve) = pv; + + float bestTimeDiff = 1000, bestTime = -999, bestAmp = -1; + for (int ift0 = vtref.getFirstEntryOfSource(GTrackID::FT0); ift0 < vtref.getFirstEntryOfSource(GTrackID::FT0) + vtref.getEntriesOfSource(GTrackID::FT0); ift0++) { + const auto& ft0 = FITInfo[trackIndex[ift0]]; + if (ft0.isValidTime(o2::ft0::RecPoints::TimeMean) && ft0.getTrigger().getAmplA() + ft0.getTrigger().getAmplC() > 20) { + auto fitTime = ft0.getInteractionRecord().differenceInBCMUS(recoData.startIR); + if (std::abs(fitTime - pv.getTimeStamp().getTimeStamp()) < bestTimeDiff) { + bestTimeDiff = fitTime - pv.getTimeStamp().getTimeStamp(); + bestTime = fitTime; + bestAmp = ft0.getTrigger().getAmplA() + ft0.getTrigger().getAmplC(); + } + } + } + pve.FT0Amp = bestAmp; + pve.FT0Time = bestTime; for (int is = 0; is < GTrackID::NSources; is++) { if (!GTrackID::getSourceDetectorsMask(is)[GTrackID::ITS]) { continue; } - int idMin = vtxRefs[iv].getFirstEntryOfSource(is), idMax = idMin + vtxRefs[iv].getEntriesOfSource(is); + int idMin = vtref.getFirstEntryOfSource(is), idMax = idMin + vtref.getEntriesOfSource(is); for (int i = idMin; i < idMax; i++) { auto vid = trackIndex[i]; bool pvCont = vid.isPVContributor(); + if (pvCont) { + pve.nSrc[is]++; + } bool ambig = vid.isAmbiguous(); auto trc = recoData.getTrackParam(vid); float xmin = trc.getX(); @@ -136,11 +165,23 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) } } } + + for (size_t cnt = 0; cnt < pveVec.size(); cnt++) { + const auto& pve = pveVec[cnt]; + const auto& pvePrev = cnt > 0 ? pveVec[cnt - 1] : pveDummy; + const auto& pveNext = cnt == pveVec.size() - 1 ? pveDummy : pveVec[cnt + 1]; + (*mDBGOutVtx) << "pvExt" + << "pve=" << pve + << "pveP=" << pvePrev + << "pveN=" << pveNext + << "\n"; + } } void TrackingStudySpec::endOfStream(EndOfStreamContext& ec) { mDBGOut.reset(); + mDBGOutVtx.reset(); } void TrackingStudySpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) From 1d5fb4624e00d8f3bf5d33dbed91d3501fbddeb1 Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 8 Sep 2023 17:55:30 +0200 Subject: [PATCH 013/324] Make run_trac_its.C empty in interpreter mode --- macro/run_trac_its.C | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/macro/run_trac_its.C b/macro/run_trac_its.C index 67bc075c5754d..824e4ebcf5d79 100644 --- a/macro/run_trac_its.C +++ b/macro/run_trac_its.C @@ -1,3 +1,14 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + #if !defined(__CLING__) || defined(__ROOTCLING__) #include #include @@ -30,7 +41,6 @@ #include "CCDB/BasicCCDBManager.h" #include "CCDB/CCDBTimeStampUtils.h" #include "DataFormatsITSMFT/TopologyDictionary.h" -#endif #include "ReconstructionDataFormats/PrimaryVertex.h" // hack to silence JIT compiler #include "ITStracking/ROframe.h" @@ -208,3 +218,5 @@ void run_trac_its(std::string path = "./", std::string outputfile = "o2trac_its. timer.Stop(); timer.Print(); } + +#endif From d9ef845660b2de08deb657b8f2aefc90a5f1fb47 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Sun, 10 Sep 2023 08:16:45 +0200 Subject: [PATCH 014/324] DPL Analysis: provide metadata to workflow construction (#11875) --- .../src/AODJAlienReaderHelpers.cxx | 4 +- Framework/Core/CMakeLists.txt | 1 + .../include/Framework/ConfigParamDiscovery.h | 34 +++++++++ .../include/Framework/runDataProcessing.h | 3 + Framework/Core/src/ConfigParamDiscovery.cxx | 71 +++++++++++++++++++ .../Core/src/WorkflowCustomizationHelpers.cxx | 4 ++ Framework/Core/src/WorkflowHelpers.cxx | 2 +- .../TestWorkflows/src/o2AnalysisWorkflow.cxx | 13 +++- 8 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 Framework/Core/include/Framework/ConfigParamDiscovery.h create mode 100644 Framework/Core/src/ConfigParamDiscovery.cxx diff --git a/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx b/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx index 1e20f46c2e464..9cd7d5affc379 100644 --- a/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx @@ -133,12 +133,12 @@ AlgorithmSpec AODJAlienReaderHelpers::rootFileReaderCallback() stats.updateStats({static_cast(ProcessingStatsId::ARROW_MESSAGES_DESTROYED), DataProcessingStats::Op::Set, 0}); stats.updateStats({static_cast(ProcessingStatsId::ARROW_BYTES_EXPIRED), DataProcessingStats::Op::Set, 0}); - if (!options.isSet("aod-file")) { + if (!options.isSet("aod-file-private")) { LOGP(fatal, "No input file defined!"); throw std::runtime_error("Processing is stopped!"); } - auto filename = options.get("aod-file"); + auto filename = options.get("aod-file-private"); std::string parentFileReplacement; if (options.isSet("aod-parent-base-path-replacement")) { diff --git a/Framework/Core/CMakeLists.txt b/Framework/Core/CMakeLists.txt index eabc3f7c30593..f71744f33f77e 100644 --- a/Framework/Core/CMakeLists.txt +++ b/Framework/Core/CMakeLists.txt @@ -45,6 +45,7 @@ o2_add_library(Framework src/DefaultsHelpers.cxx src/DomainInfoHeader.cxx src/ProcessingPoliciesHelpers.cxx + src/ConfigParamDiscovery.cxx src/ConfigParamStore.cxx src/ConfigParamsHelper.cxx src/ChannelParamSpec.cxx diff --git a/Framework/Core/include/Framework/ConfigParamDiscovery.h b/Framework/Core/include/Framework/ConfigParamDiscovery.h new file mode 100644 index 0000000000000..c4bdb497366b7 --- /dev/null +++ b/Framework/Core/include/Framework/ConfigParamDiscovery.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_CONFIGPARAMDISCOVERY_H_ +#define O2_FRAMEWORK_CONFIGPARAMDISCOVERY_H_ + +#include "Framework/ConfigParamRegistry.h" + +namespace o2::framework +{ +struct ConfigParamDiscovery { + /// Given a ConfigParamRegistry, discovers all the extrac ConfigParam + /// which require an additional lookup starting from the ones already + /// present. E.g. you could use this to populate the registry with + /// ConfigParams defined in a file. + static void discover(ConfigParamRegistry& registry); +}; + +/// A plugin which is able to discover more option then the ones +/// provided on the command line. +struct ConfigDiscoveryPlugin { + virtual void discover(ConfigParamRegistry& registry) = 0; +}; + +} // namespace o2::framework +#endif // O2_FRAMEWORK_CONFIGPARAMDISCOVERY_H_ diff --git a/Framework/Core/include/Framework/runDataProcessing.h b/Framework/Core/include/Framework/runDataProcessing.h index bfda47d07971c..2112dc7cbfd5d 100644 --- a/Framework/Core/include/Framework/runDataProcessing.h +++ b/Framework/Core/include/Framework/runDataProcessing.h @@ -30,6 +30,7 @@ #include "Framework/Logger.h" #include "Framework/CheckTypes.h" #include "Framework/StructToTuple.h" +#include "Framework/ConfigParamDiscovery.h" #include #include @@ -203,6 +204,8 @@ int mainNoCatch(int argc, char** argv) workflowOptionsStore->preload(); workflowOptionsStore->activate(); ConfigParamRegistry workflowOptionsRegistry(std::move(workflowOptionsStore)); + ConfigParamDiscovery::discover(workflowOptionsRegistry); + ConfigContext configContext(workflowOptionsRegistry, argc, argv); o2::framework::WorkflowSpec specs = defineDataProcessing(configContext); overrideCloning(configContext, specs); diff --git a/Framework/Core/src/ConfigParamDiscovery.cxx b/Framework/Core/src/ConfigParamDiscovery.cxx new file mode 100644 index 0000000000000..e392bf155d457 --- /dev/null +++ b/Framework/Core/src/ConfigParamDiscovery.cxx @@ -0,0 +1,71 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ConfigParamDiscovery.h" +#include "Framework/Plugins.h" +#include +#include +#include + +namespace o2::framework +{ + +void ConfigParamDiscovery::discover(ConfigParamRegistry& registry) +{ + // Keep track of the plugins + std::vector plugins; + if (registry.hasOption("aod-file") && registry.isSet("aod-file")) { + auto filename = registry.get("aod-file"); + if (filename.empty()) { + return; + } + TFile* currentFile = nullptr; + if (filename.at(0) == '@') { + filename.erase(0, 1); + // read the text file and set filename to the contents of the first line + std::ifstream file(filename); + if (!file.is_open()) { + LOGP(fatal, "Couldn't open file \"{}\"!", filename); + } + std::getline(file, filename); + file.close(); + currentFile = TFile::Open(filename.c_str()); + } else { + currentFile = TFile::Open(filename.c_str()); + } + if (!currentFile) { + LOGP(fatal, "Couldn't open file \"{}\"!", filename); + } + + // Get the metadata, if any + auto m = (TMap*)currentFile->Get("metaData"); + if (!m) { + LOGP(warning, "No metadata found in file \"{}\"", filename); + return; + } + auto it = m->MakeIterator(); + + // Serialise metadata into a ; separated string with : separating key and value + bool first = true; + while (auto obj = it->Next()) { + if (first) { + LOGP(info, "Metadata for file \"{}\":", filename); + first = false; + } + auto objString = (TObjString*)m->GetValue(obj); + LOGP(info, "- {}: {}", obj->GetName(), objString->String()); + std::string key = "aod-metadata-" + std::string(obj->GetName()); + registry.override(key.c_str(), objString->String()); + } + } +} + +} // namespace o2::framework diff --git a/Framework/Core/src/WorkflowCustomizationHelpers.cxx b/Framework/Core/src/WorkflowCustomizationHelpers.cxx index da21168a8fe44..efdc535c683c5 100644 --- a/Framework/Core/src/WorkflowCustomizationHelpers.cxx +++ b/Framework/Core/src/WorkflowCustomizationHelpers.cxx @@ -54,6 +54,10 @@ std::vector WorkflowCustomizationHelpers::requiredWorkflowOptio // options for AOD rate limiting {"aod-memory-rate-limit", VariantType::Int64, 0LL, {"Rate limit AOD processing based on memory"}}, + // options for the AOD reader + // aod-file needs to be available as workflow option, because we + // can configure the workflow based on the contents of the first file. + {"aod-file", VariantType::String, "", {"Input AOD file"}}, // options for AOD writer {"aod-writer-json", VariantType::String, "", {"Name of the json configuration file"}}, {"aod-writer-resdir", VariantType::String, "", {"Name of the output directory"}}, diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index ce56385f71dd4..c2049dedcfc8f 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -297,7 +297,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext static_cast(compile_time_hash("internal-dpl-aod-reader")), aodLifetime}}, .algorithm = AlgorithmSpec::dummyAlgorithm(), - .options = {ConfigParamSpec{"aod-file", VariantType::String, {"Input AOD file"}}, + .options = {ConfigParamSpec{"aod-file-private", VariantType::String, ctx.options().get("aod-file"), {"AOD file"}}, ConfigParamSpec{"aod-reader-json", VariantType::String, {"json configuration file"}}, ConfigParamSpec{"aod-parent-access-level", VariantType::String, {"Allow parent file access up to specified level. Default: no (0)"}}, ConfigParamSpec{"aod-parent-base-path-replacement", VariantType::String, {R"(Replace base path of parent files. Syntax: FROM;TO. E.g. "alien:///path/in/alien;/local/path". Enclose in "" on the command line.)"}}, diff --git a/Framework/TestWorkflows/src/o2AnalysisWorkflow.cxx b/Framework/TestWorkflows/src/o2AnalysisWorkflow.cxx index c0da7a24c1a90..b1c6da0775b2e 100644 --- a/Framework/TestWorkflows/src/o2AnalysisWorkflow.cxx +++ b/Framework/TestWorkflows/src/o2AnalysisWorkflow.cxx @@ -49,7 +49,14 @@ struct EtaAndClsHistograms { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - }; + // For the sake of running without an option, we do not throw an exception + // in case the option is not present. + if (cfgc.options().hasOption("aod-metadata-Run") == false || + cfgc.options().get("aod-metadata-Run") == "2") { + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; + } else { + throw std::runtime_error("Unsupported run type"); + } } From 364aeee3c1cb18ef8a4bc83c9a33f43f0832d82f Mon Sep 17 00:00:00 2001 From: wiechula Date: Wed, 6 Sep 2023 16:09:06 +0200 Subject: [PATCH 015/324] Fix writing debug information --- Detectors/TPC/calibration/src/TrackDump.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/TPC/calibration/src/TrackDump.cxx b/Detectors/TPC/calibration/src/TrackDump.cxx index f309dc5e77179..ca8d61643e7ee 100644 --- a/Detectors/TPC/calibration/src/TrackDump.cxx +++ b/Detectors/TPC/calibration/src/TrackDump.cxx @@ -107,7 +107,7 @@ void TrackDump::filter(const gsl::span tracks, ClusterNativeAcce } } if (writeGlobal) { - tree << "cls" << clustersGlobalEvent; + tree << "clsGlo=" << clustersGlobalEvent; } if (writeMC) { tree << "TPCTracksMCTruth=" << tpcTracksMCTruth; @@ -128,7 +128,7 @@ void TrackDump::filter(const gsl::span tracks, ClusterNativeAcce std::vector clustersUn; fillClNativeAdd(clusterIndex, clustersUn, &excludes); auto& cltree = (*treeDumpUn) << "clsn"; - cltree << "cls=" << clusters + cltree << "cls=" << clustersUn << "\n"; } } From 89fada8ac18166dfdd655b52eb7ba3de7e731925 Mon Sep 17 00:00:00 2001 From: wiechula Date: Wed, 6 Sep 2023 16:11:37 +0200 Subject: [PATCH 016/324] Only allow calibration triggers, allow early return --- .../TPCWorkflow/CalibProcessingHelper.h | 2 +- .../workflow/src/CalibProcessingHelper.cxx | 21 +++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h b/Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h index 36a2cb0cf6508..783320330d10b 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CalibProcessingHelper.h @@ -28,7 +28,7 @@ class RawReaderCRU; namespace calib_processing_helper { -uint64_t processRawData(o2::framework::InputRecord& inputs, std::unique_ptr& reader, bool useOldSubspec = false, const std::vector& sectors = {}, size_t* nerrors = nullptr, uint32_t syncOffsetReference = 144, uint32_t decoderType = 1, bool useTrigger = true); +uint64_t processRawData(o2::framework::InputRecord& inputs, std::unique_ptr& reader, bool useOldSubspec = false, const std::vector& sectors = {}, size_t* nerrors = nullptr, uint32_t syncOffsetReference = 144, uint32_t decoderType = 1, bool useTrigger = true, bool returnOnNoTrigger = false); /// absolute BC relative to TF start (firstOrbit) std::vector getFilter(o2::framework::InputRecord& inputs); diff --git a/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx b/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx index d335e55bd37aa..1abd248b69d6c 100644 --- a/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx +++ b/Detectors/TPC/workflow/src/CalibProcessingHelper.cxx @@ -73,7 +73,7 @@ std::vector calib_processing_helper::getFilter(o2::fra return filter; } -uint64_t calib_processing_helper::processRawData(o2::framework::InputRecord& inputs, std::unique_ptr& reader, bool useOldSubspec, const std::vector& sectors, size_t* nerrors, uint32_t syncOffsetReference, uint32_t decoderType, bool useTrigger) +uint64_t calib_processing_helper::processRawData(o2::framework::InputRecord& inputs, std::unique_ptr& reader, bool useOldSubspec, const std::vector& sectors, size_t* nerrors, uint32_t syncOffsetReference, uint32_t decoderType, bool useTrigger, bool returnOnNoTrigger) { std::vector filter = getFilter(inputs); @@ -85,6 +85,9 @@ uint64_t calib_processing_helper::processRawData(o2::framework::InputRecord& inp bool readFirstZS = false; const auto triggerBC = ((decoderType == 1 && useTrigger)) ? getTriggerBCoffset(inputs, filter) : -1; + if (returnOnNoTrigger && (triggerBC < 0)) { + return 0; + } // for LinkZS data the maximum sync offset is needed to align the data properly. // getBCsyncOffsetReference only works, if the full TF is seen. Alternatively, this value could be set @@ -435,13 +438,19 @@ int calib_processing_helper::getTriggerBCoffset(const char* data, size_t size, u return -1; } const auto triggerWord = (TriggerWordDLBZS*)(data + size - sizeof(TPCZSHDRV2) - sizeof(TriggerWordDLBZS)); - // Check only first trigger word assuming we will only have laser triggers - const int iTrg = 0; - if (!triggerWord->isValid(iTrg)) { - return -1; + // Only process calibration (Laser) triggers + int iTrg; + for (iTrg = 0; iTrg < TriggerWordDLBZS::MaxTriggerEntries; ++iTrg) { + if (triggerWord->isValid(iTrg)) { + if (triggerWord->getTriggerType(iTrg) == TriggerWordDLBZS::Cal) { + break; + } + } else { + return -1; + } } - const auto triggerBC = triggerWord->getTriggerBC(0); + const auto triggerBC = triggerWord->getTriggerBC(iTrg); const auto orbit = RDHUtils::getHeartBeatOrbit(rdh); const int orbitBC = ((orbit - firstOrbit) * o2::constants::lhc::LHCMaxBunches) + triggerBC; LOGP(debug, "TriggerWordDLBZS {}: Type = {}, orbit = {}, firstOrbit = {}, BC = {}, oribitBC = {}", iTrg, triggerWord->getTriggerType(iTrg), orbit, firstOrbit, triggerWord->getTriggerBC(iTrg), orbitBC); From a5d277582adc5eae8d745d8592e5833c1fc73007 Mon Sep 17 00:00:00 2001 From: wiechula Date: Fri, 8 Sep 2023 10:09:10 +0200 Subject: [PATCH 017/324] Fix Laser VDrift calibratio and make it more stable --- .../TPC/include/DataFormatsTPC/LtrCalibData.h | 49 ++++++++++++++++++- .../include/TPCCalibration/CalibLaserTracks.h | 3 +- .../TPC/calibration/src/CalibLaserTracks.cxx | 27 ++++++++-- .../TPC/calibration/src/VDriftHelper.cxx | 6 +-- .../TPCWorkflow/CalibLaserTracksSpec.h | 23 ++++++--- .../workflow/src/tpc-laser-track-filter.cxx | 4 +- 6 files changed, 91 insertions(+), 21 deletions(-) diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/LtrCalibData.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/LtrCalibData.h index f5a3626294eb9..17378df332775 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/LtrCalibData.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/LtrCalibData.h @@ -35,13 +35,42 @@ struct LtrCalibData { float dvOffsetA{}; ///< drift velocity trigger offset A-Side float dvOffsetC{}; ///< drift velocity trigger offset C-Side float refVDrift{}; ///< reference vdrift for which factor was extracted + float refTimeOffset{0.}; ///< additive time offset reference (\mus) + float timeOffsetCorr{0.}; ///< additive time offset correction (\mus) uint16_t nTracksA{}; ///< number of tracks used for A-Side fit uint16_t nTracksC{}; ///< number of tracks used for C-Side fit std::vector matchedLtrIDs; ///< matched laser track IDs std::vector nTrackTF; ///< number of laser tracks per TF std::vector dEdx; ///< dE/dx of each track - float getDriftVCorrection() const { return 0.5f * (dvCorrectionA + dvCorrectionC); } + float getDriftVCorrection() const + { + float correction = 0; + int nCorr = 0; + // only allow +- 20% around reference correction + if (std::abs(dvCorrectionA - 1.f) < 0.2) { + correction += dvCorrectionA; + ++nCorr; + } else { + LOGP(warning, "abs(dvCorrectionA ({}) - 1) >= 0.2, not using for combined estimate", dvCorrectionA); + } + + if (std::abs(dvCorrectionC - 1.f) < 0.2) { + correction += dvCorrectionC; + ++nCorr; + } else { + LOGP(warning, "abs(dvCorrectionC ({}) - 1) >= 0.2, not using for combined estimate", dvCorrectionC); + } + + if (nCorr == 0) { + LOGP(error, "no valid drift velocity correction"); + return 1.f; + } + + return correction / nCorr; + } + + float getTimeOffset() const { return refTimeOffset + timeOffsetCorr; } // renormalize reference and correction either to provided new reference (if >0) or to correction 1 wrt current reference void normalize(float newVRef = 0.f) @@ -63,6 +92,20 @@ struct LtrCalibData { dvCorrectionC *= fact; } + // similarly, the time offset reference is set to provided newRefTimeOffset (if > -998) or modified to have timeOffsetCorr to + // be 0 otherwise + + void normalizeOffset(float newRefTimeOffset = -999.) + { + if (newRefTimeOffset > -999.) { + timeOffsetCorr = getTimeOffset() - newRefTimeOffset; + refTimeOffset = newRefTimeOffset; + } else { + refTimeOffset = getTimeOffset(); + timeOffsetCorr = 0.; + } + } + float getT0A() const { return (250.f * (1.f - dvCorrectionA) - dvOffsetA) / refVDrift; } float getT0C() const { return (250.f * (1.f - dvCorrectionC) + dvOffsetC) / refVDrift; } float getZOffsetA() const { return (250.f * (1.f - dvCorrectionA) - dvOffsetA) / dvCorrectionA; } @@ -81,12 +124,14 @@ struct LtrCalibData { nTracksA = 0; nTracksC = 0; refVDrift = 0; + refTimeOffset = 0; + timeOffsetCorr = 0; matchedLtrIDs.clear(); nTrackTF.clear(); dEdx.clear(); } - ClassDefNV(LtrCalibData, 3); + ClassDefNV(LtrCalibData, 4); }; } // namespace o2::tpc diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibLaserTracks.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibLaserTracks.h index eed7989882c0c..cf77c69374f77 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibLaserTracks.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibLaserTracks.h @@ -23,6 +23,7 @@ #define TPC_CalibLaserTracks_H_ #include +#include #include "CommonConstants/MathConstants.h" #include "CommonUtils/TreeStreamRedirector.h" @@ -140,7 +141,7 @@ class CalibLaserTracks bool getWriteDebugTree() const { return mWriteDebugTree; } /// extract DV correction and T0 offset - TimePair fit(const std::vector& trackMatches) const; + TimePair fit(const std::vector& trackMatches, std::string_view info) const; /// sort TimePoint vectors void sort(std::vector& trackMatches); diff --git a/Detectors/TPC/calibration/src/CalibLaserTracks.cxx b/Detectors/TPC/calibration/src/CalibLaserTracks.cxx index cc796462152ce..81e3d9f99dde5 100644 --- a/Detectors/TPC/calibration/src/CalibLaserTracks.cxx +++ b/Detectors/TPC/calibration/src/CalibLaserTracks.cxx @@ -19,6 +19,8 @@ #include "TPCCalibration/CalibLaserTracks.h" #include "TLinearFitter.h" #include +#include +#include using namespace o2::tpc; void CalibLaserTracks::fill(std::vector const& tracks) @@ -94,6 +96,7 @@ void CalibLaserTracks::processTrack(const TrackTPC& track) zTrack += zOffset; parOutAtLtr.setZ(zTrack); } else if (mTriggerPos > 0) { + const float zOffset = mTriggerPos; } if (std::abs(zTrack) > 300) { @@ -321,8 +324,8 @@ void CalibLaserTracks::finalize() //______________________________________________________________________________ void CalibLaserTracks::fillCalibData(LtrCalibData& calibData, const std::vector& pairsA, const std::vector& pairsC) { - auto dvA = fit(pairsA); - auto dvC = fit(pairsC); + auto dvA = fit(pairsA, "A-Side"); + auto dvC = fit(pairsC, "C-Side"); calibData.creationTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); calibData.refVDrift = mDriftV; calibData.dvOffsetA = dvA.x1; @@ -335,7 +338,7 @@ void CalibLaserTracks::fillCalibData(LtrCalibData& calibData, const std::vector< } //______________________________________________________________________________ -TimePair CalibLaserTracks::fit(const std::vector& trackMatches) const +TimePair CalibLaserTracks::fit(const std::vector& trackMatches, std::string_view info) const { if (!trackMatches.size()) { return TimePair(); @@ -346,12 +349,17 @@ TimePair CalibLaserTracks::fit(const std::vector& trackMatches) const fit.ClearPoints(); uint64_t meanTime = 0; + double minZrec = 1000; + double maxZrec = -1000; for (const auto& point : trackMatches) { double x = point.x1; double y = point.x2; fit.AddPoint(&x, y); meanTime += point.time; + + minZrec = std::min(y, minZrec); + maxZrec = std::max(y, maxZrec); } meanTime /= uint64_t(trackMatches.size()); @@ -360,6 +368,11 @@ TimePair CalibLaserTracks::fit(const std::vector& trackMatches) const const int minPoints = 6; if (trackMatches.size() < size_t(minPoints / robustFraction)) { + LOGP(warning, "{} - Not enough points to perform the fit: {} < {}", info, trackMatches.size(), size_t(minPoints / robustFraction)); + return TimePair({0, 0, meanTime}); + } + if (std::abs(maxZrec - minZrec) < 50) { + LOGP(warning, "{} - All points seem to be from one Layer: abs({}cm - {}cm) < 50cm, will not do fitting", info, trackMatches.size(), maxZrec, minZrec); return TimePair({0, 0, meanTime}); } @@ -385,7 +398,7 @@ void CalibLaserTracks::print() const { if (mFinalized) { LOGP(info, - "Processed {} TFs from {} - {}; found tracks: {} / {}; T0 offsets: {} / {}; dv correction factors: {} / {} for A- / C-Side, reference: {}", + "Processed {} TFs from {} - {}; found tracks: {} / {}; fit offsets (cm): {} / {}; T0s (us): {} / {}; dv correction factors: {} / {} for A- / C-Side, reference: {}", mCalibData.processedTFs, mCalibData.firstTime, mCalibData.lastTime, @@ -393,6 +406,8 @@ void CalibLaserTracks::print() const mCalibData.nTracksC, mCalibData.dvOffsetA, mCalibData.dvOffsetC, + mCalibData.getT0A(), + mCalibData.getT0C(), mCalibData.dvCorrectionA, mCalibData.dvCorrectionC, mCalibData.refVDrift); @@ -404,13 +419,15 @@ void CalibLaserTracks::print() const mCalibData.lastTime); LOGP(info, - "Last processed TF from {} - {}; found tracks: {} / {}; T0 offsets: {} / {}; dv correction factors: {} / {} for A- / C-Side, reference: {}", + "Last processed TF from {} - {}; found tracks: {} / {}; fit offsets (cm): {} / {}; T0s (us): {} / {}; dv correction factors: {} / {} for A- / C-Side, reference: {}", mCalibDataTF.firstTime, mCalibDataTF.lastTime, mCalibDataTF.nTracksA, mCalibDataTF.nTracksC, mCalibDataTF.dvOffsetA, mCalibDataTF.dvOffsetC, + mCalibDataTF.getT0A(), + mCalibDataTF.getT0C(), mCalibDataTF.dvCorrectionA, mCalibDataTF.dvCorrectionC, mCalibDataTF.refVDrift); diff --git a/Detectors/TPC/calibration/src/VDriftHelper.cxx b/Detectors/TPC/calibration/src/VDriftHelper.cxx index 13f8e3e5bcc27..034888998e567 100644 --- a/Detectors/TPC/calibration/src/VDriftHelper.cxx +++ b/Detectors/TPC/calibration/src/VDriftHelper.cxx @@ -58,7 +58,7 @@ void VDriftHelper::accountLaserCalibration(const LtrCalibData* calib, long fallB } // old entries of laser calib have no update time assigned long updateTS = calib->creationTime > 0 ? calib->creationTime : fallBackTimeStamp; - LOG(info) << "accountLaserCalibration " << calib->getDriftVCorrection() << " t " << updateTS << " vs " << mVDLaser.creationTime; + LOG(info) << "accountLaserCalibration " << calib->refVDrift << " / " << calib->getDriftVCorrection() << " t " << updateTS << " vs " << mVDLaser.creationTime; // old entries of laser calib have no reference assigned float ref = calib->refVDrift > 0. ? calib->refVDrift : o2::tpc::ParameterGas::Instance().DriftV; float corr = calib->getDriftVCorrection(); @@ -71,7 +71,7 @@ void VDriftHelper::accountLaserCalibration(const LtrCalibData* calib, long fallB mUpdated = true; mSource = Source::Laser; if (mMayRenormSrc & (0x1U << Source::Laser)) { // this was 1st setting? - if (corr != 1.f) { // this may happen if old-style (non-normalized) standalone or non-normalized run-time laset calibration is used + if (corr != 1.f) { // this may happen if old-style (non-normalized) standalone or non-normalized run-time laset calibration is used LOGP(warn, "VDriftHelper: renorming initinal TPC refVDrift={}/correction={} to {}/1.0, source: {}", mVDLaser.refVDrift, mVDLaser.corrFact, mVDLaser.getVDrift(), getSourceName(mSource)); mVDLaser.normalize(); // renorm reference to have correction = 1. } @@ -95,7 +95,7 @@ void VDriftHelper::accountDriftCorrectionITSTPCTgl(const VDriftCorrFact* calib) mVDTPCITSTgl = *calib; mUpdated = true; mSource = Source::ITSTPCTgl; - if (mMayRenormSrc & (0x1U << Source::ITSTPCTgl)) { // this was 1st setting? + if (mMayRenormSrc & (0x1U << Source::ITSTPCTgl)) { // this was 1st setting? if (!mForceParamDrift && mVDTPCITSTgl.corrFact != 1.f) { // this may happen if calibration from prevous run is used LOGP(warn, "VDriftHelper: renorming initinal TPC refVDrift={}/correction={} to {}/1.0, source: {}", mVDTPCITSTgl.refVDrift, mVDTPCITSTgl.corrFact, mVDTPCITSTgl.getVDrift(), getSourceName(mSource)); mVDTPCITSTgl.normalize(); // renorm reference to have correction = 1. diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CalibLaserTracksSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/CalibLaserTracksSpec.h index 5ba1590dec7e2..3222d24667760 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/CalibLaserTracksSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CalibLaserTracksSpec.h @@ -15,6 +15,7 @@ /// @file CalibLaserTracksSpec.h /// @brief Device to run tpc laser track calibration +#include "TFile.h" #include "TPCCalibration/CalibLaserTracks.h" #include "DetectorsCalibration/Utils.h" #include "CommonUtils/MemFileHelper.h" @@ -39,7 +40,8 @@ class CalibLaserTracksDevice : public o2::framework::Task public: void init(o2::framework::InitContext& ic) final { - mCalib.setWriteDebugTree(ic.options().get("write-debug")); + mWriteDebug = ic.options().get("write-debug"); + mCalib.setWriteDebugTree(mWriteDebug); mMinNumberTFs = ic.options().get("min-tfs"); mOnlyPublishOnEOS = ic.options().get("only-publish-on-eos"); mNormalize = !ic.options().get("ignore-normalization"); @@ -62,6 +64,11 @@ class CalibLaserTracksDevice : public o2::framework::Task return; } mTPCVDriftHelper.extractCCDBInputs(pc); + if (mTPCVDriftHelper.isUpdated()) { + mTPCVDriftHelper.acknowledgeUpdate(); + mCalib.setVDriftRef(mTPCVDriftHelper.getVDriftObject().getVDrift()); + LOGP(info, "Updated reference drift velocity to: {}", mTPCVDriftHelper.getVDriftObject().getVDrift()); + } const auto startTime = dph->startTime; const auto endTime = dph->startTime + dph->duration; mRunNumber = processing_helpers::getRunNumber(pc); @@ -90,22 +97,19 @@ class CalibLaserTracksDevice : public o2::framework::Task void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final { if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { - if (mTPCVDriftHelper.isUpdated()) { - mTPCVDriftHelper.acknowledgeUpdate(); - mCalib.setVDriftRef(mTPCVDriftHelper.getVDriftObject().getVDrift()); - } return; } } private: - CalibLaserTracks mCalib; ///< laser track calibration component + CalibLaserTracks mCalib; ///< laser track calibration component o2::tpc::VDriftHelper mTPCVDriftHelper{}; uint64_t mRunNumber{0}; ///< processed run number int mMinNumberTFs{100}; ///< minimum number of TFs required for good calibration bool mPublished{false}; ///< if calibration was already published bool mOnlyPublishOnEOS{false}; ///< if to only publish the calibration on EOS, not during running bool mNormalize{true}; ///< normalize reference to have mean correction = 1 + bool mWriteDebug{false}; ///< Write debug output //________________________________________________________________ void sendOutput(DataAllocator& output) @@ -120,7 +124,7 @@ class CalibLaserTracksDevice : public o2::framework::Task if (mNormalize) { ltrCalib.normalize(0.); - LOGP(info, "After normalization: correction factors: {} / {} for A- / C-Side, reference: {}", ltrCalib.dvCorrectionA, ltrCalib.dvCorrectionC, ltrCalib.refVDrift); + LOGP(info, "After normalization: correction factors: {} / {} for A- / C-Side, reference: {}, vdrift correction: {}", ltrCalib.dvCorrectionA, ltrCalib.dvCorrectionC, ltrCalib.refVDrift, ltrCalib.getDriftVCorrection()); } if (ltrCalib.getDriftVCorrection() == 0) { LOG(error) << "Extracted drift correction is 0, something is wrong, will not upload the object"; @@ -148,6 +152,11 @@ class CalibLaserTracksDevice : public o2::framework::Task output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TPC_CalibLtr", 0}, w); mPublished = true; + + if (mWriteDebug) { + TFile f("LaserTracks.snapshot.root", "recreate"); + f.WriteObject(<rCalib, "ccdb_object"); + } } }; diff --git a/Detectors/TPC/workflow/src/tpc-laser-track-filter.cxx b/Detectors/TPC/workflow/src/tpc-laser-track-filter.cxx index a1f1ef75ff3ba..7b31bf80b8874 100644 --- a/Detectors/TPC/workflow/src/tpc-laser-track-filter.cxx +++ b/Detectors/TPC/workflow/src/tpc-laser-track-filter.cxx @@ -12,8 +12,6 @@ #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "Framework/WorkflowSpec.h" #include "Framework/ConfigParamSpec.h" -#include "Framework/CompletionPolicy.h" -#include "Framework/CompletionPolicyHelpers.h" #include "TPCWorkflow/LaserTrackFilterSpec.h" #include "DataFormatsTPC/TrackTPC.h" @@ -47,7 +45,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) const char* defaultFileName = "tpc-laser-tracks.root"; const char* defaultTreeName = "tpcrec"; - //branch definitions for RootTreeWriter spec + // branch definitions for RootTreeWriter spec using TrackOutputType = std::vector; // a spectator callback which will be invoked by the tree writer with the extracted object From 2493698c4f3f524d9e1a4edb40c32f8f763d8a74 Mon Sep 17 00:00:00 2001 From: sidibu <55976675+sidibu@users.noreply.github.com> Date: Mon, 11 Sep 2023 09:34:57 +0200 Subject: [PATCH 018/324] Occupancy Filter Device (#11778) * Add simple occupancy filter device to analyse special events * Break out of loop in case of the time bin occupancy greater than the given threshold * Implemented ADC Value Threshold Added the adc-threshold option to only count digits which ADC Value is greater than a certain threshold. * Pad Output with empty Data In case the calculated occupancy is not greater than the given threshold, the output of the filter is now padded with empty data. * Implemented Filtering by Timestamp and ADC Value * Fixed Formatting * Implemented suggested changes * Changed type of min-timestamp option to long --------- Co-authored-by: wiechula --- Detectors/TPC/workflow/CMakeLists.txt | 6 + .../include/TPCWorkflow/OccupancyFilterSpec.h | 29 +++ .../TPC/workflow/src/OccupancyFilterSpec.cxx | 138 +++++++++++ .../TPC/workflow/src/tpc-occupancy-filter.cxx | 220 ++++++++++++++++++ 4 files changed, 393 insertions(+) create mode 100644 Detectors/TPC/workflow/include/TPCWorkflow/OccupancyFilterSpec.h create mode 100644 Detectors/TPC/workflow/src/OccupancyFilterSpec.cxx create mode 100644 Detectors/TPC/workflow/src/tpc-occupancy-filter.cxx diff --git a/Detectors/TPC/workflow/CMakeLists.txt b/Detectors/TPC/workflow/CMakeLists.txt index 7d504630bc476..4dc4d3345005c 100644 --- a/Detectors/TPC/workflow/CMakeLists.txt +++ b/Detectors/TPC/workflow/CMakeLists.txt @@ -23,6 +23,7 @@ o2_add_library(TPCWorkflow src/CalDetMergerPublisherSpec.cxx src/KryptonClustererSpec.cxx src/KryptonRawFilterSpec.cxx + src/OccupancyFilterSpec.cxx src/SACProcessorSpec.cxx src/IDCToVectorSpec.cxx src/CalibdEdxSpec.cxx @@ -170,6 +171,11 @@ o2_add_executable(krypton-raw-filter SOURCES src/tpc-krypton-raw-filter.cxx PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) +o2_add_executable(occupancy-filter + COMPONENT_NAME tpc + SOURCES src/tpc-occupancy-filter.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + o2_add_executable(idc-to-vector COMPONENT_NAME tpc SOURCES src/tpc-idc-to-vector.cxx diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/OccupancyFilterSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/OccupancyFilterSpec.h new file mode 100644 index 0000000000000..7fcf67d0f8f71 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/OccupancyFilterSpec.h @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file OccupancyFilterSpec.h +/// @author Jens Wiechula +/// @since 2021-11-19 +/// @brief Processor spec for filtering krypton raw data + +#ifndef TPC_OccupancyFilterSpec_H_ +#define TPC_OccupancyFilterSpec_H_ + +#include "Framework/DataProcessorSpec.h" + +namespace o2::tpc +{ + +o2::framework::DataProcessorSpec getOccupancyFilterSpec(); + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/workflow/src/OccupancyFilterSpec.cxx b/Detectors/TPC/workflow/src/OccupancyFilterSpec.cxx new file mode 100644 index 0000000000000..9891d80a39503 --- /dev/null +++ b/Detectors/TPC/workflow/src/OccupancyFilterSpec.cxx @@ -0,0 +1,138 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include +#include +#include +#include + +#include "Framework/ConfigParamRegistry.h" +#include "Framework/Task.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Headers/DataHeader.h" + +#include "DataFormatsTPC/TPCSectorHeader.h" +#include "DataFormatsTPC/Digit.h" +#include "TPCWorkflow/OccupancyFilterSpec.h" + +using namespace o2::framework; +using namespace o2::header; +using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; + +namespace o2::tpc +{ + +class OccupancyFilterDevice : public o2::framework::Task +{ + public: + OccupancyFilterDevice() = default; + + void init(o2::framework::InitContext& ic) final + { + mOccupancyThreshold = ic.options().get("occupancy-threshold"); + mAdcValueThreshold = ic.options().get("adc-threshold"); + mMinimumTimeStamp = ic.options().get("min-timestamp"); + mFilterAdcValue = ic.options().get("filter-adc"); + mFilterTimeStamp = ic.options().get("filter-timestamp"); + LOGP(debug, "got minimum timestamp {}", mMinimumTimeStamp); + } + + void run(o2::framework::ProcessingContext& pc) final + { + for (auto const& inputRef : InputRecordWalker(pc.inputs())) { + auto const* sectorHeader = DataRefUtils::getHeader(inputRef); + if (sectorHeader == nullptr) { + LOGP(error, "sector header missing on header stack for input on ", inputRef.spec->binding); + continue; + } + + const int sector = sectorHeader->sector(); + auto inDigitsO = pc.inputs().get>(inputRef); + LOGP(debug, "processing sector {} with {} input digits", sector, inDigitsO.size()); + + std::vector digitsPerTimeBin(int(128 * 445.5)); + + for (const auto& digit : inDigitsO) { + if ((digit.getChargeFloat() > mAdcValueThreshold) && (digit.getTimeStamp() > mMinimumTimeStamp)) { + ++digitsPerTimeBin[digit.getTimeStamp()]; + } + } + + bool isAboveThreshold{false}; + for (const auto& timeBinOccupancy : digitsPerTimeBin) { + if (timeBinOccupancy > mOccupancyThreshold) { + LOGP(info, "Sector {}, timeBinOccupancy {} > occupancy-threshold {}", sector, timeBinOccupancy, mOccupancyThreshold); + isAboveThreshold = true; + break; + } + } + + std::vector cpDigits; + if (isAboveThreshold) { + std::copy_if(inDigitsO.begin(), inDigitsO.end(), std::back_inserter(cpDigits), + [this](const auto& digit) { + return (!mFilterTimeStamp || (digit.getTimeStamp() > mMinimumTimeStamp)) && (!mFilterAdcValue || (digit.getChargeFloat() > mAdcValueThreshold)); + }); + } + snapshot(pc.outputs(), cpDigits, sector); + + ++mProcessedTFs; + LOGP(info, "Number of processed time frames: {}", mProcessedTFs); + } + } + + private: + float mOccupancyThreshold{50.f}; + float mAdcValueThreshold{0.f}; + long mMinimumTimeStamp{0LL}; + bool mFilterAdcValue{false}; + bool mFilterTimeStamp{false}; + uint32_t mProcessedTFs{0}; + + //____________________________________________________________________________ + void snapshot(DataAllocator& output, std::vector& digits, int sector) + { + o2::tpc::TPCSectorHeader header{sector}; + header.activeSectors = (0x1 << sector); + output.snapshot(Output{gDataOriginTPC, "FILTERDIG", static_cast(sector), Lifetime::Sporadic, header}, digits); + } +}; + +o2::framework::DataProcessorSpec getOccupancyFilterSpec() +{ + using device = o2::tpc::OccupancyFilterDevice; + + std::vector inputs{ + InputSpec{"digits", gDataOriginTPC, "DIGITS", 0, Lifetime::Timeframe}, + }; + + std::vector outputs; + outputs.emplace_back(gDataOriginTPC, "FILTERDIG", 0, Lifetime::Sporadic); + + return DataProcessorSpec{ + "tpc-occupancy-filter", + inputs, + outputs, + AlgorithmSpec{adaptFromTask()}, + Options{ + {"occupancy-threshold", VariantType::Float, 50.f, {"threshold for occupancy in one time bin"}}, + {"adc-threshold", VariantType::Float, 0.f, {"threshold for adc value"}}, + {"min-timestamp", VariantType::Int64, 0LL, {"minimum time bin"}}, + {"filter-adc", VariantType::Bool, false, {"filter the data by the given adc threshold"}}, + {"filter-timestamp", VariantType::Bool, false, {"filter the data by the given minimum timestamp"}}, + } // end Options + }; // end DataProcessorSpec +} +} // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/tpc-occupancy-filter.cxx b/Detectors/TPC/workflow/src/tpc-occupancy-filter.cxx new file mode 100644 index 0000000000000..f71d0b837f783 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-occupancy-filter.cxx @@ -0,0 +1,220 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include +#include + +#include "Algorithm/RangeTokenizer.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "CommonUtils/ConfigurableParam.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsTPC/TPCSectorHeader.h" +#include "DataFormatsTPC/Digit.h" +#include "TPCBase/Sector.h" +#include "TPCWorkflow/OccupancyFilterSpec.h" +#include "TPCWorkflow/FileWriterSpec.h" +#include "TPCReaderWorkflow/TPCSectorCompletionPolicy.h" + +using namespace o2::framework; +using namespace o2::tpc; + +// Global variable used to transport data to the completion policy +std::vector gPolicyData; +unsigned long gTpcSectorMask = 0xFFFFFFFFF; + +// customize the completion policy +void customize(std::vector& policies) +{ + using o2::framework::CompletionPolicy; + // policies.push_back(CompletionPolicyHelpers::defineByName("tpc-krypton-raw-filter.*", CompletionPolicy::CompletionOp::Consume)); + // policies.push_back(CompletionPolicyHelpers::defineByName("file-writer", CompletionPolicy::CompletionOp::Consume)); + + // we customize the pipeline processors to consume data as it comes + // + // the custom completion policy for the tracker + policies.push_back(o2::tpc::TPCSectorCompletionPolicy("occupancy-file-writer", o2::tpc::TPCSectorCompletionPolicy::Config::RequireAll, &gPolicyData, &gTpcSectorMask)()); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + std::string sectorDefault = "0-" + std::to_string(o2::tpc::Sector::MAXSECTOR - 1); + int defaultlanes = std::max(1u, std::thread::hardware_concurrency() / 2); + + std::vector options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCCalibPedestal.FirstTimeBin=10;...')"}}, + {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, + {"outputFile", VariantType::String, "./occupancy-filtered-digits.root", {"output file name for the filtered krypton file"}}, + {"lanes", VariantType::Int, defaultlanes, {"Number of parallel processing lanes."}}, + {"sectors", VariantType::String, sectorDefault.c_str(), {"List of TPC sectors, comma separated ranges, e.g. 0-3,7,9-15"}}, + {"writer-type", VariantType::String, "local", {"Writer type (local, EPN, none)"}}, + {"ccdb-path", VariantType::String, "http://ccdb-test.cern.ch:8080", {"Path to CCDB"}}, + }; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +template +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; + +enum class WriterType { + Local, + EPN, + None, +}; + +const std::unordered_map WriterMap{ + {"local", WriterType::Local}, + {"EPN", WriterType::EPN}, + {"none", WriterType::None}, +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + + using namespace o2::tpc; + + // set up configuration + o2::conf::ConfigurableParam::updateFromFile(config.options().get("configFile")); + o2::conf::ConfigurableParam::updateFromString(config.options().get("configKeyValues")); + o2::conf::ConfigurableParam::writeINI("o2tpccalibration_configuration.ini"); + + const std::string outputFile = config.options().get("outputFile"); + + const auto tpcSectors = o2::RangeTokenizer::tokenize(config.options().get("sectors")); + const auto nSectors = (int)tpcSectors.size(); + const auto nLanes = std::min(config.options().get("lanes"), nSectors); + + WriterType writerType; + try { + writerType = WriterMap.at(config.options().get("writer-type")); + } catch (std::out_of_range&) { + throw std::invalid_argument(std::string("invalid writer-type type: ") + config.options().get("writer-type")); + } + + WorkflowSpec workflow; + + if (nLanes <= 0) { + return workflow; + } + + std::vector laneConfiguration = tpcSectors; // Currently just a copy of the tpcSectors, why? + + gTpcSectorMask = 0; + for (auto s : tpcSectors) { + gTpcSectorMask |= (1ul << s); + } + gPolicyData.emplace_back(o2::framework::InputSpec{"data", o2::framework::ConcreteDataTypeMatcher{"TPC", "FILTERDIG"}}); + + WorkflowSpec parallelProcessors; + parallelProcessors.emplace_back(getOccupancyFilterSpec()); + + parallelProcessors = parallelPipeline( + parallelProcessors, nLanes, + [&laneConfiguration]() { return laneConfiguration.size(); }, + [&laneConfiguration](size_t index) { return laneConfiguration[index]; }); + workflow.insert(workflow.end(), parallelProcessors.begin(), parallelProcessors.end()); + + if (writerType == WriterType::Local) { + ////////////////////////////////////////////////////////////////////////////////////////////// + // + // generation of processor specs for various types of outputs + // based on generic RootTreeWriter and MakeRootTreeWriterSpec generator + // + // ------------------------------------------------------------------------------------------- + // the callbacks for the RootTreeWriter + // + // The generic writer needs a way to associate incoming data with the individual branches for + // the TPC sectors. The sector number is transmitted as part of the sector header, the callback + // finds the corresponding index in the vector of configured sectors + auto getIndex = [tpcSectors](o2::framework::DataRef const& ref) { + auto const* tpcSectorHeader = o2::framework::DataRefUtils::getHeader(ref); + if (!tpcSectorHeader) { + throw std::runtime_error("TPC sector header missing in header stack"); + } + if (tpcSectorHeader->sector() < 0) { + // special data sets, don't write + return ~(size_t)0; + } + size_t index = 0; + for (auto const& sector : tpcSectors) { + if (sector == tpcSectorHeader->sector()) { + return index; + } + ++index; + } + throw std::runtime_error("sector " + std::to_string(tpcSectorHeader->sector()) + " not configured for writing"); + }; + auto getName = [tpcSectors](std::string base, size_t index) { + return base + "_" + std::to_string(tpcSectors.at(index)); + }; + + auto makeWriterSpec = [tpcSectors, laneConfiguration, getIndex, getName](const char* processName, + const char* defaultFileName, + const char* defaultTreeName, + auto&& databranch, + bool singleBranch = false) { + if (tpcSectors.size() == 0) { + throw std::invalid_argument(std::string("writer process configuration needs list of TPC sectors")); + } + + auto amendInput = [tpcSectors, laneConfiguration](InputSpec& input, size_t index) { + input.binding += std::to_string(laneConfiguration[index]); + DataSpecUtils::updateMatchingSubspec(input, laneConfiguration[index]); + }; + auto amendBranchDef = [laneConfiguration, amendInput, tpcSectors, getIndex, getName, singleBranch](auto&& def, bool enableMC = true) { + if (!singleBranch) { + def.keys = mergeInputs(def.keys, laneConfiguration.size(), amendInput); + // the branch is disabled if set to 0 + def.nofBranches = enableMC ? tpcSectors.size() : 0; + def.getIndex = getIndex; + def.getName = getName; + } else { + // instead of the separate sector branches only one is going to be written + def.nofBranches = enableMC ? 1 : 0; + } + return std::move(def); + }; + + return std::move(MakeRootTreeWriterSpec(processName, defaultFileName, defaultTreeName, + std::move(amendBranchDef(databranch)))()); + }; + + ////////////////////////////////////////////////////////////////////////////////////////////// + // + // a writer process for digits + // + // selected by output type 'difits' + using OutputType = std::vector; + workflow.push_back(makeWriterSpec("tpc-occupancy-writer", + outputFile.data(), + "o2sim", + BranchDefinition{InputSpec{"data", "TPC", "FILTERDIG", 0}, + "TPCDigit", + "digit-branch-name"})); + } else if (writerType == WriterType::EPN) { + workflow.push_back(getFileWriterSpec("data:TPC/FILTERDIG", BranchType::Digits)); + } + + return workflow; +} From 9b2b1ed6efe42c7d3d77d36de933d350444ed5c3 Mon Sep 17 00:00:00 2001 From: MichalTrzeb Date: Wed, 6 Sep 2023 10:41:08 +0200 Subject: [PATCH 019/324] Opening local files in navigateURLsAndLoadFileToMemory --- CCDB/src/CcdbApi.cxx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index 8b63fe455b5db..bef13d844a4a2 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -1586,6 +1586,14 @@ void CcdbApi::navigateURLsAndLoadFileToMemory(o2::pmr::vector& dest, CURL* if (url.find("alien:/", 0) != std::string::npos) { return loadFileToMemory(dest, url, nullptr); // headers loaded from the file in case of the snapshot reading only } + if ((url.find("file:/", 0) != std::string::npos)) { + std::string path = url.substr(7); + if (std::filesystem::exists(path)) { + return loadFileToMemory(dest, path, nullptr); + } else { + return; + } + } // otherwise make an HTTP/CURL request struct HeaderObjectPair_t { std::map header; From 377337d8fab7d674ccce514098c418fd45d5b8ed Mon Sep 17 00:00:00 2001 From: swenzel Date: Mon, 11 Sep 2023 12:55:45 +0200 Subject: [PATCH 020/324] Static_assert check for hit property space Need to check if data-layout compatible with number of detectors. Important in view of ALICE3 extensions etc. --- DataFormats/simulation/include/SimulationDataFormat/MCTrack.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h b/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h index a08a12327bc59..fd9b794e59d91 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h @@ -27,6 +27,7 @@ #include "TParticle.h" #include "TParticlePDG.h" #include "TVector3.h" +#include namespace o2 { @@ -261,6 +262,7 @@ class MCTrackT int storage : 1; // encoding whether to store this track to the output unsigned int process : 6; // encoding process that created this track (enough to store TMCProcess from ROOT) int hitmask : 22; // encoding hits per detector + static_assert(o2::detectors::DetID::nDetectors <= 22); // ensure that all known detectors can be encoded here by a bit int reserved1 : 1; // bit reserved for possible future purposes int inhibited : 1; // whether tracking of this was inhibited int toBeDone : 1; // whether this (still) needs tracking --> we might more complete information to cover full ParticleStatus space From f176408fc19503795d55df66cbef97c6d0c839de Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Sat, 9 Sep 2023 13:14:15 +0200 Subject: [PATCH 021/324] extend data model --- Framework/Core/include/Framework/AnalysisDataModel.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Framework/Core/include/Framework/AnalysisDataModel.h b/Framework/Core/include/Framework/AnalysisDataModel.h index 1c1871608391e..79f6a5e854a2c 100644 --- a/Framework/Core/include/Framework/AnalysisDataModel.h +++ b/Framework/Core/include/Framework/AnalysisDataModel.h @@ -1511,12 +1511,14 @@ DECLARE_SOA_COLUMN(Attempted, attempted, uint64_t); //! The number of events DECLARE_SOA_COLUMN(XsectGen, xsectGen, float); //! Cross section in pb DECLARE_SOA_COLUMN(XsectErr, xsectErr, float); //! Error associated with this cross section DECLARE_SOA_COLUMN(PtHard, ptHard, float); //! PT-hard (event scale, for pp collisions) +DECLARE_SOA_COLUMN(NMPI, nMPI, int); //! number of MPIs (for pp collisions) +DECLARE_SOA_COLUMN(ProcessId, processId, int); //! process id from MC generator } // namespace hepmcxsection DECLARE_SOA_TABLE(HepMCXSections, "AOD", "HEPMCXSECTION", //! HepMC table for cross sections o2::soa::Index<>, hepmcxsection::McCollisionId, hepmcxsection::GeneratorsID, hepmcxsection::Accepted, hepmcxsection::Attempted, hepmcxsection::XsectGen, - hepmcxsection::XsectErr, hepmcxsection::PtHard); + hepmcxsection::XsectErr, hepmcxsection::PtHard, hepmcxsection::NMPI, hepmcxsection::ProcessId); using HepMCXSection = HepMCXSections::iterator; namespace hepmcpdfinfo From e7f57c09ac2105a559f3050f211816cad6db4850 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Sat, 9 Sep 2023 13:15:16 +0200 Subject: [PATCH 022/324] o2sim: update * add extra HepMC info when publishing MCHeader * use extra HepMC info in MCHeader to produce AOD HepMC tables --- run/o2sim_hepmc_publisher.cxx | 49 ++++++++++++++++++++++++++++ run/o2sim_mctracks_to_aod.cxx | 60 +++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/run/o2sim_hepmc_publisher.cxx b/run/o2sim_hepmc_publisher.cxx index 22616b09dc45a..76fbddc1993f3 100644 --- a/run/o2sim_hepmc_publisher.cxx +++ b/run/o2sim_hepmc_publisher.cxx @@ -68,6 +68,55 @@ struct O2simHepmcPublisher { o2::dataformats::MCEventHeader mcHeader; mcHeader.SetEventID(event.event_number()); mcHeader.SetVertex(event.event_pos().px(), event.event_pos().py(), event.event_pos().pz()); + auto xsecInfo = event.cross_section(); + if (xsecInfo != nullptr) { + mcHeader.putInfo("Accepted", (uint64_t)xsecInfo->get_accepted_events()); + mcHeader.putInfo("Attempted", (uint64_t)xsecInfo->get_attempted_events()); + mcHeader.putInfo("XsectGen", (float)xsecInfo->xsec()); + mcHeader.putInfo("XsectErr", (float)xsecInfo->xsec_err()); + } + auto scale = event.attribute("event_scale"); + if (scale != nullptr) { + mcHeader.putInfo("PtHard", (float)scale->value()); + } + auto nMPI = event.attribute("mpi"); + if (nMPI != nullptr) { + mcHeader.putInfo("MPI", nMPI->value()); + } + auto sid = event.attribute("signal_process_id"); + if (sid != nullptr) { + mcHeader.putInfo("ProcessId", sid->value()); + } + auto pdfInfo = event.pdf_info(); + if (pdfInfo != nullptr) { + mcHeader.putInfo("Id1", pdfInfo->parton_id[0]); + mcHeader.putInfo("Id2", pdfInfo->parton_id[1]); + mcHeader.putInfo("PdfId1", pdfInfo->pdf_id[0]); + mcHeader.putInfo("PdfId2", pdfInfo->pdf_id[1]); + mcHeader.putInfo("X1", (float)pdfInfo->x[0]); + mcHeader.putInfo("X2", (float)pdfInfo->x[1]); + mcHeader.putInfo("scale", (float)pdfInfo->scale); + mcHeader.putInfo("Pdf1", (float)pdfInfo->xf[0]); + mcHeader.putInfo("Pdf2", (float)pdfInfo->xf[1]); + } + auto heavyIon = event.heavy_ion(); + if (heavyIon != nullptr) { + mcHeader.putInfo("NcollHard", heavyIon->Ncoll_hard); + mcHeader.putInfo("NpartProj", heavyIon->Npart_proj); + mcHeader.putInfo("NpartTarg", heavyIon->Npart_targ); + mcHeader.putInfo("Ncoll", heavyIon->Ncoll); + mcHeader.putInfo("NNwoundedCollisions", heavyIon->N_Nwounded_collisions); + mcHeader.putInfo("NwoundedNCollisions", heavyIon->Nwounded_N_collisions); + mcHeader.putInfo("NwoundedNwoundedCollisions", heavyIon->Nwounded_Nwounded_collisions); + mcHeader.putInfo("SpectatorNeutrons", heavyIon->spectator_neutrons); + mcHeader.putInfo("SpectatorProtons", heavyIon->spectator_protons); + mcHeader.putInfo("ImpactParameter", (float)heavyIon->impact_parameter); + mcHeader.putInfo("EventPlaneAngle", (float)heavyIon->event_plane_angle); + mcHeader.putInfo("Eccentricity", (float)heavyIon->eccentricity); + mcHeader.putInfo("SigmaInelNN", (float)heavyIon->sigma_inel_NN); + mcHeader.putInfo("Centrality", (float)heavyIon->centrality); + } + auto particles = event.particles(); for (auto const& particle : particles) { auto parents = particle->parents(); diff --git a/run/o2sim_mctracks_to_aod.cxx b/run/o2sim_mctracks_to_aod.cxx index 092572e630ad3..316fbd9e31323 100644 --- a/run/o2sim_mctracks_to_aod.cxx +++ b/run/o2sim_mctracks_to_aod.cxx @@ -22,6 +22,12 @@ using namespace o2::framework; struct MctracksToAod { Produces mcollisions; Produces mcparticles; + + // optional extra info from HepMC (if found in header) + Produces hepmcxsections; + Produces hepmcpdfinfos; + Produces hepmcheavyions; + Configurable IR{"interaction-rate", 100.f, "Interaction rate to simulate"}; uint64_t timeframe = 0; @@ -57,6 +63,60 @@ struct MctracksToAod { record.timeInBCNS * 1.e-3, // ns to ms 1., // weight mcheader->GetB()); + bool valid; + if (mcheader->hasInfo("Accepted")) { + auto ptHard = mcheader->hasInfo("PtHard") ? mcheader->getInfo("PtHard", valid) : 0.f; + auto nMPI = mcheader->hasInfo("MPI") ? mcheader->getInfo("MPI", valid) : -1; + auto processId = mcheader->hasInfo("ProcessId") ? mcheader->getInfo("ProcessId", valid) : -1; + hepmcxsections( + mcollisions.lastIndex(), + 0, + mcheader->getInfo("Accepted", valid), + mcheader->getInfo("Attempted", valid), + mcheader->getInfo("XsectGen", valid), + mcheader->getInfo("XsectErr", valid), + ptHard, + nMPI, + processId + ); + } + if (mcheader->hasInfo("Id1")) { + hepmcpdfinfos( + mcollisions.lastIndex(), + 0, + mcheader->getInfo("Id1", valid), + mcheader->getInfo("Id2", valid), + mcheader->getInfo("PdfId1", valid), + mcheader->getInfo("PdfId2", valid), + mcheader->getInfo("X1", valid), + mcheader->getInfo("X2", valid), + mcheader->getInfo("scale", valid), + mcheader->getInfo("Pdf1", valid), + mcheader->getInfo("Pdf2", valid) + ); + } + if (mcheader->hasInfo("NcollHard")) { + hepmcheavyions( + mcollisions.lastIndex(), + 0, + mcheader->getInfo("NcollHard", valid), + mcheader->getInfo("NpartProj", valid), + mcheader->getInfo("NpartTarg", valid), + mcheader->getInfo("Ncoll", valid), + mcheader->getInfo("NNwoundedCollisions", valid), + mcheader->getInfo("NwoundedNCollisions", valid), + mcheader->getInfo("NwoundedNwoundedCollisions", valid), + mcheader->getInfo("SpectatorNeutrons", valid), + mcheader->getInfo("SpectatorProtons", valid), + mcheader->getInfo("ImpactParameter", valid), + mcheader->getInfo("EventPlaneAngle", valid), + mcheader->getInfo("Eccentricity", valid), + mcheader->getInfo("SigmaInelNN", valid), + mcheader->getInfo("Centrality", valid) + ); + } + + for (auto& mctrack : mctracks) { std::vector mothers; int daughters[2]; From 381af6a8bf25164e1943c56d470b4ac68bac7714 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Sat, 9 Sep 2023 11:20:11 +0000 Subject: [PATCH 023/324] Please consider the following formatting changes --- run/o2sim_mctracks_to_aod.cxx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/run/o2sim_mctracks_to_aod.cxx b/run/o2sim_mctracks_to_aod.cxx index 316fbd9e31323..e5460e346c3f9 100644 --- a/run/o2sim_mctracks_to_aod.cxx +++ b/run/o2sim_mctracks_to_aod.cxx @@ -65,7 +65,7 @@ struct MctracksToAod { mcheader->GetB()); bool valid; if (mcheader->hasInfo("Accepted")) { - auto ptHard = mcheader->hasInfo("PtHard") ? mcheader->getInfo("PtHard", valid) : 0.f; + auto ptHard = mcheader->hasInfo("PtHard") ? mcheader->getInfo("PtHard", valid) : 0.f; auto nMPI = mcheader->hasInfo("MPI") ? mcheader->getInfo("MPI", valid) : -1; auto processId = mcheader->hasInfo("ProcessId") ? mcheader->getInfo("ProcessId", valid) : -1; hepmcxsections( @@ -77,8 +77,7 @@ struct MctracksToAod { mcheader->getInfo("XsectErr", valid), ptHard, nMPI, - processId - ); + processId); } if (mcheader->hasInfo("Id1")) { hepmcpdfinfos( @@ -92,8 +91,7 @@ struct MctracksToAod { mcheader->getInfo("X2", valid), mcheader->getInfo("scale", valid), mcheader->getInfo("Pdf1", valid), - mcheader->getInfo("Pdf2", valid) - ); + mcheader->getInfo("Pdf2", valid)); } if (mcheader->hasInfo("NcollHard")) { hepmcheavyions( @@ -112,11 +110,9 @@ struct MctracksToAod { mcheader->getInfo("EventPlaneAngle", valid), mcheader->getInfo("Eccentricity", valid), mcheader->getInfo("SigmaInelNN", valid), - mcheader->getInfo("Centrality", valid) - ); + mcheader->getInfo("Centrality", valid)); } - for (auto& mctrack : mctracks) { std::vector mothers; int daughters[2]; From af9681187b6964fdbe5eb837794109ba37f05165 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 11 Sep 2023 21:09:09 +0200 Subject: [PATCH 024/324] Revert "DPL Analysis: provide metadata to workflow construction (#11875)" (#11885) This reverts commit eb6627554b3a5f7c249a057c48f1e480e8715b4d. --- .../src/AODJAlienReaderHelpers.cxx | 4 +- Framework/Core/CMakeLists.txt | 1 - .../include/Framework/ConfigParamDiscovery.h | 34 --------- .../include/Framework/runDataProcessing.h | 3 - Framework/Core/src/ConfigParamDiscovery.cxx | 71 ------------------- .../Core/src/WorkflowCustomizationHelpers.cxx | 4 -- Framework/Core/src/WorkflowHelpers.cxx | 2 +- .../TestWorkflows/src/o2AnalysisWorkflow.cxx | 13 +--- 8 files changed, 6 insertions(+), 126 deletions(-) delete mode 100644 Framework/Core/include/Framework/ConfigParamDiscovery.h delete mode 100644 Framework/Core/src/ConfigParamDiscovery.cxx diff --git a/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx b/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx index 9cd7d5affc379..1e20f46c2e464 100644 --- a/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx @@ -133,12 +133,12 @@ AlgorithmSpec AODJAlienReaderHelpers::rootFileReaderCallback() stats.updateStats({static_cast(ProcessingStatsId::ARROW_MESSAGES_DESTROYED), DataProcessingStats::Op::Set, 0}); stats.updateStats({static_cast(ProcessingStatsId::ARROW_BYTES_EXPIRED), DataProcessingStats::Op::Set, 0}); - if (!options.isSet("aod-file-private")) { + if (!options.isSet("aod-file")) { LOGP(fatal, "No input file defined!"); throw std::runtime_error("Processing is stopped!"); } - auto filename = options.get("aod-file-private"); + auto filename = options.get("aod-file"); std::string parentFileReplacement; if (options.isSet("aod-parent-base-path-replacement")) { diff --git a/Framework/Core/CMakeLists.txt b/Framework/Core/CMakeLists.txt index f71744f33f77e..eabc3f7c30593 100644 --- a/Framework/Core/CMakeLists.txt +++ b/Framework/Core/CMakeLists.txt @@ -45,7 +45,6 @@ o2_add_library(Framework src/DefaultsHelpers.cxx src/DomainInfoHeader.cxx src/ProcessingPoliciesHelpers.cxx - src/ConfigParamDiscovery.cxx src/ConfigParamStore.cxx src/ConfigParamsHelper.cxx src/ChannelParamSpec.cxx diff --git a/Framework/Core/include/Framework/ConfigParamDiscovery.h b/Framework/Core/include/Framework/ConfigParamDiscovery.h deleted file mode 100644 index c4bdb497366b7..0000000000000 --- a/Framework/Core/include/Framework/ConfigParamDiscovery.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_FRAMEWORK_CONFIGPARAMDISCOVERY_H_ -#define O2_FRAMEWORK_CONFIGPARAMDISCOVERY_H_ - -#include "Framework/ConfigParamRegistry.h" - -namespace o2::framework -{ -struct ConfigParamDiscovery { - /// Given a ConfigParamRegistry, discovers all the extrac ConfigParam - /// which require an additional lookup starting from the ones already - /// present. E.g. you could use this to populate the registry with - /// ConfigParams defined in a file. - static void discover(ConfigParamRegistry& registry); -}; - -/// A plugin which is able to discover more option then the ones -/// provided on the command line. -struct ConfigDiscoveryPlugin { - virtual void discover(ConfigParamRegistry& registry) = 0; -}; - -} // namespace o2::framework -#endif // O2_FRAMEWORK_CONFIGPARAMDISCOVERY_H_ diff --git a/Framework/Core/include/Framework/runDataProcessing.h b/Framework/Core/include/Framework/runDataProcessing.h index 2112dc7cbfd5d..bfda47d07971c 100644 --- a/Framework/Core/include/Framework/runDataProcessing.h +++ b/Framework/Core/include/Framework/runDataProcessing.h @@ -30,7 +30,6 @@ #include "Framework/Logger.h" #include "Framework/CheckTypes.h" #include "Framework/StructToTuple.h" -#include "Framework/ConfigParamDiscovery.h" #include #include @@ -204,8 +203,6 @@ int mainNoCatch(int argc, char** argv) workflowOptionsStore->preload(); workflowOptionsStore->activate(); ConfigParamRegistry workflowOptionsRegistry(std::move(workflowOptionsStore)); - ConfigParamDiscovery::discover(workflowOptionsRegistry); - ConfigContext configContext(workflowOptionsRegistry, argc, argv); o2::framework::WorkflowSpec specs = defineDataProcessing(configContext); overrideCloning(configContext, specs); diff --git a/Framework/Core/src/ConfigParamDiscovery.cxx b/Framework/Core/src/ConfigParamDiscovery.cxx deleted file mode 100644 index e392bf155d457..0000000000000 --- a/Framework/Core/src/ConfigParamDiscovery.cxx +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Framework/ConfigParamDiscovery.h" -#include "Framework/Plugins.h" -#include -#include -#include - -namespace o2::framework -{ - -void ConfigParamDiscovery::discover(ConfigParamRegistry& registry) -{ - // Keep track of the plugins - std::vector plugins; - if (registry.hasOption("aod-file") && registry.isSet("aod-file")) { - auto filename = registry.get("aod-file"); - if (filename.empty()) { - return; - } - TFile* currentFile = nullptr; - if (filename.at(0) == '@') { - filename.erase(0, 1); - // read the text file and set filename to the contents of the first line - std::ifstream file(filename); - if (!file.is_open()) { - LOGP(fatal, "Couldn't open file \"{}\"!", filename); - } - std::getline(file, filename); - file.close(); - currentFile = TFile::Open(filename.c_str()); - } else { - currentFile = TFile::Open(filename.c_str()); - } - if (!currentFile) { - LOGP(fatal, "Couldn't open file \"{}\"!", filename); - } - - // Get the metadata, if any - auto m = (TMap*)currentFile->Get("metaData"); - if (!m) { - LOGP(warning, "No metadata found in file \"{}\"", filename); - return; - } - auto it = m->MakeIterator(); - - // Serialise metadata into a ; separated string with : separating key and value - bool first = true; - while (auto obj = it->Next()) { - if (first) { - LOGP(info, "Metadata for file \"{}\":", filename); - first = false; - } - auto objString = (TObjString*)m->GetValue(obj); - LOGP(info, "- {}: {}", obj->GetName(), objString->String()); - std::string key = "aod-metadata-" + std::string(obj->GetName()); - registry.override(key.c_str(), objString->String()); - } - } -} - -} // namespace o2::framework diff --git a/Framework/Core/src/WorkflowCustomizationHelpers.cxx b/Framework/Core/src/WorkflowCustomizationHelpers.cxx index efdc535c683c5..da21168a8fe44 100644 --- a/Framework/Core/src/WorkflowCustomizationHelpers.cxx +++ b/Framework/Core/src/WorkflowCustomizationHelpers.cxx @@ -54,10 +54,6 @@ std::vector WorkflowCustomizationHelpers::requiredWorkflowOptio // options for AOD rate limiting {"aod-memory-rate-limit", VariantType::Int64, 0LL, {"Rate limit AOD processing based on memory"}}, - // options for the AOD reader - // aod-file needs to be available as workflow option, because we - // can configure the workflow based on the contents of the first file. - {"aod-file", VariantType::String, "", {"Input AOD file"}}, // options for AOD writer {"aod-writer-json", VariantType::String, "", {"Name of the json configuration file"}}, {"aod-writer-resdir", VariantType::String, "", {"Name of the output directory"}}, diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index c2049dedcfc8f..ce56385f71dd4 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -297,7 +297,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext static_cast(compile_time_hash("internal-dpl-aod-reader")), aodLifetime}}, .algorithm = AlgorithmSpec::dummyAlgorithm(), - .options = {ConfigParamSpec{"aod-file-private", VariantType::String, ctx.options().get("aod-file"), {"AOD file"}}, + .options = {ConfigParamSpec{"aod-file", VariantType::String, {"Input AOD file"}}, ConfigParamSpec{"aod-reader-json", VariantType::String, {"json configuration file"}}, ConfigParamSpec{"aod-parent-access-level", VariantType::String, {"Allow parent file access up to specified level. Default: no (0)"}}, ConfigParamSpec{"aod-parent-base-path-replacement", VariantType::String, {R"(Replace base path of parent files. Syntax: FROM;TO. E.g. "alien:///path/in/alien;/local/path". Enclose in "" on the command line.)"}}, diff --git a/Framework/TestWorkflows/src/o2AnalysisWorkflow.cxx b/Framework/TestWorkflows/src/o2AnalysisWorkflow.cxx index b1c6da0775b2e..c0da7a24c1a90 100644 --- a/Framework/TestWorkflows/src/o2AnalysisWorkflow.cxx +++ b/Framework/TestWorkflows/src/o2AnalysisWorkflow.cxx @@ -49,14 +49,7 @@ struct EtaAndClsHistograms { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - // For the sake of running without an option, we do not throw an exception - // in case the option is not present. - if (cfgc.options().hasOption("aod-metadata-Run") == false || - cfgc.options().get("aod-metadata-Run") == "2") { - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - }; - } else { - throw std::runtime_error("Unsupported run type"); - } + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; } From d9d2000b7daf9b10119e5d288a632932998fc83e Mon Sep 17 00:00:00 2001 From: wiechula Date: Mon, 11 Sep 2023 13:54:58 +0200 Subject: [PATCH 025/324] Fix drift velocity calculation, add proper t0 value --- Detectors/TPC/base/src/Painter.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Detectors/TPC/base/src/Painter.cxx b/Detectors/TPC/base/src/Painter.cxx index c85ad0164a0fc..7339a11e4c8e0 100644 --- a/Detectors/TPC/base/src/Painter.cxx +++ b/Detectors/TPC/base/src/Painter.cxx @@ -1134,9 +1134,11 @@ std::vector painter::makeSummaryCanvases(const LtrCalibData& ltr, std: calibValMsg->AddText(fmt::format("dvCorrectionA: {}", ltr.dvCorrectionA).data()); calibValMsg->AddText(fmt::format("dvCorrectionC: {}", ltr.dvCorrectionC).data()); calibValMsg->AddText(fmt::format("dvCorrection: {}", ltr.getDriftVCorrection()).data()); - calibValMsg->AddText(fmt::format("dvAbsolute: {}", ltr.getDriftVCorrection() * ltr.refVDrift).data()); + calibValMsg->AddText(fmt::format("dvAbsolute: {}", ltr.refVDrift / ltr.getDriftVCorrection()).data()); calibValMsg->AddText(fmt::format("dvOffsetA: {}", ltr.dvOffsetA).data()); calibValMsg->AddText(fmt::format("dvOffsetC: {}", ltr.dvOffsetC).data()); + calibValMsg->AddText(fmt::format("t0A: {}", ltr.getT0A()).data()); + calibValMsg->AddText(fmt::format("t0C: {}", ltr.getT0C()).data()); calibValMsg->AddText(fmt::format("nTracksA: {}", ltr.nTracksA).data()); calibValMsg->AddText(fmt::format("nTracksC: {}", ltr.nTracksC).data()); calibValMsg->AddText(fmt::format("#LTdEdx A#GT: {}", dEdxSumA).data()); From 7258b1a8f05984dc19853f76f4f28d707aa026d7 Mon Sep 17 00:00:00 2001 From: shahoian Date: Mon, 11 Sep 2023 14:49:05 +0200 Subject: [PATCH 026/324] Fix for multiple URLs support in CcbApi::loadToMemory --- CCDB/src/CcdbApi.cxx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index bef13d844a4a2..0ae9099040c05 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -562,6 +562,7 @@ size_t header_map_callback(char* buffer, size_t size, size_t nitems, void* userd if (index != std::string::npos) { const auto key = boost::algorithm::trim_copy(header.substr(0, index)); const auto value = boost::algorithm::trim_copy(header.substr(index + 1)); + LOGP(debug, "Adding #{} {} -> {}", headers->size(), key, value); headers->insert(std::make_pair(key, value)); } return size * nitems; @@ -1539,12 +1540,10 @@ void CcdbApi::loadFileToMemory(o2::pmr::vector& dest, std::string const& p curl_slist* options_list = nullptr; initCurlHTTPHeaderOptionsForRetrieve(curl_handle, options_list, timestamp, headers, etag, createdNotAfter, createdNotBefore); - navigateURLsAndLoadFileToMemory(dest, curl_handle, fullUrl, headers); - for (size_t hostIndex = 1; hostIndex < hostsPool.size() && isMemoryFileInvalid(dest); hostIndex++) { fullUrl = getFullUrlForRetrieval(curl_handle, path, metadata, timestamp, hostIndex); - loadFileToMemory(dest, fullUrl, headers); // headers loaded from the file in case of the snapshot reading only + navigateURLsAndLoadFileToMemory(dest, curl_handle, fullUrl, headers); // headers loaded from the file in case of the snapshot reading only } curl_slist_free_all(options_list); curl_easy_cleanup(curl_handle); @@ -1596,7 +1595,7 @@ void CcdbApi::navigateURLsAndLoadFileToMemory(o2::pmr::vector& dest, CURL* } // otherwise make an HTTP/CURL request struct HeaderObjectPair_t { - std::map header; + std::multimap header; o2::pmr::vector* object = nullptr; int counter = 0; } hoPair{{}, &dest, 0}; From 640d52b6bb515947ef065f78976b83e24fc035c2 Mon Sep 17 00:00:00 2001 From: iravasen Date: Tue, 12 Sep 2023 02:28:20 +0200 Subject: [PATCH 027/324] ITS calib: number of points of the s-curve to ROOT trees (#11883) * added number of points of the s-curve to ROOT trees * removed useless log --- .../ITSWorkflow/ThresholdCalibratorSpec.h | 7 ++++--- .../workflow/src/ThresholdCalibratorSpec.cxx | 21 +++++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h index 46703c8ae0e91..bd08859a0fe3a 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h @@ -165,6 +165,7 @@ class ITSThresholdCalibrator : public Task short int vThreshold[N_COL]; bool vSuccess[N_COL]; unsigned char vNoise[N_COL]; + unsigned char vPoints[N_COL]; short int vMixData[N_COL]; unsigned char vCharge[N_COL]; float vSlope[N_COL]; @@ -187,9 +188,9 @@ class ITSThresholdCalibrator : public Task // Helper functions related to threshold extraction void initThresholdTree(bool recreate = true); bool findUpperLower(std::vector>, const short int&, short int&, short int&, bool, int); - bool findThreshold(const short int&, std::vector>, const float*, short int&, float&, float&, int); - bool findThresholdFit(const short int&, std::vector>, const float*, const short int&, float&, float&, int); - bool findThresholdDerivative(std::vector>, const float*, const short int&, float&, float&, int); + bool findThreshold(const short int&, std::vector>, const float*, short int&, float&, float&, int&, int); + bool findThresholdFit(const short int&, std::vector>, const float*, const short int&, float&, float&, int&, int); + bool findThresholdDerivative(std::vector>, const float*, const short int&, float&, float&, int&, int); bool findThresholdHitcounting(std::vector>, const float*, const short int&, float&, int); bool isScanFinished(const short int&, const short int&, const short int&); void findAverage(const std::array&, float&, float&, float&, float&); diff --git a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx index cac93a30e6e86..466c892350162 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx @@ -358,6 +358,7 @@ void ITSThresholdCalibrator::initThresholdTree(bool recreate /*=true*/) if (this->mScanType == 'T') { this->mThresholdTree->Branch("thr", &vThreshold, "vThreshold[1024]/S"); this->mThresholdTree->Branch("noise", &vNoise, "vNoise[1024]/b"); + this->mThresholdTree->Branch("spoints", &vPoints, "vPoints[1024]/b"); this->mThresholdTree->Branch("success", &vSuccess, "vSuccess[1024]/O"); } else if (mScanType == 'D' || mScanType == 'A') { // this->mScanType == 'D' and this->mScanType == 'A' this->mThresholdTree->Branch("n_hits", &vThreshold, "vThreshold[1024]/S"); @@ -380,6 +381,7 @@ void ITSThresholdCalibrator::initThresholdTree(bool recreate /*=true*/) this->mThresholdTree->Branch("vresetd", &vMixData, "vMixData[1024]/S"); } else if (mScanType == 'r') { this->mThresholdTree->Branch("thr", &vThreshold, "vThreshold[1024]/S"); + this->mThresholdTree->Branch("noise", &vNoise, "vNoise[1024]/b"); this->mThresholdTree->Branch("success", &vSuccess, "vSuccess[1024]/O"); this->mThresholdTree->Branch("vresetd", &vMixData, "vMixData[1024]/S"); } @@ -454,17 +456,17 @@ bool ITSThresholdCalibrator::findUpperLower( // Main findThreshold function which calls one of the three methods bool ITSThresholdCalibrator::findThreshold( const short int& chipID, std::vector> data, const float* x, short int& NPoints, - float& thresh, float& noise, int iloop2) + float& thresh, float& noise, int& spoints, int iloop2) { bool success = false; switch (this->mFitType) { case DERIVATIVE: // Derivative method - success = this->findThresholdDerivative(data, x, NPoints, thresh, noise, iloop2); + success = this->findThresholdDerivative(data, x, NPoints, thresh, noise, spoints, iloop2); break; case FIT: // Fit method - success = this->findThresholdFit(chipID, data, x, NPoints, thresh, noise, iloop2); + success = this->findThresholdFit(chipID, data, x, NPoints, thresh, noise, spoints, iloop2); break; case HITCOUNTING: // Hit-counting method @@ -482,10 +484,11 @@ bool ITSThresholdCalibrator::findThreshold( // x is the array of charge injected values; // NPoints is the length of both arrays. // thresh, noise, chi2 pointers are updated with results from the fit +// spoints: number of points in the S of the S-curve (with n_hits between 0 and 50, excluding first and last point) // iloop2 is 0 for thr scan but is equal to vresetd index in 2D vresetd scan bool ITSThresholdCalibrator::findThresholdFit( const short int& chipID, std::vector> data, const float* x, const short int& NPoints, - float& thresh, float& noise, int iloop2) + float& thresh, float& noise, int& spoints, int iloop2) { // Find lower & upper values of the S-curve region short int lower, upper; @@ -540,6 +543,7 @@ bool ITSThresholdCalibrator::findThresholdFit( noise = this->mFitFunction->GetParameter(1); thresh = this->mFitFunction->GetParameter(0); float chi2 = this->mFitFunction->GetChisquare() / this->mFitFunction->GetNDF(); + spoints = upper - lower - 1; // Clean up histogram for next time it is used this->mFitHist->Reset(); @@ -552,9 +556,10 @@ bool ITSThresholdCalibrator::findThresholdFit( // data is the number of trigger counts per charge injected; // x is the array of charge injected values; // NPoints is the length of both arrays. +// spoints: number of points in the S of the S-curve (with n_hits between 0 and 50, excluding first and last point) // iloop2 is 0 for thr scan but is equal to vresetd index in 2D vresetd scan bool ITSThresholdCalibrator::findThresholdDerivative(std::vector> data, const float* x, const short int& NPoints, - float& thresh, float& noise, int iloop2) + float& thresh, float& noise, int& spoints, int iloop2) { // Find lower & upper values of the S-curve region short int lower, upper; @@ -587,6 +592,7 @@ bool ITSThresholdCalibrator::findThresholdDerivative(std::vector 0.; } @@ -731,18 +737,21 @@ void ITSThresholdCalibrator::extractThresholdRow(const short int& chipID, const // Do the threshold fit float thresh = 0., noise = 0.; bool success = false; + int spoints = 0; if (isDumpS) { // already protected for multi-thread in the init mFitHist->SetName(Form("scurve_chip%d_row%d_col%d_scani%d", chipID, row, col_i, scan_i)); } success = this->findThreshold(chipID, mPixelHits[chipID][row][col_i], - this->mX, mScanType == 'r' ? N_RANGE2 : N_RANGE, thresh, noise, scan_i); + this->mX, mScanType == 'r' ? N_RANGE2 : N_RANGE, thresh, noise, spoints, scan_i); vChipid[col_i] = chipID; vRow[col_i] = row; vThreshold[col_i] = (mScanType == 'T' || mScanType == 'r') ? (short int)(thresh * 10.) : (short int)(thresh); vNoise[col_i] = (unsigned char)(noise * 10.); // always factor 10 also for ITHR/VCASN to not have all zeros vSuccess[col_i] = success; + vPoints[col_i] = spoints > 0 ? (unsigned char)(spoints) : 0; + if (mScanType == 'r') { vMixData[col_i] = (scan_i * this->mStep) + mMin; } From d4d082db5b7ee95d17c7865b290d9ff20fc900bd Mon Sep 17 00:00:00 2001 From: Ruben Shahoyan Date: Tue, 12 Sep 2023 10:18:58 +0200 Subject: [PATCH 028/324] optionally ensure RDH with SOX in o2-raw-data-dump-workflow (#11878) --- Detectors/Raw/src/RawDumpSpec.cxx | 142 +++++++++++++++++++++++----- Detectors/Raw/src/RawFileReader.cxx | 2 +- 2 files changed, 121 insertions(+), 23 deletions(-) diff --git a/Detectors/Raw/src/RawDumpSpec.cxx b/Detectors/Raw/src/RawDumpSpec.cxx index c85f3bd4d272c..c58c7e8365624 100644 --- a/Detectors/Raw/src/RawDumpSpec.cxx +++ b/Detectors/Raw/src/RawDumpSpec.cxx @@ -17,6 +17,7 @@ #include "DetectorsRaw/RDHUtils.h" #include "DPLUtils/DPLRawParser.h" #include "CommonUtils/StringUtils.h" +#include "CommonConstants/Triggers.h" #include "Algorithm/RangeTokenizer.h" #include #include @@ -34,6 +35,14 @@ class RawDump : public Task public: static constexpr o2h::DataDescription DESCRaw{"RAWDATA"}, DESCCRaw{"CRAWDATA"}; + struct LinkInfo { + FILE* fileHandler = nullptr; + o2::header::RDHAny rdhSOX; + o2::InteractionRecord firstIR{}; + bool hasSOX{false}; + DetID detID{}; + }; + RawDump(bool TOFUncompressed = false); void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -41,7 +50,7 @@ class RawDump : public Task static std::string getReadoutType(DetID id); private: - FILE* getFile(o2h::DataOrigin detOr, const header::RDHAny* rdh); + LinkInfo& getLinkInfo(o2h::DataOrigin detOr, const header::RDHAny* rdh); std::string getFileName(DetID detID, const header::RDHAny* rdh); std::string getBaseFileNameITS(const header::RDHAny* rdh); std::string getBaseFileNameTPC(const header::RDHAny* rdh); @@ -63,10 +72,13 @@ class RawDump : public Task bool mFatalOnDeadBeef{false}; bool mSkipDump{false}; bool mTOFUncompressed{false}; + bool mImposeSOX{false}; int mVerbosity{0}; + int mTFCount{0}; uint64_t mTPCLinkRej{0}; // pattern of TPC links to reject + o2::InteractionRecord mFirstIR{}; std::string mOutDir{}; - std::unordered_map mDetFEEID2File{}; + std::unordered_map mLinksInfo{}; std::unordered_map mName2File{}; std::unordered_map mOrigin2DetID{}; std::array mConfigEntries{}; @@ -88,6 +100,7 @@ void RawDump::init(InitContext& ic) mVerbosity = ic.options().get("dump-verbosity"); mOutDir = ic.options().get("output-directory"); mSkipDump = ic.options().get("skip-dump"); + mImposeSOX = !ic.options().get("skip-impose-sox"); auto vrej = o2::RangeTokenizer::tokenize(ic.options().get("reject-tpc-links")); for (auto i : vrej) { if (i < 63) { @@ -125,21 +138,84 @@ void RawDump::run(ProcessingContext& pc) { DPLRawParser parser(pc.inputs()); - static DetID::mask_t repDeadBeef{}; - for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { - auto const* raw = it.raw(); - auto const* dh = it.o2DataHeader(); + auto procDEADBEEF = [this](const o2::header::DataHeader* dh) { + static DetID::mask_t repDeadBeef{}; if (dh->subSpecification == 0xdeadbeef && dh->payloadSize == 0) { - if (mFatalOnDeadBeef) { + if (this->mFatalOnDeadBeef) { LOGP(fatal, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{}", dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit); } else { - if (!repDeadBeef[DetID(dh->dataOrigin.str)] || mVerbosity > 0) { + if (!repDeadBeef[DetID(dh->dataOrigin.str)] || this->mVerbosity > 0) { LOGP(warn, "Skipping input [{}/{}/{:#x}] TF#{} 1st_orbit:{}", dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit); repDeadBeef |= DetID::getMask(dh->dataOrigin.str); } + return false; + } + } + return true; + }; + + auto isRORC = [](DetID id) { + return id == DetID::PHS || id == DetID::EMC || id == DetID::HMP; + }; + + if (mTFCount == 0 && mImposeSOX) { // make sure all links payload starts with SOX + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + auto const* dh = it.o2DataHeader(); + if (!procDEADBEEF(dh)) { + continue; + } + const auto rdh = reinterpret_cast(it.raw()); + if (!RDHUtils::checkRDH(rdh, true)) { + o2::raw::RDHUtils::printRDH(rdh); + continue; + } + auto& lInfo = getLinkInfo(dh->dataOrigin, rdh); + if (!lInfo.firstIR.isDummy()) { // already processed continue; } + lInfo.firstIR = {0, o2::raw::RDHUtils::getTriggerOrbit(rdh)}; + if (lInfo.firstIR < mFirstIR) { + mFirstIR = lInfo.firstIR; + } + auto trig = o2::raw::RDHUtils::getTriggerType(rdh); + lInfo.hasSOX = trig & (o2::trigger::SOT | o2::trigger::SOC); + lInfo.rdhSOX = *rdh; + lInfo.detID = mOrigin2DetID[dh->dataOrigin]; + } + // now write RDH with SOX (if needed) + for (auto& lit : mLinksInfo) { + auto& lInfo = lit.second; + if (!lInfo.hasSOX && lInfo.fileHandler) { + auto trig = o2::raw::RDHUtils::getTriggerType(lInfo.rdhSOX); + if (o2::raw::RDHUtils::getTriggerIR(lInfo.rdhSOX) != mFirstIR) { // need to write cooked header + o2::raw::RDHUtils::setTriggerOrbit(lInfo.rdhSOX, mFirstIR.orbit); + o2::raw::RDHUtils::setOffsetToNext(lInfo.rdhSOX, sizeof(o2::header::RDHAny)); + o2::raw::RDHUtils::setMemorySize(lInfo.rdhSOX, sizeof(o2::header::RDHAny)); + trig = isRORC(lInfo.detID) ? o2::trigger::SOT : (o2::trigger::SOC | o2::trigger::ORBIT | o2::trigger::HB | o2::trigger::TF); + o2::raw::RDHUtils::setTriggerType(lInfo.rdhSOX, trig); + o2::raw::RDHUtils::setStop(lInfo.rdhSOX, 0x1); + if (mVerbosity > 0) { + LOGP(info, "Writing cooked up RDH with SOX"); + o2::raw::RDHUtils::printRDH(lInfo.rdhSOX); + } + auto ws = std::fwrite(&lInfo.rdhSOX, 1, sizeof(o2::header::RDHAny), lInfo.fileHandler); + if (ws != sizeof(o2::header::RDHAny)) { + LOGP(fatal, "Failed to write cooked up RDH with SOX"); + } + lInfo.hasSOX = true; // flag that it is already written + } // otherwhise data has RDH with orbit matching to SOX, we will simply set a flag while writing the data + } else if (lInfo.fileHandler && o2::raw::RDHUtils::getTriggerOrbit(lInfo.rdhSOX) != mFirstIR.orbit) { + o2::raw::RDHUtils::printRDH(lInfo.rdhSOX); + LOGP(error, "Original data had SOX set but the orbit differs from the smallest seen {}, keep original one", mFirstIR.orbit); + } + } + } + + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + auto const* dh = it.o2DataHeader(); + if (!procDEADBEEF(dh)) { + continue; } const auto rdh = reinterpret_cast(it.raw()); if (!RDHUtils::checkRDH(rdh, true)) { @@ -150,14 +226,36 @@ void RawDump::run(ProcessingContext& pc) o2::raw::RDHUtils::printRDH(rdh); } FILE* fh = nullptr; - if (!mSkipDump && (fh = getFile(dh->dataOrigin, rdh))) { + auto& lInfo = getLinkInfo(dh->dataOrigin, rdh); + if (!mSkipDump && lInfo.fileHandler) { auto sz = o2::raw::RDHUtils::getOffsetToNext(rdh); - auto ws = std::fwrite(raw, 1, sz, fh); + auto raw = it.raw(); + if (mTFCount == 0 && !lInfo.hasSOX && o2::raw::RDHUtils::getTriggerIR(rdh) == mFirstIR) { // need to add SOX bit to existing RDH + auto trig = o2::raw::RDHUtils::getTriggerType(rdh); + trig |= isRORC(lInfo.detID) ? o2::trigger::SOT : (o2::trigger::SOC | o2::trigger::ORBIT | o2::trigger::HB | o2::trigger::TF); + auto rdhC = *rdh; + o2::raw::RDHUtils::setTriggerType(rdhC, trig); + if (mVerbosity > 0) { + LOGP(info, "Write existing RDH with SOX added"); + o2::raw::RDHUtils::printRDH(rdhC); + } + auto ws = std::fwrite(&rdhC, 1, sizeof(o2::header::RDHAny), lInfo.fileHandler); + if (ws != sizeof(o2::header::RDHAny)) { + LOGP(fatal, "Failed to write RDH with SOX added"); + } + raw += sizeof(o2::header::RDHAny); + sz -= sizeof(o2::header::RDHAny); + if (o2::raw::RDHUtils::getStop(rdhC)) { + lInfo.hasSOX = true; + } + } + auto ws = std::fwrite(raw, 1, sz, lInfo.fileHandler); if (ws != sz) { LOGP(fatal, "Failed to write payload of {} bytes", sz); } } } + mTFCount++; } //____________________________________________________________ @@ -186,39 +284,38 @@ void RawDump::endOfStream(EndOfStreamContext& ec) } //_____________________________________________________________________ -FILE* RawDump::getFile(o2h::DataOrigin detOr, const header::RDHAny* rdh) +RawDump::LinkInfo& RawDump::getLinkInfo(o2h::DataOrigin detOr, const header::RDHAny* rdh) { uint32_t feeid = RDHUtils::getFEEID(rdh); uint64_t id = (uint64_t(detOr) << 32) + feeid; - auto fhandler = mDetFEEID2File[id]; - if (!fhandler) { + auto& linkInfo = mLinksInfo[id]; + if (!linkInfo.fileHandler) { DetID detID = mOrigin2DetID[detOr]; auto name = getFileName(detID, rdh); if (name.empty()) { - return nullptr; // reject data of this RDH + return linkInfo; // reject data of this RDH } - fhandler = mName2File[name]; - if (!fhandler) { - fhandler = std::fopen(name.c_str(), "w"); - if (!fhandler) { + linkInfo.fileHandler = mName2File[name]; + if (!linkInfo.fileHandler) { + linkInfo.fileHandler = std::fopen(name.c_str(), "w"); + if (!linkInfo.fileHandler) { LOGP(fatal, "Failed to create file {} for Det={} / FeeID=0x{:05x}", name, detOr.str, feeid); } - mName2File[name] = fhandler; + mName2File[name] = linkInfo.fileHandler; mConfigEntries[detID] += fmt::format( "[input-{}-{}]\n" "dataOrigin = {}\n" "dataDescription = {}\n" "readoutCard = {}\n" "filePath = {}\n\n", - detOr.str, mFilesPerDet[detID]++, detOr.str, (detID == DetID::TOF || mTOFUncompressed) ? DESCRaw.str : DESCCRaw.str, getReadoutType(detID), o2::utils::Str::getFullPath(name)); + detOr.str, mFilesPerDet[detID]++, detOr.str, (detID != DetID::TOF || mTOFUncompressed) ? DESCRaw.str : DESCCRaw.str, getReadoutType(detID), o2::utils::Str::getFullPath(name)); } if (mVerbosity > 0) { RDHUtils::printRDH(rdh); LOGP(info, "Write Det={}/0x{:05x} to {}", detOr.str, feeid, o2::utils::Str::getFullPath(name)); } - mDetFEEID2File[id] = fhandler; } - return fhandler; + return linkInfo; } //_____________________________________________________________________ @@ -588,6 +685,7 @@ DataProcessorSpec getRawDumpSpec(DetID::mask_t detMask, bool TOFUncompressed) ConfigParamSpec{"skip-dump", VariantType::Bool, false, {"do not produce binary data"}}, ConfigParamSpec{"dump-verbosity", VariantType::Int, 0, {"0:minimal, 1:report Det/FeeID->filename, 2: print RDH"}}, ConfigParamSpec{"reject-tpc-links", VariantType::String, "", {"comma-separated list TPC links to reject"}}, + ConfigParamSpec{"skip-impose-sox", VariantType::Bool, false, {"do not impose SOX for 1st TF"}}, ConfigParamSpec{"output-directory", VariantType::String, "./", {"Output directory (create if needed)"}}}}; } diff --git a/Detectors/Raw/src/RawFileReader.cxx b/Detectors/Raw/src/RawFileReader.cxx index be9bc4060b8fb..2d666a6800fe7 100644 --- a/Detectors/Raw/src/RawFileReader.cxx +++ b/Detectors/Raw/src/RawFileReader.cxx @@ -378,7 +378,7 @@ bool RawFileReader::LinkData::preprocessCRUPage(const RDHAny& rdh, bool newSPage reader->imposeFirstTF(irOfSOX.orbit); } } - auto newTFCalc = reader->getTFAutodetect() != FirstTFDetection::Pending && (blocks.empty() || HBU.getTF(blocks.back().ir) < HBU.getTF(ir)); + auto newTFCalc = reader->getTFAutodetect() != FirstTFDetection::Pending && (blocks.empty() || HBU.getTF(blocks.back().ir) != HBU.getTF(ir)); // TF change if (cruDetector) { newTF = (triggerType & o2::trigger::TF); newHB = (triggerType & o2::trigger::HB); From 3c7607010e4cda49ba8ae9bc201458e67b460428 Mon Sep 17 00:00:00 2001 From: Michael Lettrich Date: Sun, 10 Sep 2023 15:24:55 +0200 Subject: [PATCH 029/324] [rANS] Parallel STL Fix --- Utilities/rANS/CMakeLists.txt | 16 ++++++++++++---- Utilities/rANS/benchmarks/bench_ransDecode.cxx | 13 +++++++------ .../rANS/benchmarks/bench_ransDecodeScaling.cxx | 9 +++++---- Utilities/rANS/benchmarks/bench_ransEncode.cxx | 9 +++++---- .../rANS/benchmarks/bench_ransEncodeImpl.cxx | 9 +++++---- .../rANS/benchmarks/bench_ransHistogram.cxx | 11 ++++++----- Utilities/rANS/benchmarks/bench_ransPack.cxx | 9 +++++---- .../rANS/benchmarks/bench_ransStreaming.cxx | 9 +++++---- Utilities/rANS/benchmarks/bench_ransUnpack.cxx | 9 +++++---- Utilities/rANS/benchmarks/helpers.h | 14 +++++++++----- .../rANS/include/rANS/internal/common/defines.h | 6 ++++++ .../rANS/internal/decode/DecoderConcept.h | 4 ++-- 12 files changed, 72 insertions(+), 46 deletions(-) diff --git a/Utilities/rANS/CMakeLists.txt b/Utilities/rANS/CMakeLists.txt index 608485ac601a0..710fe7879571c 100644 --- a/Utilities/rANS/CMakeLists.txt +++ b/Utilities/rANS/CMakeLists.txt @@ -10,6 +10,8 @@ # or submit itself to any jurisdiction. option(RANS_ENABLE_JSON "compile librans with rapidjson" ON) +option(RANS_LOG_PROCESSED_DATA "logs data processed by encoders/decoders as JSON array to log sink" OFF) + set(RANS_ARCH "" CACHE STRING "Compile librans for a given CPU type,\ see https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html.") set(RANS_COMPILE_OPTIONS "" CACHE STRING "Compile librans with these compiler option") @@ -37,6 +39,9 @@ if(${RANS_ENABLE_JSON}) target_compile_definitions(${LIBRANS} INTERFACE RANS_ENABLE_JSON) target_link_libraries(${LIBRANS} INTERFACE RapidJSON::RapidJSON) endif() +if(${RANS_LOG_PROCESSED_DATA}) + target_compile_definitions(${LIBRANS} INTERFACE RANS_LOG_PROCESSED_DATA) +endif() if (OpenMP_CXX_FOUND AND ( NOT APPLE ) ) target_compile_definitions(${LIBRANS} INTERFACE RANS_OPENMP) target_link_libraries(${LIBRANS} INTERFACE OpenMP::OpenMP_CXX) @@ -182,13 +187,15 @@ o2_add_test(Serialize LABELS utils) target_compile_options(${TEST_SERIALIZE} PRIVATE ${RANS_TEST_ARCH}) -if(${RANS_ENABLE_JSON}) - if (${ENABLE_RANS_BENCHMARK}) - +if (TARGET benchmark::benchmark) o2_add_header_only_library(libransBenchmark TARGETVARNAME LIB_RANS_BENCHMARK - INTERFACE_LINK_LIBRARIES O2::rANS RapidJSON::RapidJSON benchmark::benchmark TBB::tbb) + INTERFACE_LINK_LIBRARIES O2::rANS benchmark::benchmark) target_compile_options(${LIB_RANS_BENCHMARK} INTERFACE -O3 ${RANS_OPTIONS}) + if(TARGET TBB::tbb) + target_compile_definitions(${LIB_RANS_BENCHMARK} INTERFACE RANS_ENABLE_PARALLEL_STL) + target_link_libraries(${LIB_RANS_BENCHMARK} INTERFACE TBB::tbb) + endif() if(${ENABLE_VTUNE_PROFILER}) target_compile_definitions(${LIB_RANS_BENCHMARK} INTERFACE ENABLE_VTUNE_PROFILER) target_link_libraries(${LIB_RANS_BENCHMARK} INTERFACE PkgConfig::Vtune) @@ -248,6 +255,7 @@ if(${RANS_ENABLE_JSON}) IS_BENCHMARK PUBLIC_LINK_LIBRARIES O2::libransBenchmark) + if(${RANS_ENABLE_JSON}) o2_add_executable(TPCEncodeDecode SOURCES benchmarks/bench_ransTPC.cxx COMPONENT_NAME rANS diff --git a/Utilities/rANS/benchmarks/bench_ransDecode.cxx b/Utilities/rANS/benchmarks/bench_ransDecode.cxx index 6e85d7c7cd50c..a642b58a3431d 100644 --- a/Utilities/rANS/benchmarks/bench_ransDecode.cxx +++ b/Utilities/rANS/benchmarks/bench_ransDecode.cxx @@ -13,12 +13,13 @@ /// @author Michael Lettrich /// @brief compares performance of different encoders +#include "rANS/internal/common/defines.h" + #include #include #include #include -#include -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL #include #endif #include @@ -51,11 +52,11 @@ inline constexpr size_t MessageSize = 1ull << 22; // std::binomial_distribution dist(draws, probability); // const size_t sourceSize = messageSize / sizeof(source_T) + 1; // mSourceMessage.resize(sourceSize); -// #ifdef __cpp_lib_execution +// #ifdef RANS_PARALLEL_STL // std::generate(std::execution::par_unseq, mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); // #else // std::generate(mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); -// #endif +// #endif // RANS_PARALLEL_STL // } // } @@ -82,11 +83,11 @@ class SourceMessageProxyUniform std::uniform_int_distribution dist(min, max); const size_t sourceSize = messageSize / sizeof(source_T) + 1; mSourceMessage.resize(sourceSize); -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL std::generate(std::execution::par_unseq, mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); #else std::generate(mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); -#endif +#endif // RANS_PARALLEL_STL } } diff --git a/Utilities/rANS/benchmarks/bench_ransDecodeScaling.cxx b/Utilities/rANS/benchmarks/bench_ransDecodeScaling.cxx index 4b8c1c01f98be..2d882aaecf8b7 100644 --- a/Utilities/rANS/benchmarks/bench_ransDecodeScaling.cxx +++ b/Utilities/rANS/benchmarks/bench_ransDecodeScaling.cxx @@ -13,12 +13,13 @@ /// @author Michael Lettrich /// @brief compares performance of different encoders +#include "rANS/internal/common/defines.h" + #include #include #include #include -#include -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL #include #endif #include @@ -48,11 +49,11 @@ class SourceMessageUniform std::uniform_int_distribution dist(0, max); const size_t sourceSize = messageSize / sizeof(source_T) + 1; mSourceMessage.resize(sourceSize); -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL std::generate(std::execution::par_unseq, mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); #else std::generate(mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); -#endif +#endif // RANS_PARALLEL_STL } const auto& get() const { return mSourceMessage; }; diff --git a/Utilities/rANS/benchmarks/bench_ransEncode.cxx b/Utilities/rANS/benchmarks/bench_ransEncode.cxx index 67eb78dfdb127..668697aaad455 100644 --- a/Utilities/rANS/benchmarks/bench_ransEncode.cxx +++ b/Utilities/rANS/benchmarks/bench_ransEncode.cxx @@ -13,12 +13,13 @@ /// @author Michael Lettrich /// @brief compares performance of different encoders +#include "rANS/internal/common/defines.h" + #include #include #include #include -#include -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL #include #endif #include @@ -51,11 +52,11 @@ class SourceMessageProxy std::binomial_distribution dist(draws, probability); const size_t sourceSize = messageSize / sizeof(source_T) + 1; mSourceMessage.resize(sourceSize); -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL std::generate(std::execution::par_unseq, mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); #else std::generate(mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); -#endif +#endif // RANS_PARALLEL_STL } } diff --git a/Utilities/rANS/benchmarks/bench_ransEncodeImpl.cxx b/Utilities/rANS/benchmarks/bench_ransEncodeImpl.cxx index 1896d5b4ffe81..b6f260996c9ce 100644 --- a/Utilities/rANS/benchmarks/bench_ransEncodeImpl.cxx +++ b/Utilities/rANS/benchmarks/bench_ransEncodeImpl.cxx @@ -13,12 +13,13 @@ /// @author Michael Lettrich /// @brief benchmarks different encoding kernels without the need to renorm and stream data +#include "rANS/internal/common/defines.h" + #include #include #include #include -#include -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL #include #endif #include @@ -66,11 +67,11 @@ class SymbolTableData std::binomial_distribution dist(draws, probability); const size_t sourceSize = messageSize / sizeof(source_T); mSourceMessage.resize(sourceSize); -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL std::generate(std::execution::par_unseq, mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); #else std::generate(mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); -#endif +#endif // RANS_PARALLEL_STL const auto histogram = makeDenseHistogram::fromSamples(gsl::span(mSourceMessage)); Metrics metrics{histogram}; diff --git a/Utilities/rANS/benchmarks/bench_ransHistogram.cxx b/Utilities/rANS/benchmarks/bench_ransHistogram.cxx index ca925ea742bdb..9c32117ba914b 100644 --- a/Utilities/rANS/benchmarks/bench_ransHistogram.cxx +++ b/Utilities/rANS/benchmarks/bench_ransHistogram.cxx @@ -13,12 +13,13 @@ /// @author Michael Lettrich /// @brief compares performance of different encoders +#include "rANS/internal/common/defines.h" + #include #include #include #include -#include -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL #include #endif #include @@ -56,11 +57,11 @@ class SourceMessageProxyBinomial std::binomial_distribution dist(draws, probability); const size_t sourceSize = messageSize / sizeof(source_T) + 1; mSourceMessage.resize(sourceSize); -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL std::generate(std::execution::par_unseq, mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); #else std::generate(mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); -#endif +#endif // RANS_PARALLEL_STL } return mSourceMessage; @@ -89,7 +90,7 @@ class SourceMessageProxyUniform std::uniform_int_distribution dist(min, max); const size_t sourceSize = messageSize / sizeof(source_T) + 1; mSourceMessage.resize(sourceSize); -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL std::generate(std::execution::par_unseq, mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); #else std::generate(mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); diff --git a/Utilities/rANS/benchmarks/bench_ransPack.cxx b/Utilities/rANS/benchmarks/bench_ransPack.cxx index 188ab481dd4ab..c00a18b323a76 100644 --- a/Utilities/rANS/benchmarks/bench_ransPack.cxx +++ b/Utilities/rANS/benchmarks/bench_ransPack.cxx @@ -13,12 +13,13 @@ /// @author Michael Lettrich /// @brief benchmarks packing algorithms and compares it to memcpy +#include "rANS/internal/common/defines.h" + #include #include #include #include -#include -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL #include #endif #include @@ -46,11 +47,11 @@ std::vector makeRandomUniformVector(size_t nelems, source_T min = std: std::mt19937 mt(0); // same seed we want always the same distrubution of random numbers; std::uniform_int_distribution dist(min, max); -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL std::generate(std::execution::par_unseq, result.begin(), result.end(), [&dist, &mt]() { return dist(mt); }); #else std::generate(result.begin(), result.end(), [&dist, &mt]() { return dist(mt); }); -#endif +#endif // RANS_PARALLEL_STL return result; }; diff --git a/Utilities/rANS/benchmarks/bench_ransStreaming.cxx b/Utilities/rANS/benchmarks/bench_ransStreaming.cxx index 04e592aea2403..c079b04910936 100644 --- a/Utilities/rANS/benchmarks/bench_ransStreaming.cxx +++ b/Utilities/rANS/benchmarks/bench_ransStreaming.cxx @@ -13,12 +13,13 @@ /// @author Michael Lettrich /// @brief benchmarks streaming out data from rANS state to memory +#include "rANS/internal/common/defines.h" + #include #include #include #include -#include -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL #include #endif #include @@ -61,11 +62,11 @@ class RenormingData std::binomial_distribution dist(draws, probability); const size_t sourceSize = messageSize / sizeof(source_T); mSourceMessage.resize(sourceSize); -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL std::generate(std::execution::par_unseq, mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); #else std::generate(mSourceMessage.begin(), mSourceMessage.end(), [&dist, &mt]() { return dist(mt); }); -#endif +#endif // RANS_PARALLEL_STL const auto histogram = makeDenseHistogram::fromSamples(gsl::span(mSourceMessage)); Metrics metrics{histogram}; diff --git a/Utilities/rANS/benchmarks/bench_ransUnpack.cxx b/Utilities/rANS/benchmarks/bench_ransUnpack.cxx index 9af732f5b58c5..fce8b99cbc910 100644 --- a/Utilities/rANS/benchmarks/bench_ransUnpack.cxx +++ b/Utilities/rANS/benchmarks/bench_ransUnpack.cxx @@ -13,12 +13,13 @@ /// @author Michael Lettrich /// @brief benchmark unpacking of data compared to memcpy +#include "rANS/internal/common/defines.h" + #include #include #include #include -#include -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL #include #endif #include @@ -46,11 +47,11 @@ std::vector makeRandomUniformVector(size_t nelems, source_T min = std: std::mt19937 mt(0); // same seed we want always the same distrubution of random numbers; std::uniform_int_distribution dist(min, max); -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL std::generate(std::execution::par_unseq, result.begin(), result.end(), [&dist, &mt]() { return dist(mt); }); #else std::generate(result.begin(), result.end(), [&dist, &mt]() { return dist(mt); }); -#endif +#endif // RANS_PARALLEL_STL return result; }; diff --git a/Utilities/rANS/benchmarks/helpers.h b/Utilities/rANS/benchmarks/helpers.h index a06531310b19f..936c478c51054 100644 --- a/Utilities/rANS/benchmarks/helpers.h +++ b/Utilities/rANS/benchmarks/helpers.h @@ -16,25 +16,28 @@ #ifndef RANS_BENCHMARKS_HELPERS_H_ #define RANS_BENCHMARKS_HELPERS_H_ +#include "rANS/internal/common/defines.h" + #ifdef ENABLE_VTUNE_PROFILER #include #endif +#ifdef RANS_ENABLE_JSON #include #include #include #include - +#endif // RANS_ENABLE_JSON #include #include #include "rANS/internal/common/exceptions.h" -#include -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL #include #endif +#ifdef RANS_ENABLE_JSON struct TPCCompressedClusters { TPCCompressedClusters() = default; @@ -276,6 +279,7 @@ TPCCompressedClusters readFile(const std::string& filename) } return compressedClusters; }; +#endif // RANS_ENABLE_JSON template struct EncodeBuffer { @@ -303,11 +307,11 @@ struct DecodeBuffer { template bool operator==(const T& correct) { -#ifdef __cpp_lib_execution +#ifdef RANS_PARALLEL_STL return std::equal(std::execution::par_unseq, buffer.begin(), buffer.end(), std::begin(correct), std::end(correct)); #else return std::equal(buffer.begin(), buffer.end(), std::begin(correct), std::end(correct)); -#endif +#endif // RANS_PARALLEL_STL } std::vector buffer{}; diff --git a/Utilities/rANS/include/rANS/internal/common/defines.h b/Utilities/rANS/include/rANS/internal/common/defines.h index 5f1a5731a20bd..21afb4ff01750 100644 --- a/Utilities/rANS/include/rANS/internal/common/defines.h +++ b/Utilities/rANS/include/rANS/internal/common/defines.h @@ -16,6 +16,8 @@ #ifndef RANS_INTERNAL_COMMON_DEFINES_H_ #define RANS_INTERNAL_COMMON_DEFINES_H_ +#include + #ifdef RANS_AVX2 #error RANS_AVX2 cannot be directly set #endif @@ -66,4 +68,8 @@ #define RANS_FMA #endif +#if defined(RANS_ENABLE_PARALLEL_STL) && defined(__cpp_lib_execution) +#define RANS_PARALLEL_STL +#endif + #endif /*RANS_INTERNAL_COMMON_DEFINES_H_*/ \ No newline at end of file diff --git a/Utilities/rANS/include/rANS/internal/decode/DecoderConcept.h b/Utilities/rANS/include/rANS/internal/decode/DecoderConcept.h index 759b22aca5d7b..e888ff9b24dcb 100644 --- a/Utilities/rANS/include/rANS/internal/decode/DecoderConcept.h +++ b/Utilities/rANS/include/rANS/internal/decode/DecoderConcept.h @@ -83,7 +83,7 @@ class DecoderConcept auto decode = [&, this](coder_type& decoder) { const auto cumul = decoder.get(); const value_type symbol = lookupSymbol(cumul); -#ifdef O2_RANS_PRINT_PROCESSED_DATA +#ifdef RANS_LOG_PROCESSED_DATA arrayLogger << symbol.first; #endif return std::make_tuple(symbol.first, decoder.advanceSymbol(inputIter, symbol.second)); @@ -110,7 +110,7 @@ class DecoderConcept std::tie(*outputIter++, inputIter) = decode(decoders[i]); } -#ifdef O2_RANS_PRINT_PROCESSED_DATA +#ifdef RANS_LOG_PROCESSED_DATA LOG(info) << "decoderOutput:" << arrayLogger; #endif } From c702f00e83a1f5636fa637fea9d9d02bcdcbc4e0 Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Tue, 12 Sep 2023 11:40:00 +0200 Subject: [PATCH 030/324] Fix TRD raw data stats trigger counter (#11882) --- DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h index 53401d96c2d07..acc241d55cf90 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h @@ -163,6 +163,8 @@ class TRDDataCountersPerTimeFrame mTimeTakenForTracklets = 0; mDigitsFound = 0; mTrackletsFound = 0; + mNTriggersCalib = 0; + mNTriggersTotal = 0; mDataFormatRead.fill(0); }; ClassDefNV(TRDDataCountersPerTimeFrame, 2); // primarily for serialisation so we can send this as a message in o2 From 7e71238104e4904307b3274b3bca912e651e9695 Mon Sep 17 00:00:00 2001 From: rmunzer <97919772+rmunzer@users.noreply.github.com> Date: Wed, 13 Sep 2023 17:09:49 +0200 Subject: [PATCH 031/324] TPC: Add Writing of Pad Status Map (#11859) * Add option to write out dead channel map to tpd idc factorize * Include variable to deactivate PadStatusMapWriting * Add option to disable Pad Status Map Writing for IDC * For disabeling the option need to removed complety: setting to false does not work * Update aggregator-workflow.sh --------- Co-authored-by: David Rohr --- prodtests/full-system-test/aggregator-workflow.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/prodtests/full-system-test/aggregator-workflow.sh b/prodtests/full-system-test/aggregator-workflow.sh index 55fb15e78b66d..10c0e38275319 100755 --- a/prodtests/full-system-test/aggregator-workflow.sh +++ b/prodtests/full-system-test/aggregator-workflow.sh @@ -258,10 +258,12 @@ IDC_DELTA="--disable-IDCDelta true" # off by default if [[ "${DISABLE_IDC_DELTA:-}" == "1" ]]; then IDC_DELTA=""; fi if [[ "${ENABLE_IDC_DELTA_FILE:-}" == "1" ]]; then IDC_DELTA+=" --dump-IDCDelta-calib-data true --output-dir $CALIB_DIR --meta-output-dir $EPN2EOS_METAFILES_DIR "; fi +if [[ "${DISABLE_IDC_PAD_MAP_WRITING:-}" == 1 ]]; then TPC_WRITING_PAD_STATUS_MAP=""; else TPC_WRITING_PAD_STATUS_MAP="--enableWritingPadStatusMap true"; fi + if ! workflow_has_parameter CALIB_LOCAL_INTEGRATED_AGGREGATOR; then if [[ $CALIB_TPC_IDC == 1 ]] && [[ $AGGREGATOR_TASKS == TPC_IDCBOTH_SAC || $AGGREGATOR_TASKS == ALL ]]; then add_W o2-tpc-idc-distribute "--crus ${crus} --timeframes ${nTFs} --output-lanes ${lanesFactorize} --send-precise-timestamp true --condition-tf-per-query ${nTFs} --n-TFs-buffer ${nBuffer}" - add_W o2-tpc-idc-factorize "--n-TFs-buffer ${nBuffer} --input-lanes ${lanesFactorize} --crus ${crus} --timeframes ${nTFs} --nthreads-grouping 8 --nthreads-IDC-factorization 8 --sendOutputFFT true --enable-CCDB-output true --enablePadStatusMap true --use-precise-timestamp true $IDC_DELTA" "TPCIDCGroupParam.groupPadsSectorEdges=32211" + add_W o2-tpc-idc-factorize "--n-TFs-buffer ${nBuffer} --input-lanes ${lanesFactorize} --crus ${crus} --timeframes ${nTFs} --nthreads-grouping 8 --nthreads-IDC-factorization 8 --sendOutputFFT true --enable-CCDB-output true --enablePadStatusMap true ${TPC_WRITING_PAD_STATUS_MAP} --use-precise-timestamp true $IDC_DELTA" "TPCIDCGroupParam.groupPadsSectorEdges=32211" add_W o2-tpc-idc-ft-aggregator "--rangeIDC 200 --inputLanes ${lanesFactorize} --nFourierCoeff 40 --nthreads 8" fi if [[ $CALIB_TPC_SAC == 1 ]] && [[ $AGGREGATOR_TASKS == TPC_IDCBOTH_SAC || $AGGREGATOR_TASKS == ALL ]]; then From 76c0a016c06aa91cd4dfa33b95693a8f3a3dace8 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 14 Sep 2023 17:19:03 +0200 Subject: [PATCH 032/324] Avoid exposing rANS internal details to ROOT (#11892) --- .../include/DetectorsCommonDataFormats/EncodedBlocks.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index 4e3dd1f9f4004..7f2db5cedffc9 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -33,6 +33,7 @@ #include "DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h" #include "DetectorsCommonDataFormats/internal/Packer.h" #include "DetectorsCommonDataFormats/Metadata.h" +#ifndef __CLING__ #include "rANS/compat.h" #include "rANS/histogram.h" #include "rANS/serialize.h" @@ -40,6 +41,7 @@ #include "rANS/metrics.h" #include "rANS/serialize.h" #include "rANS/utils.h" +#endif namespace o2 { @@ -333,8 +335,10 @@ class EncodedBlocks public: typedef EncodedBlocks base; +#ifndef __CLING__ template using dictionaryType = std::variant, rans::RenormedDenseHistogram>; +#endif void setHeader(const H& h) { mHeader = h; } const H& getHeader() const { return mHeader; } @@ -357,6 +361,7 @@ class EncodedBlocks return mBlocks[i]; } +#ifndef __CLING__ template dictionaryType getDictionary(int i, ANSHeader ansVersion = ANSVersionUnspecified) const { @@ -393,6 +398,7 @@ class EncodedBlocks throw std::runtime_error(fmt::format("Failed to load serialized Dictionary. Unsupported ANS Version: {}", static_cast(ansVersion))); } }; +#endif void setANSHeader(const ANSHeader& h) { @@ -913,6 +919,7 @@ CTFIOSize EncodedBlocks::decode(D_IT dest, // it } }; +#ifndef __CLING__ template template CTFIOSize EncodedBlocks::decodeCompatImpl(dst_IT dstBegin, int slot, const std::any& decoderExt) const @@ -1400,6 +1407,7 @@ CTFIOSize EncodedBlocks::encodeRANSV1Inplace(const input_IT srcBegin, c return {0, thisMetadata->getUncompressedSize(), thisMetadata->getCompressedSize()}; }; // namespace ctf +#endif template template From bd386f271ea25bdb525f7c633a1c596024274da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Jacazio?= Date: Thu, 14 Sep 2023 16:01:27 -0500 Subject: [PATCH 033/324] Add labelled string array (#11707) --- Framework/Core/include/Framework/Variant.h | 7 ++++++- Framework/Core/include/Framework/VariantJSONHelpers.h | 3 +++ Framework/Core/src/BoostOptionsRetriever.cxx | 1 + Framework/Core/src/ConfigParamsHelper.cxx | 1 + Framework/Core/src/PropertyTreeHelpers.cxx | 11 +++++++++++ Framework/Core/src/WorkflowSerializationHelpers.cxx | 4 ++++ Framework/Core/src/runDataProcessing.cxx | 3 +++ Framework/Core/test/test_Variants.cxx | 6 ++++++ 8 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Framework/Core/include/Framework/Variant.h b/Framework/Core/include/Framework/Variant.h index f0664bcdc3bd4..24e60b74999b3 100644 --- a/Framework/Core/include/Framework/Variant.h +++ b/Framework/Core/include/Framework/Variant.h @@ -44,6 +44,7 @@ enum class VariantType : int { Int = 0, LabeledArrayInt, LabeledArrayFloat, LabeledArrayDouble, + LabeledArrayString, UInt8, UInt16, UInt32, @@ -77,7 +78,8 @@ constexpr auto isLabeledArray() { return (V == VariantType::LabeledArrayInt || V == VariantType::LabeledArrayFloat || - V == VariantType::LabeledArrayDouble); + V == VariantType::LabeledArrayDouble || + V == VariantType::LabeledArrayString); } template @@ -146,6 +148,7 @@ DECLARE_VARIANT_TRAIT(Array2D, Array2DDouble); DECLARE_VARIANT_TRAIT(LabeledArray, LabeledArrayInt); DECLARE_VARIANT_TRAIT(LabeledArray, LabeledArrayFloat); DECLARE_VARIANT_TRAIT(LabeledArray, LabeledArrayDouble); +DECLARE_VARIANT_TRAIT(LabeledArray, LabeledArrayString); template struct variant_array_symbol { @@ -216,6 +219,7 @@ DECLARE_VARIANT_TYPE(Array2D, Array2DDouble); DECLARE_VARIANT_TYPE(LabeledArray, LabeledArrayInt); DECLARE_VARIANT_TYPE(LabeledArray, LabeledArrayFloat); DECLARE_VARIANT_TYPE(LabeledArray, LabeledArrayDouble); +DECLARE_VARIANT_TYPE(LabeledArray, LabeledArrayString); template struct variant_array_element_type { @@ -239,6 +243,7 @@ DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(std::string, ArrayString); DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(int, LabeledArrayInt); DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(float, LabeledArrayFloat); DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(double, LabeledArrayDouble); +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(std::string, LabeledArrayString); template using variant_array_element_type_t = typename variant_array_element_type::type; diff --git a/Framework/Core/include/Framework/VariantJSONHelpers.h b/Framework/Core/include/Framework/VariantJSONHelpers.h index a09192d9954e7..ce998275d26b3 100644 --- a/Framework/Core/include/Framework/VariantJSONHelpers.h +++ b/Framework/Core/include/Framework/VariantJSONHelpers.h @@ -437,6 +437,9 @@ struct VariantJSONHelpers { case VariantType::LabeledArrayDouble: writeVariant(o, v); break; + case VariantType::LabeledArrayString: + writeVariant(o, v); + break; case VariantType::Dict: writeVariant(o, v); default: diff --git a/Framework/Core/src/BoostOptionsRetriever.cxx b/Framework/Core/src/BoostOptionsRetriever.cxx index 5f9381da9f0b3..fbf56a312cf66 100644 --- a/Framework/Core/src/BoostOptionsRetriever.cxx +++ b/Framework/Core/src/BoostOptionsRetriever.cxx @@ -97,6 +97,7 @@ void BoostOptionsRetriever::update(std::vector const& specs, case VariantType::LabeledArrayInt: case VariantType::LabeledArrayFloat: case VariantType::LabeledArrayDouble: + case VariantType::LabeledArrayString: case VariantType::Unknown: case VariantType::Empty: break; diff --git a/Framework/Core/src/ConfigParamsHelper.cxx b/Framework/Core/src/ConfigParamsHelper.cxx index 2f0c75c131f48..a7b32c86e3eca 100644 --- a/Framework/Core/src/ConfigParamsHelper.cxx +++ b/Framework/Core/src/ConfigParamsHelper.cxx @@ -101,6 +101,7 @@ void ConfigParamsHelper::populateBoostProgramOptions( case VariantType::LabeledArrayInt: case VariantType::LabeledArrayFloat: case VariantType::LabeledArrayDouble: + case VariantType::LabeledArrayString: // FIXME: for Dict we should probably allow parsing stuff // provided on the command line case VariantType::Dict: diff --git a/Framework/Core/src/PropertyTreeHelpers.cxx b/Framework/Core/src/PropertyTreeHelpers.cxx index 48bb4803b18b4..cf862b78e77b5 100644 --- a/Framework/Core/src/PropertyTreeHelpers.cxx +++ b/Framework/Core/src/PropertyTreeHelpers.cxx @@ -106,6 +106,9 @@ void PropertyTreeHelpers::populateDefaults(std::vector const& s case VariantType::LabeledArrayDouble: pt.put_child(key, labeledArrayToBranch(spec.defaultValue.get>())); break; + case VariantType::LabeledArrayString: + pt.put_child(key, labeledArrayToBranch(spec.defaultValue.get>())); + break; case VariantType::Unknown: case VariantType::Empty: default: @@ -320,6 +323,14 @@ void PropertyTreeHelpers::populate(std::vector const& schema, pt.put_child(key, labeledArrayToBranch(std::move(v))); } }; break; + case VariantType::LabeledArrayString: { + auto v = labeledArrayFromBranch(it.value()); + if (!replaceLabels(v, spec.defaultValue.get>())) { + pt.put_child(key, *it); + } else { + pt.put_child(key, labeledArrayToBranch(std::move(v))); + } + }; break; case VariantType::Unknown: case VariantType::Empty: default: diff --git a/Framework/Core/src/WorkflowSerializationHelpers.cxx b/Framework/Core/src/WorkflowSerializationHelpers.cxx index 3a33d4a14a734..ac182a27a70c5 100644 --- a/Framework/Core/src/WorkflowSerializationHelpers.cxx +++ b/Framework/Core/src/WorkflowSerializationHelpers.cxx @@ -507,6 +507,9 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler, case VariantType::LabeledArrayDouble: opt = std::make_unique(optionName, optionType, VariantJSONHelpers::read(is), HelpString{optionHelp}, optionKind); break; + case VariantType::LabeledArrayString: + opt = std::make_unique(optionName, optionType, VariantJSONHelpers::read(is), HelpString{optionHelp}, optionKind); + break; case VariantType::Dict: opt = std::make_unique(optionName, optionType, emptyDict(), HelpString{optionHelp}, optionKind); break; @@ -1191,6 +1194,7 @@ void WorkflowSerializationHelpers::dump(std::ostream& out, case VariantType::LabeledArrayInt: case VariantType::LabeledArrayFloat: case VariantType::LabeledArrayDouble: + case VariantType::LabeledArrayString: case VariantType::Dict: VariantJSONHelpers::write(oss, option.defaultValue); break; diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index 8651d25829963..9f92f85038057 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -1800,6 +1800,9 @@ int runStateMachine(DataProcessorSpecs const& workflow, case VariantType::LabeledArrayDouble: option.defaultValue = reg->get>(name); break; + case VariantType::LabeledArrayString: + option.defaultValue = reg->get>(name); + break; default: break; } diff --git a/Framework/Core/test/test_Variants.cxx b/Framework/Core/test/test_Variants.cxx index a5753e26925b3..d774fe160885b 100644 --- a/Framework/Core/test/test_Variants.cxx +++ b/Framework/Core/test/test_Variants.cxx @@ -218,14 +218,20 @@ TEST_CASE("Array2DTest") TEST_CASE("LabeledArrayTest") { float m[3][4] = {{0.1, 0.2, 0.3, 0.4}, {0.5, 0.6, 0.7, 0.8}, {0.9, 1.0, 1.1, 1.2}}; + std::string mS[3][4] = {{"a", "b", "c", "d"}, {"e", "f", "g", "h"}, {"i", "l", "m", "n"}}; std::string xl[] = {"c1", "c2", "c3", "c4"}; std::string yl[] = {"r1", "r2", "r3"}; LabeledArray laf{&m[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}}; + LabeledArray las{&mS[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}}; for (auto i = 0u; i < 3; ++i) { for (auto j = 0u; j < 4; ++j) { REQUIRE(laf.get(yl[i].c_str(), xl[j].c_str()) == laf.get(i, j)); REQUIRE(laf.get(i, xl[j].c_str()) == laf.get(i, j)); REQUIRE(laf.get(yl[i].c_str(), j) == laf.get(i, j)); + + REQUIRE(las.get(yl[i].c_str(), xl[j].c_str()) == las.get(i, j)); + REQUIRE(las.get(i, xl[j].c_str()) == las.get(i, j)); + REQUIRE(las.get(yl[i].c_str(), j) == las.get(i, j)); } } } From 144851bbb115c36229bf0681905a4d839b4c2fd4 Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 14 Sep 2023 19:06:28 +0200 Subject: [PATCH 034/324] Define alignable volumes for all detoctors including those declared inactive --- Steer/src/O2MCApplication.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Steer/src/O2MCApplication.cxx b/Steer/src/O2MCApplication.cxx index 8594de2c860a8..ea4faab1c415f 100644 --- a/Steer/src/O2MCApplication.cxx +++ b/Steer/src/O2MCApplication.cxx @@ -163,7 +163,7 @@ void O2MCApplicationBase::InitGeometry() bool O2MCApplicationBase::MisalignGeometry() { - for (auto det : listActiveDetectors) { + for (auto det : listDetectors) { if (dynamic_cast(det)) { ((o2::base::Detector*)det)->addAlignableVolumes(); } From 04ae1e5cfa25121ac8b1be721bb776a6a32f049c Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 14 Sep 2023 17:54:32 +0200 Subject: [PATCH 035/324] do not raise error if all hits of the chip are masked --- .../include/ITSMFTReconstruction/AlpideCoder.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h index c415f25157539..f36473b2c7899 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h @@ -150,6 +150,7 @@ class AlpideCoder uint32_t expectInp = ExpectChipHeader | ExpectChipEmpty; // data must always start with chip header or chip empty flag chipData.clear(); + bool dataSeen = false; LOG(debug) << "NewEntry"; while (buffer.next(dataC)) { // @@ -179,6 +180,7 @@ class AlpideCoder return unexpectedEOF("CHIP_HEADER"); // abandon cable data } expectInp = ExpectRegion; // now expect region info + dataSeen = false; continue; } @@ -205,7 +207,7 @@ class AlpideCoder } } - if (!chipData.getData().size() && !chipData.isErrorSet()) { + if (!dataSeen && !chipData.isErrorSet()) { #ifdef ALPIDE_DECODING_STAT chipData.setError(ChipStat::TrailerAfterHeader); #endif @@ -216,6 +218,7 @@ class AlpideCoder // hit info ? if ((expectInp & ExpectData)) { + dataSeen = true; if (isData(dataC)) { // region header was seen, expect data // note that here we are checking on the byte rather than the short, need complete to ushort dataS = dataC << 8; From d9d644c2033707a88bd65dc1a1d7e3da6f54ae02 Mon Sep 17 00:00:00 2001 From: Jan Fiete Date: Fri, 15 Sep 2023 12:51:58 +0200 Subject: [PATCH 036/324] Revert "Add labelled string array (#11707)" (#11899) This reverts commit 051af6e5e710a398ca8b98e8b494d711fead3b89. --- Framework/Core/include/Framework/Variant.h | 7 +------ Framework/Core/include/Framework/VariantJSONHelpers.h | 3 --- Framework/Core/src/BoostOptionsRetriever.cxx | 1 - Framework/Core/src/ConfigParamsHelper.cxx | 1 - Framework/Core/src/PropertyTreeHelpers.cxx | 11 ----------- Framework/Core/src/WorkflowSerializationHelpers.cxx | 4 ---- Framework/Core/src/runDataProcessing.cxx | 3 --- Framework/Core/test/test_Variants.cxx | 6 ------ 8 files changed, 1 insertion(+), 35 deletions(-) diff --git a/Framework/Core/include/Framework/Variant.h b/Framework/Core/include/Framework/Variant.h index 24e60b74999b3..f0664bcdc3bd4 100644 --- a/Framework/Core/include/Framework/Variant.h +++ b/Framework/Core/include/Framework/Variant.h @@ -44,7 +44,6 @@ enum class VariantType : int { Int = 0, LabeledArrayInt, LabeledArrayFloat, LabeledArrayDouble, - LabeledArrayString, UInt8, UInt16, UInt32, @@ -78,8 +77,7 @@ constexpr auto isLabeledArray() { return (V == VariantType::LabeledArrayInt || V == VariantType::LabeledArrayFloat || - V == VariantType::LabeledArrayDouble || - V == VariantType::LabeledArrayString); + V == VariantType::LabeledArrayDouble); } template @@ -148,7 +146,6 @@ DECLARE_VARIANT_TRAIT(Array2D, Array2DDouble); DECLARE_VARIANT_TRAIT(LabeledArray, LabeledArrayInt); DECLARE_VARIANT_TRAIT(LabeledArray, LabeledArrayFloat); DECLARE_VARIANT_TRAIT(LabeledArray, LabeledArrayDouble); -DECLARE_VARIANT_TRAIT(LabeledArray, LabeledArrayString); template struct variant_array_symbol { @@ -219,7 +216,6 @@ DECLARE_VARIANT_TYPE(Array2D, Array2DDouble); DECLARE_VARIANT_TYPE(LabeledArray, LabeledArrayInt); DECLARE_VARIANT_TYPE(LabeledArray, LabeledArrayFloat); DECLARE_VARIANT_TYPE(LabeledArray, LabeledArrayDouble); -DECLARE_VARIANT_TYPE(LabeledArray, LabeledArrayString); template struct variant_array_element_type { @@ -243,7 +239,6 @@ DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(std::string, ArrayString); DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(int, LabeledArrayInt); DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(float, LabeledArrayFloat); DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(double, LabeledArrayDouble); -DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(std::string, LabeledArrayString); template using variant_array_element_type_t = typename variant_array_element_type::type; diff --git a/Framework/Core/include/Framework/VariantJSONHelpers.h b/Framework/Core/include/Framework/VariantJSONHelpers.h index ce998275d26b3..a09192d9954e7 100644 --- a/Framework/Core/include/Framework/VariantJSONHelpers.h +++ b/Framework/Core/include/Framework/VariantJSONHelpers.h @@ -437,9 +437,6 @@ struct VariantJSONHelpers { case VariantType::LabeledArrayDouble: writeVariant(o, v); break; - case VariantType::LabeledArrayString: - writeVariant(o, v); - break; case VariantType::Dict: writeVariant(o, v); default: diff --git a/Framework/Core/src/BoostOptionsRetriever.cxx b/Framework/Core/src/BoostOptionsRetriever.cxx index fbf56a312cf66..5f9381da9f0b3 100644 --- a/Framework/Core/src/BoostOptionsRetriever.cxx +++ b/Framework/Core/src/BoostOptionsRetriever.cxx @@ -97,7 +97,6 @@ void BoostOptionsRetriever::update(std::vector const& specs, case VariantType::LabeledArrayInt: case VariantType::LabeledArrayFloat: case VariantType::LabeledArrayDouble: - case VariantType::LabeledArrayString: case VariantType::Unknown: case VariantType::Empty: break; diff --git a/Framework/Core/src/ConfigParamsHelper.cxx b/Framework/Core/src/ConfigParamsHelper.cxx index a7b32c86e3eca..2f0c75c131f48 100644 --- a/Framework/Core/src/ConfigParamsHelper.cxx +++ b/Framework/Core/src/ConfigParamsHelper.cxx @@ -101,7 +101,6 @@ void ConfigParamsHelper::populateBoostProgramOptions( case VariantType::LabeledArrayInt: case VariantType::LabeledArrayFloat: case VariantType::LabeledArrayDouble: - case VariantType::LabeledArrayString: // FIXME: for Dict we should probably allow parsing stuff // provided on the command line case VariantType::Dict: diff --git a/Framework/Core/src/PropertyTreeHelpers.cxx b/Framework/Core/src/PropertyTreeHelpers.cxx index cf862b78e77b5..48bb4803b18b4 100644 --- a/Framework/Core/src/PropertyTreeHelpers.cxx +++ b/Framework/Core/src/PropertyTreeHelpers.cxx @@ -106,9 +106,6 @@ void PropertyTreeHelpers::populateDefaults(std::vector const& s case VariantType::LabeledArrayDouble: pt.put_child(key, labeledArrayToBranch(spec.defaultValue.get>())); break; - case VariantType::LabeledArrayString: - pt.put_child(key, labeledArrayToBranch(spec.defaultValue.get>())); - break; case VariantType::Unknown: case VariantType::Empty: default: @@ -323,14 +320,6 @@ void PropertyTreeHelpers::populate(std::vector const& schema, pt.put_child(key, labeledArrayToBranch(std::move(v))); } }; break; - case VariantType::LabeledArrayString: { - auto v = labeledArrayFromBranch(it.value()); - if (!replaceLabels(v, spec.defaultValue.get>())) { - pt.put_child(key, *it); - } else { - pt.put_child(key, labeledArrayToBranch(std::move(v))); - } - }; break; case VariantType::Unknown: case VariantType::Empty: default: diff --git a/Framework/Core/src/WorkflowSerializationHelpers.cxx b/Framework/Core/src/WorkflowSerializationHelpers.cxx index ac182a27a70c5..3a33d4a14a734 100644 --- a/Framework/Core/src/WorkflowSerializationHelpers.cxx +++ b/Framework/Core/src/WorkflowSerializationHelpers.cxx @@ -507,9 +507,6 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler, case VariantType::LabeledArrayDouble: opt = std::make_unique(optionName, optionType, VariantJSONHelpers::read(is), HelpString{optionHelp}, optionKind); break; - case VariantType::LabeledArrayString: - opt = std::make_unique(optionName, optionType, VariantJSONHelpers::read(is), HelpString{optionHelp}, optionKind); - break; case VariantType::Dict: opt = std::make_unique(optionName, optionType, emptyDict(), HelpString{optionHelp}, optionKind); break; @@ -1194,7 +1191,6 @@ void WorkflowSerializationHelpers::dump(std::ostream& out, case VariantType::LabeledArrayInt: case VariantType::LabeledArrayFloat: case VariantType::LabeledArrayDouble: - case VariantType::LabeledArrayString: case VariantType::Dict: VariantJSONHelpers::write(oss, option.defaultValue); break; diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index 9f92f85038057..8651d25829963 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -1800,9 +1800,6 @@ int runStateMachine(DataProcessorSpecs const& workflow, case VariantType::LabeledArrayDouble: option.defaultValue = reg->get>(name); break; - case VariantType::LabeledArrayString: - option.defaultValue = reg->get>(name); - break; default: break; } diff --git a/Framework/Core/test/test_Variants.cxx b/Framework/Core/test/test_Variants.cxx index d774fe160885b..a5753e26925b3 100644 --- a/Framework/Core/test/test_Variants.cxx +++ b/Framework/Core/test/test_Variants.cxx @@ -218,20 +218,14 @@ TEST_CASE("Array2DTest") TEST_CASE("LabeledArrayTest") { float m[3][4] = {{0.1, 0.2, 0.3, 0.4}, {0.5, 0.6, 0.7, 0.8}, {0.9, 1.0, 1.1, 1.2}}; - std::string mS[3][4] = {{"a", "b", "c", "d"}, {"e", "f", "g", "h"}, {"i", "l", "m", "n"}}; std::string xl[] = {"c1", "c2", "c3", "c4"}; std::string yl[] = {"r1", "r2", "r3"}; LabeledArray laf{&m[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}}; - LabeledArray las{&mS[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}}; for (auto i = 0u; i < 3; ++i) { for (auto j = 0u; j < 4; ++j) { REQUIRE(laf.get(yl[i].c_str(), xl[j].c_str()) == laf.get(i, j)); REQUIRE(laf.get(i, xl[j].c_str()) == laf.get(i, j)); REQUIRE(laf.get(yl[i].c_str(), j) == laf.get(i, j)); - - REQUIRE(las.get(yl[i].c_str(), xl[j].c_str()) == las.get(i, j)); - REQUIRE(las.get(i, xl[j].c_str()) == las.get(i, j)); - REQUIRE(las.get(yl[i].c_str(), j) == las.get(i, j)); } } } From af8d16aba712908457587108b661b57033ef75a1 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 5 Sep 2023 15:17:36 +0200 Subject: [PATCH 037/324] DPL: have DPL callback last when FairMQ supports ordering --- Framework/Core/src/DataProcessingDevice.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index a5b492d24fba2..aa2bf66f77c94 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -172,7 +172,8 @@ DataProcessingDevice::DataProcessingDevice(RunningDeviceRef running, ServiceRegi } }; - this->SubscribeToStateChange("dpl", stateWatcher); + // 99 is to execute DPL callbacks last + this->SubscribeToStateChange("99-dpl", stateWatcher); // One task for now. mStreams.resize(1); From 0f163293a59ff251d11f998ece2e3570490336e7 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 31 Aug 2023 13:18:59 +0200 Subject: [PATCH 038/324] DPL: handle spurious messages when in READY state, take two --- Framework/Core/src/DataProcessingDevice.cxx | 4 ++ .../Core/src/ExternalFairMQDeviceProxy.cxx | 35 +++++++++- Framework/TestWorkflows/CMakeLists.txt | 4 ++ .../src/o2DeadlockReproducer.cxx | 66 +++++++++++++++++++ 4 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 Framework/TestWorkflows/src/o2DeadlockReproducer.cxx diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index aa2bf66f77c94..cf664a5e9fdeb 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -1502,6 +1502,10 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) if (info.channel == nullptr) { continue; } + // Only poll DPL channels for now. + if (info.channelType != ChannelAccountingType::DPL) { + continue; + } auto& socket = info.channel->GetSocket(); // If we have pending events from a previous iteration, // we do receive in any case. diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 9dc709bf5befc..941cd8873d438 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -467,11 +468,12 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, for (auto& channel : channels) { LOGP(detail, "Injecting channel '{}' into DPL configuration", channel); // Converter should pump messages + auto& channelPtr = services.get().device()->GetChannel(channel, 0); deviceState.inputChannelInfos.push_back(InputChannelInfo{ .state = InputChannelState::Running, .hasPendingEvents = false, .readPolled = false, - .channel = nullptr, + .channel = &channelPtr, .id = {ChannelIndex::INVALID}, .channelType = ChannelAccountingType::RAWFMQ, }); @@ -490,14 +492,39 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, } // We keep track of whether or not all channels have seen a new state. std::vector lastNewStatePending(deviceState.inputChannelInfos.size(), false); + uv_update_time(deviceState.loop); + auto start = uv_now(deviceState.loop); // Continue iterating until all channels have seen a new state. - while (std::all_of(lastNewStatePending.begin(), lastNewStatePending.end(), [](bool b) { return b; })) { + while (std::all_of(lastNewStatePending.begin(), lastNewStatePending.end(), [](bool b) { return b; }) != true) { + if (uv_now(deviceState.loop) - start > 5000) { + LOGP(info, "Timeout while draining messages, going to next state anyway."); + break; + } fair::mq::Parts parts; for (size_t ci = 0; ci < deviceState.inputChannelInfos.size(); ++ci) { auto& info = deviceState.inputChannelInfos[ci]; + // We only care about rawfmq channels. + if (info.channelType != ChannelAccountingType::RAWFMQ) { + lastNewStatePending[ci] = true; + continue; + } + // This means we have not set things up yet. I.e. the first iteration from + // ready to run has not happened yet. + if (info.channel == nullptr) { + lastNewStatePending[ci] = true; + continue; + } info.channel->Receive(parts, 10); - lastNewStatePending[ci] = device->NewStatePending(); + // Handle both cases of state changes: + // + // - The state has been changed from the outside and FairMQ knows about it. + // - The state has been changed from the GUI, and deviceState.nextFairMQState knows about it. + // + // This latter case is probably better handled from DPL itself, after all it's fair to + // assume we need to switch state as soon as the GUI notifies us. + // For now we keep it here to avoid side effects. + lastNewStatePending[ci] = device->NewStatePending() || (deviceState.nextFairMQState.empty() == false); if (parts.Size() == 0) { continue; } @@ -511,6 +538,8 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, info.readPolled = true; } } + // Keep state transitions going also when running with the standalone GUI. + uv_run(deviceState.loop, UV_RUN_NOWAIT); } }; diff --git a/Framework/TestWorkflows/CMakeLists.txt b/Framework/TestWorkflows/CMakeLists.txt index 1fae48e50364d..05c40f034b9d2 100644 --- a/Framework/TestWorkflows/CMakeLists.txt +++ b/Framework/TestWorkflows/CMakeLists.txt @@ -105,3 +105,7 @@ o2_add_dpl_workflow(test-ccdb-fetcher SOURCES src/test_CCDBFetcher.cxx PUBLIC_LINK_LIBRARIES O2::DataFormatsTOF O2::Framework COMPONENT_NAME TestWorkflows) + +add_executable(o2-test-deadlock src/o2DeadlockReproducer.cxx) +target_link_libraries(o2-test-deadlock PUBLIC FairMQ::FairMQ) +add_test(NAME o2-test-deadlock COMMAND o2-test-deadlock --channel-config "name=data,type=sub,method=bind,address=ipc://127.0.0.1,rateLogging=0" --id foo --transport zeromq --control static) diff --git a/Framework/TestWorkflows/src/o2DeadlockReproducer.cxx b/Framework/TestWorkflows/src/o2DeadlockReproducer.cxx new file mode 100644 index 0000000000000..196c448efe016 --- /dev/null +++ b/Framework/TestWorkflows/src/o2DeadlockReproducer.cxx @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include + +#include + +namespace bpo = boost::program_options; + +void addCustomOptions(bpo::options_description& options) +{ +} + +struct Deadlocked : fair::mq::Device { + Deadlocked() + { + auto stateWatcher = [this](fair::mq::State newState) { + static bool first = true; + LOG(info) << "State changed to " << newState; + if (newState != fair::mq::State::Ready) { + LOG(info) << "Not ready state, ignoring"; + return; + } + if (first) { + first = false; + return; + } + fair::mq::Parts parts; + LOG(info) << "Draining messages" << std::endl; + auto& channels = this->GetChannels(); + LOG(info) << "Number of channels: " << channels.size(); + if (channels.size() == 0) { + LOG(info) << "No messages to drain"; + return; + } + auto& channel = channels.at("data")[0]; + while (this->NewStatePending() == false) { + channel.Receive(parts, 10); + if (parts.Size() != 0) { + LOG(info) << "Draining" << parts.Size() << "messages"; + } + } + LOG(info) << "Done draining"; + }; + this->SubscribeToStateChange("99-drain", stateWatcher); + } + + void Run() override + { + LOG(info) << "Simply exit"; + } +}; + +std::unique_ptr getDevice(fair::mq::ProgOptions& /*config*/) +{ + return std::make_unique(); +} From a29acea4557e9e416c355c34a28274b29898f3b3 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 15 Sep 2023 22:38:39 +0200 Subject: [PATCH 039/324] Distinguish between ROOT_INPUT and DIGIT_ROOT_INPUT --- prodtests/full-system-test/dpl-workflow.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index b892d8b7a876f..5f0c585b2417c 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -441,9 +441,9 @@ fi has_detector_reco ITS && ! has_detector_from_global_reader ITS && add_W o2-its-reco-workflow "--trackerCA $ITS_CONFIG $DISABLE_MC $DISABLE_DIGIT_CLUSTER_INPUT $DISABLE_ROOT_OUTPUT --pipeline $(get_N its-tracker ITS REST 1 ITSTRK)" "$ITS_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" has_detector_reco FT0 && ! has_detector_from_global_reader FT0 && add_W o2-ft0-reco-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC --pipeline $(get_N ft0-reconstructor FT0 REST 1)" has_detector_reco TRD && ! has_detector_from_global_reader TRD && add_W o2-trd-tracklet-transformer "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TRD_FILTER_CONFIG --pipeline $(get_N TRDTRACKLETTRANSFORMER TRD REST 1 TRDTRKTRANS)" -has_detectors_reco ITS TPC && has_detector_matching ITSTPC && add_W o2-tpcits-match-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $SEND_ITSTPC_DTGL $TPC_CORR_SCALING --nthreads $ITSTPC_THREADS --pipeline $(get_N itstpc-track-matcher MATCH REST $ITSTPC_THREADS TPCITS)" "$ITSTPC_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" -has_detector_reco TRD && [[ ! -z "$TRD_SOURCES" ]] && add_W o2-trd-global-tracking "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TRD_CONFIG $TRD_FILTER_CONFIG $TPC_CORR_SCALING --track-sources $TRD_SOURCES --pipeline $(get_N trd-globaltracking_TPC_ITS-TPC_ TRD REST 1 TRDTRK),$(get_N trd-globaltracking_TPC_FT0_ITS-TPC_ TRD REST 1 TRDTRK)" "$TRD_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" -has_detector_reco TOF && [[ ! -z "$TOF_SOURCES" ]] && add_W o2-tof-matcher-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TPC_CORR_SCALING --track-sources $TOF_SOURCES --pipeline $(get_N tof-matcher TOF REST 1 TOFMATCH)" "$ITSMFT_STROBES;$ITSEXTRAERR" +has_detectors_reco ITS TPC && has_detector_matching ITSTPC && add_W o2-tpcits-match-workflow "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $SEND_ITSTPC_DTGL $TPC_CORR_SCALING --nthreads $ITSTPC_THREADS --pipeline $(get_N itstpc-track-matcher MATCH REST $ITSTPC_THREADS TPCITS)" "$ITSTPC_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" +has_detector_reco TRD && [[ ! -z "$TRD_SOURCES" ]] && add_W o2-trd-global-tracking "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TRD_CONFIG $TRD_FILTER_CONFIG $TPC_CORR_SCALING --track-sources $TRD_SOURCES --pipeline $(get_N trd-globaltracking_TPC_ITS-TPC_ TRD REST 1 TRDTRK),$(get_N trd-globaltracking_TPC_FT0_ITS-TPC_ TRD REST 1 TRDTRK)" "$TRD_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" +has_detector_reco TOF && [[ ! -z "$TOF_SOURCES" ]] && add_W o2-tof-matcher-workflow "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TPC_CORR_SCALING --track-sources $TOF_SOURCES --pipeline $(get_N tof-matcher TOF REST 1 TOFMATCH)" "$ITSMFT_STROBES;$ITSEXTRAERR" has_detectors TPC && [[ -z "$DISABLE_ROOT_OUTPUT" && "${SKIP_TPC_CLUSTERSTRACKS_OUTPUT:-}" != 1 ]] && add_W o2-tpc-reco-workflow "--input-type pass-through --output-type clusters,tracks,send-clusters-per-sector $DISABLE_MC" # --------------------------------------------------------------------------------------------------------------------- @@ -456,8 +456,8 @@ has_detector FV0 && ! has_detector_from_global_reader FV0 && has_processing_step has_detector ZDC && ! has_detector_from_global_reader ZDC && has_processing_step ZDC_RECO && add_W o2-zdc-digits-reco "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC" has_detector HMP && ! has_detector_from_global_reader HMP && has_processing_step HMP_RECO && add_W o2-hmpid-digits-to-clusters-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT --pipeline $(get_N HMP-Clusterization HMP REST 1 HMPCLUS)" has_detector HMP && ! has_detector_from_global_reader HMP && has_processing_step HMP_RECO && add_W o2-hmpid-matcher-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC" -has_detectors_reco MCH MID && has_detector_matching MCHMID && add_W o2-muon-tracks-matcher-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_MC $DISABLE_ROOT_OUTPUT --pipeline $(get_N muon-track-matcher MATCH REST 1)" -has_detectors_reco MFT MCH && has_detector_matching MFTMCH && add_W o2-globalfwd-matcher-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC --pipeline $(get_N globalfwd-track-matcher MATCH REST 1 FWDMATCH)" "$MFTMCHConf" +has_detectors_reco MCH MID && has_detector_matching MCHMID && add_W o2-muon-tracks-matcher-workflow "$DISABLE_ROOT_INPUT $DISABLE_MC $DISABLE_ROOT_OUTPUT --pipeline $(get_N muon-track-matcher MATCH REST 1)" +has_detectors_reco MFT MCH && has_detector_matching MFTMCH && add_W o2-globalfwd-matcher-workflow "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC --pipeline $(get_N globalfwd-track-matcher MATCH REST 1 FWDMATCH)" "$MFTMCHConf" # --------------------------------------------------------------------------------------------------------------------- # Reconstruction workflows needed only in case QC or CALIB was requested @@ -472,7 +472,7 @@ has_detectors_reco MFT MCH && has_detector_matching MFTMCH && add_W o2-globalfwd has_detector_reco TRD && ( [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output o2-trd-digittracklet-writer ) && ! has_detector_from_global_reader TRD && add_W o2-trd-digittracklet-writer has_detector_reco TPC && [[ "0${TPC_CONVERT_LINKZS_TO_RAW:-}" == "01" ]] && ( [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output o2-gpu-reco-workflow ) && ! has_detector_from_global_reader TPC && add_W o2-tpc-reco-workflow "--input-type digitizer --output-type digits $DISABLE_MC" has_detector_reco CPV && ( [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output o2-cpv-cluster-writer-workflow ) && ! has_detector_from_global_reader CPV && add_W o2-cpv-cluster-writer-workflow "$DISABLE_MC" -( workflow_has_parameter AOD || [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output o2-emcal-cell-writer-workflow ) && ! has_detector_from_global_reader EMC && has_detector EMC && add_W o2-emcal-cell-writer-workflow "--disable-mc --subspec 10 --cell-writer-name emcal-led-cells-writer --emcal-led-cells-writer \"--outfile emcledcells.root\"" +( workflow_has_parameter AOD || [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output o2-emcal-cell-writer-workflow ) && ! has_detector_from_global_reader EMC && has_detector EMC && add_W o2-emcal-cell-writer-workflow "$DISABLE_MC --subspec 10 --cell-writer-name emcal-led-cells-writer --emcal-led-cells-writer \"--outfile emcledcells.root\"" [[ $CTFINPUT == 1 ]] && has_detector CTP && ! has_detector_from_global_reader CTP && ( [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output o2-ctp-digit-writer ) && add_W o2-ctp-digit-writer "$DISABLE_ROOT_OUTPUT" has_detector_reco EMC && ( [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output o2-emcal-cell-writer-workflow ) && ! has_detector_from_global_reader EMC && add_W o2-emcal-cell-writer-workflow "$DISABLE_MC" has_detector_reco PHS && ( [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output o2-phos-cell-writer-workflow ) && ! has_detector_from_global_reader PHS && add_W o2-phos-cell-writer-workflow "$DISABLE_MC" @@ -484,12 +484,12 @@ has_detector_reco MCH && ( [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output # always run vertexing if requested and if there are some sources, but in cosmic mode we work in pass-trough mode (create record for non-associated tracks) ( [[ $BEAMTYPE == "cosmic" ]] || ! has_detector_reco ITS) && PVERTEX_CONFIG+=" --skip" -has_detector_matching PRIMVTX && [[ ! -z "$VERTEXING_SOURCES" ]] && add_W o2-primary-vertexing-workflow "$DISABLE_MC $DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $PVERTEX_CONFIG --pipeline $(get_N primary-vertexing MATCH REST 1 PRIMVTX),$(get_N pvertex-track-matching MATCH REST 1 PRIMVTXMATCH)" "${PVERTEXING_CONFIG_KEY}" +has_detector_matching PRIMVTX && [[ ! -z "$VERTEXING_SOURCES" ]] && add_W o2-primary-vertexing-workflow "$DISABLE_MC $DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $PVERTEX_CONFIG --pipeline $(get_N primary-vertexing MATCH REST 1 PRIMVTX),$(get_N pvertex-track-matching MATCH REST 1 PRIMVTXMATCH)" "${PVERTEXING_CONFIG_KEY}" if [[ $BEAMTYPE != "cosmic" ]]; then : ${STRTRACKING:="--disable-strangeness-tracker"} has_detectors_reco ITS && has_detector_matching SECVTX && has_detector_matching && STRTRACKING="" - has_detectors_reco ITS && has_detector_matching SECVTX && [[ ! -z "$SVERTEXING_SOURCES" ]] && add_W o2-secondary-vertexing-workflow "$DISABLE_MC $STRTRACKING $DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $TPC_CORR_SCALING --vertexing-sources $SVERTEXING_SOURCES --threads $SVERTEX_THREADS --pipeline $(get_N secondary-vertexing MATCH REST $SVERTEX_THREADS SECVTX)" + has_detectors_reco ITS && has_detector_matching SECVTX && [[ ! -z "$SVERTEXING_SOURCES" ]] && add_W o2-secondary-vertexing-workflow "$DISABLE_MC $STRTRACKING $DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $TPC_CORR_SCALING --vertexing-sources $SVERTEXING_SOURCES --threads $SVERTEX_THREADS --pipeline $(get_N secondary-vertexing MATCH REST $SVERTEX_THREADS SECVTX)" fi # --------------------------------------------------------------------------------------------------------------------- @@ -541,7 +541,7 @@ workflow_has_parameters CALIB CALIB_LOCAL_INTEGRATED_AGGREGATOR && { source ${CA # RS this is a temporary setting : ${ED_TRACKS:=$TRACK_SOURCES} : ${ED_CLUSTERS:=$TRACK_SOURCES} -workflow_has_parameter EVENT_DISPLAY && [[ $NUMAID == 0 ]] && [[ ! -z "$ED_TRACKS" ]] && [[ ! -z "$ED_CLUSTERS" ]] && add_W o2-eve-export-workflow "--display-tracks $ED_TRACKS --display-clusters $ED_CLUSTERS --skipOnEmptyInput $DISABLE_DIGIT_ROOT_INPUT --number-of_tracks 50000 $EVE_CONFIG $DISABLE_MC" "$ITSMFT_STROBES" +workflow_has_parameter EVENT_DISPLAY && [[ $NUMAID == 0 ]] && [[ ! -z "$ED_TRACKS" ]] && [[ ! -z "$ED_CLUSTERS" ]] && add_W o2-eve-export-workflow "--display-tracks $ED_TRACKS --display-clusters $ED_CLUSTERS --skipOnEmptyInput $DISABLE_ROOT_INPUT --number-of_tracks 50000 $EVE_CONFIG $DISABLE_MC" "$ITSMFT_STROBES" workflow_has_parameter GPU_DISPLAY && [[ $NUMAID == 0 ]] && add_W o2-gpu-display "${ED_TRACKS+--display-tracks} $ED_TRACKS ${ED_CLUSTERS+--display-clusters} $ED_CLUSTERS" @@ -552,7 +552,7 @@ workflow_has_parameter GPU_DISPLAY && [[ $NUMAID == 0 ]] && add_W o2-gpu-display ( ! has_detector_matching SECVTX || ! has_detectors_reco ITS || [[ $BEAMTYPE == "cosmic" ]]) && AODPROD_OPT+=" --disable-secondary-vertices" ( ! has_detector_matching STRK || ! has_detector_matching SECVTX || ! has_detectors_reco ITS || [[ $BEAMTYPE == "cosmic" ]]) && AODPROD_OPT+=" --disable-strangeness-tracking" -workflow_has_parameter AOD && [[ ! -z "$AOD_INPUT" ]] && add_W o2-aod-producer-workflow "$AODPROD_OPT --info-sources $AOD_INPUT $DISABLE_DIGIT_ROOT_INPUT --aod-writer-keep dangling --aod-writer-resfile \"AO2D\" --aod-writer-resmode UPDATE $DISABLE_MC --pipeline $(get_N aod-producer-workflow AOD REST 1 AODPROD)" +workflow_has_parameter AOD && [[ ! -z "$AOD_INPUT" ]] && add_W o2-aod-producer-workflow "$AODPROD_OPT --info-sources $AOD_INPUT $DISABLE_ROOT_INPUT --aod-writer-keep dangling --aod-writer-resfile \"AO2D\" --aod-writer-resmode UPDATE $DISABLE_MC --pipeline $(get_N aod-producer-workflow AOD REST 1 AODPROD)" # --------------------------------------------------------------------------------------------------------------------- # Quality Control From a8fe37bb8d8b5a88c82f7b36f868444218c0dacd Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 15 Sep 2023 23:23:04 +0200 Subject: [PATCH 040/324] rANS: throw compile error if exposed to ROOT --- .../Common/include/DetectorsCommonDataFormats/EncodedBlocks.h | 1 - Utilities/rANS/include/rANS/compat.h | 4 ++++ Utilities/rANS/include/rANS/decode.h | 4 ++++ Utilities/rANS/include/rANS/encode.h | 4 ++++ Utilities/rANS/include/rANS/factory.h | 4 ++++ Utilities/rANS/include/rANS/histogram.h | 4 ++++ Utilities/rANS/include/rANS/iterator.h | 4 ++++ Utilities/rANS/include/rANS/metrics.h | 4 ++++ Utilities/rANS/include/rANS/pack.h | 4 ++++ Utilities/rANS/include/rANS/serialize.h | 4 ++++ Utilities/rANS/include/rANS/utils.h | 4 ++++ 11 files changed, 40 insertions(+), 1 deletion(-) diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index 7f2db5cedffc9..b43f978f3341c 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -39,7 +39,6 @@ #include "rANS/serialize.h" #include "rANS/factory.h" #include "rANS/metrics.h" -#include "rANS/serialize.h" #include "rANS/utils.h" #endif diff --git a/Utilities/rANS/include/rANS/compat.h b/Utilities/rANS/include/rANS/compat.h index f94be92bed472..a4917246eb455 100644 --- a/Utilities/rANS/include/rANS/compat.h +++ b/Utilities/rANS/include/rANS/compat.h @@ -16,6 +16,10 @@ #ifndef RANS_COMPAT_H_ #define RANS_COMPAT_H_ +#ifdef __CLING__ +#error rANS should not be exposed to root +#endif + #include #include "rANS/internal/common/typetraits.h" diff --git a/Utilities/rANS/include/rANS/decode.h b/Utilities/rANS/include/rANS/decode.h index f98d746276ce6..df42560d8e122 100644 --- a/Utilities/rANS/include/rANS/decode.h +++ b/Utilities/rANS/include/rANS/decode.h @@ -16,6 +16,10 @@ #ifndef RANS_DECODE_H_ #define RANS_DECODE_H_ +#ifdef __CLING__ +#error rANS should not be exposed to root +#endif + #include "rANS/internal/containers/DenseSymbolTable.h" #include "rANS/internal/containers/Symbol.h" #include "rANS/internal/decode/Decoder.h" diff --git a/Utilities/rANS/include/rANS/encode.h b/Utilities/rANS/include/rANS/encode.h index a62fe1121db90..42b79b030ce39 100644 --- a/Utilities/rANS/include/rANS/encode.h +++ b/Utilities/rANS/include/rANS/encode.h @@ -16,6 +16,10 @@ #ifndef RANS_ENCODE_H_ #define RANS_ENCODE_H_ +#ifdef __CLING__ +#error rANS should not be exposed to root +#endif + #include "rANS/internal/containers/DenseSymbolTable.h" #include "rANS/internal/containers/Symbol.h" #include "rANS/internal/encode/Encoder.h" diff --git a/Utilities/rANS/include/rANS/factory.h b/Utilities/rANS/include/rANS/factory.h index 549031ae8ecdb..602d3c5879887 100644 --- a/Utilities/rANS/include/rANS/factory.h +++ b/Utilities/rANS/include/rANS/factory.h @@ -16,6 +16,10 @@ #ifndef RANS_FACTORY_H_ #define RANS_FACTORY_H_ +#ifdef __CLING__ +#error rANS should not be exposed to root +#endif + #include "rANS/internal/common/defaults.h" #include "rANS/internal/common/typetraits.h" #include "rANS/internal/common/codertraits.h" diff --git a/Utilities/rANS/include/rANS/histogram.h b/Utilities/rANS/include/rANS/histogram.h index 1c5263495d139..5815fdd45bd1d 100644 --- a/Utilities/rANS/include/rANS/histogram.h +++ b/Utilities/rANS/include/rANS/histogram.h @@ -16,6 +16,10 @@ #ifndef RANS_HISTOGRAM_H_ #define RANS_HISTOGRAM_H_ +#ifdef __CLING__ +#error rANS should not be exposed to root +#endif + #include "rANS/internal/containers/DenseHistogram.h" #include "rANS/internal/containers/AdaptiveHistogram.h" #include "rANS/internal/containers/SparseHistogram.h" diff --git a/Utilities/rANS/include/rANS/iterator.h b/Utilities/rANS/include/rANS/iterator.h index 32e0df1206150..64224f9c77c30 100644 --- a/Utilities/rANS/include/rANS/iterator.h +++ b/Utilities/rANS/include/rANS/iterator.h @@ -16,6 +16,10 @@ #ifndef RANS_ITERATOR_H_ #define RANS_ITERATOR_H_ +#ifdef __CLING__ +#error rANS should not be exposed to root +#endif + #include "rANS/internal/transform/iterator.h" #endif /* RANS_ITERATOR_H_ */ diff --git a/Utilities/rANS/include/rANS/metrics.h b/Utilities/rANS/include/rANS/metrics.h index 8fc251a9b9e25..6ab246fee8206 100644 --- a/Utilities/rANS/include/rANS/metrics.h +++ b/Utilities/rANS/include/rANS/metrics.h @@ -16,6 +16,10 @@ #ifndef RANS_METRICS_H_ #define RANS_METRICS_H_ +#ifdef __CLING__ +#error rANS should not be exposed to root +#endif + #include "rANS/internal/metrics/Metrics.h" #include "rANS/internal/metrics/properties.h" #include "rANS/internal/metrics/SizeEstimate.h" diff --git a/Utilities/rANS/include/rANS/pack.h b/Utilities/rANS/include/rANS/pack.h index 342338cdff7ed..cfa68a2e019c4 100644 --- a/Utilities/rANS/include/rANS/pack.h +++ b/Utilities/rANS/include/rANS/pack.h @@ -16,6 +16,10 @@ #ifndef RANS_PACK_H_ #define RANS_PACK_H_ +#ifdef __CLING__ +#error rANS should not be exposed to root +#endif + #include "rANS/internal/containers/BitPtr.h" #include "rANS/internal/metrics/Metrics.h" #include "rANS/internal/pack/pack.h" diff --git a/Utilities/rANS/include/rANS/serialize.h b/Utilities/rANS/include/rANS/serialize.h index 346a5eaa08fc9..5a46df196fd41 100644 --- a/Utilities/rANS/include/rANS/serialize.h +++ b/Utilities/rANS/include/rANS/serialize.h @@ -16,6 +16,10 @@ #ifndef RANS_SERIALIZE_H_ #define RANS_SERIALIZE_H_ +#ifdef __CLING__ +#error rANS should not be exposed to root +#endif + #include #include #include diff --git a/Utilities/rANS/include/rANS/utils.h b/Utilities/rANS/include/rANS/utils.h index e4412349a9120..cea058341f921 100644 --- a/Utilities/rANS/include/rANS/utils.h +++ b/Utilities/rANS/include/rANS/utils.h @@ -16,6 +16,10 @@ #ifndef RANS_UTILS_H_ #define RANS_UTILS_H_ +#ifdef __CLING__ +#error rANS should not be exposed to root +#endif + #include #include #include From c954049480b6378fa9a8f2d1cc01bf145cb94188 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 15 Sep 2023 23:33:26 +0200 Subject: [PATCH 041/324] Do not expose rANS to ROOT --- .../DetectorsCommonDataFormats/EncodedBlocks.h | 10 +++++++--- .../internal/ExternalEntropyCoder.h | 1 - .../DetectorsCommonDataFormats/internal/Packer.h | 16 ++++++++++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index b43f978f3341c..13cd7d2b122d5 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -29,11 +29,11 @@ #include "DetectorsCommonDataFormats/CTFDictHeader.h" #include "DetectorsCommonDataFormats/CTFIOSize.h" #include "DetectorsCommonDataFormats/ANSHeader.h" -#include "DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h" -#include "DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h" #include "DetectorsCommonDataFormats/internal/Packer.h" #include "DetectorsCommonDataFormats/Metadata.h" #ifndef __CLING__ +#include "DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h" +#include "DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h" #include "rANS/compat.h" #include "rANS/histogram.h" #include "rANS/serialize.h" @@ -485,8 +485,10 @@ class EncodedBlocks template , bool> = true> o2::ctf::CTFIOSize decode(D_IT dest, int slot, const std::any& decoderExt = {}) const; +#ifndef __CLING__ /// create a special EncodedBlocks containing only dictionaries made from provided vector of frequency tables static std::vector createDictionaryBlocks(const std::vector>& vfreq, const std::vector& prbits); +#endif /// print itself void print(const std::string& prefix = "", int verbosity = 1) const; @@ -572,6 +574,7 @@ class EncodedBlocks template o2::ctf::CTFIOSize encodeRANSV1Inplace(const input_IT srcBegin, const input_IT srcEnd, int slot, Metadata::OptStore opt, buffer_T* buffer = nullptr, double_t sizeEstimateSafetyFactor = 1); +#ifndef __CLING__ template o2::ctf::CTFIOSize pack(const input_IT srcBegin, const input_IT srcEnd, int slot, rans::Metrics::value_type> metrics, buffer_T* buffer = nullptr); @@ -592,6 +595,7 @@ class EncodedBlocks return pack(srcBegin, srcEnd, slot, metrics, buffer); } +#endif template o2::ctf::CTFIOSize store(const input_IT srcBegin, const input_IT srcEnd, int slot, Metadata::OptStore opt, buffer_T* buffer = nullptr); @@ -1406,7 +1410,6 @@ CTFIOSize EncodedBlocks::encodeRANSV1Inplace(const input_IT srcBegin, c return {0, thisMetadata->getUncompressedSize(), thisMetadata->getCompressedSize()}; }; // namespace ctf -#endif template template @@ -1486,6 +1489,7 @@ std::vector EncodedBlocks::createDictionaryBlocks(const std::vect } return vdict; } +#endif template void EncodedBlocks::dump(const std::string& prefix, int ncol) const diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h index b2cbed1cd27f9..6a8be509c021c 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h @@ -35,7 +35,6 @@ class ExternalEntropyCoder public: using source_type = source_T; using encoder_type = typename rans::denseEncoder_type; - using metrics_type = rans::Metrics; ExternalEntropyCoder(const encoder_type& encoder); diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/Packer.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/Packer.h index 72f62e3245797..fa11e9f6dac6d 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/Packer.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/Packer.h @@ -16,8 +16,10 @@ #ifndef ALICEO2_PACKER_H_ #define ALICEO2_PACKER_H_ +#ifndef __CLING__ #include "rANS/pack.h" #include "rANS/metrics.h" +#endif namespace o2::ctf::internal { @@ -29,9 +31,10 @@ class Packer using source_type = source_T; Packer() = default; - +#ifndef __CLING__ explicit Packer(rans::Metrics& metrics) : mOffset{metrics.getDatasetProperties().min}, mPackingWidth{metrics.getDatasetProperties().alphabetRangeBits} {}; +#endif template Packer(source_IT srcBegin, source_IT srcEnd); @@ -58,6 +61,7 @@ template template Packer::Packer(source_IT srcBegin, source_IT srcEnd) { +#ifndef __CLING__ static_assert(rans::utils::isCompatibleIter_v); if (srcBegin != srcEnd) { @@ -73,13 +77,18 @@ Packer::Packer(source_IT srcBegin, source_IT srcEnd) mOffset = min; mPackingWidth = rans::utils::getRangeBits(min, max); } +#endif }; template template [[nodiscard]] inline size_t Packer::getPackingBufferSize(size_t messageLength) const noexcept { +#ifndef __CLING__ return rans::computePackingBufferSize(messageLength, mPackingWidth); +#else + return 0; +#endif }; template @@ -99,12 +108,15 @@ template if (extent == 0) { return dstBegin; } - +#ifndef __CLING__ rans::BitPtr packEnd = rans::pack(srcBegin, extent, dstBegin, mPackingWidth, mOffset); auto* end = packEnd.toPtr(); ++end; // one past end iterator; rans::utils::checkBounds(end, dstEnd); return end; +#else + return nullptr; +#endif }; } // namespace o2::ctf::internal From fdcca1a916eaa8a71c1b93cccce4f510bc1ee86e Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 28 Aug 2023 23:11:27 +0200 Subject: [PATCH 042/324] DPL: fix warning --- Framework/AODMerger/src/aodMerger.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Framework/AODMerger/src/aodMerger.cxx b/Framework/AODMerger/src/aodMerger.cxx index 8edaefb5efb2c..363350882caaa 100644 --- a/Framework/AODMerger/src/aodMerger.cxx +++ b/Framework/AODMerger/src/aodMerger.cxx @@ -26,6 +26,7 @@ #include #include "aodMerger.h" +#include // AOD merger with correct index rewriting // No need to know the datamodel because the branch names follow a canonical standard (identified by fIndex) @@ -450,7 +451,7 @@ int main(int argc, char* argv[]) } if (totalCompressed > 0 && totalUncompressed > 0) { for (auto const& tree : sizeCompressed) { - printf(" Tree %20s | Compressed: %12llu (%2.0f%%) | Uncompressed: %12llu (%2.0f%%)\n", tree.first.c_str(), tree.second, 100.0 * tree.second / totalCompressed, sizeUncompressed[tree.first], 100.0 * sizeUncompressed[tree.first] / totalUncompressed); + printf(" Tree %20s | Compressed: %12" PRIu64 " (%2.0f%%) | Uncompressed: %12" PRIu64 " (%2.0f%%)\n", tree.first.c_str(), tree.second, 100.0 * tree.second / totalCompressed, sizeUncompressed[tree.first], 100.0 * sizeUncompressed[tree.first] / totalUncompressed); } } } From fecb892d0ba9b792e47100031911c6da527073a0 Mon Sep 17 00:00:00 2001 From: Laurent Aphecetche Date: Wed, 13 Sep 2023 18:01:51 +0200 Subject: [PATCH 043/324] MCH: do not use sporadic for StatusMap just could not make it work ... --- Detectors/MUON/MCH/DigitFiltering/src/DigitFilteringSpec.cxx | 1 - Detectors/MUON/MCH/Status/src/StatusMapCreatorSpec.cxx | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Detectors/MUON/MCH/DigitFiltering/src/DigitFilteringSpec.cxx b/Detectors/MUON/MCH/DigitFiltering/src/DigitFilteringSpec.cxx index 31e9a1772425d..ea173bd1fc7cc 100644 --- a/Detectors/MUON/MCH/DigitFiltering/src/DigitFilteringSpec.cxx +++ b/Detectors/MUON/MCH/DigitFiltering/src/DigitFilteringSpec.cxx @@ -193,7 +193,6 @@ framework::DataProcessorSpec bool useStatusMap = DigitFilterParam::Instance().statusMask != 0; if (useStatusMap) { - // input += ";statusmap:MCH/STATUSMAP/0?lifetime=sporadic"; input += ";statusmap:MCH/STATUSMAP/0"; } diff --git a/Detectors/MUON/MCH/Status/src/StatusMapCreatorSpec.cxx b/Detectors/MUON/MCH/Status/src/StatusMapCreatorSpec.cxx index 377c7179bbad1..cd7422ee05ab5 100644 --- a/Detectors/MUON/MCH/Status/src/StatusMapCreatorSpec.cxx +++ b/Detectors/MUON/MCH/Status/src/StatusMapCreatorSpec.cxx @@ -96,6 +96,9 @@ class StatusMapCreatorTask LOGP(info, "Sending updated StatusMap of size {}", size(mStatusMap)); pc.outputs().snapshot(OutputRef{"statusmap"}, mStatusMap); mStatusMapUpdated = false; + } else { + LOGP(info, "Sending unchanged StatusMap of size {}", size(mStatusMap)); + pc.outputs().snapshot(OutputRef{"statusmap"}, mStatusMap); } } @@ -122,7 +125,7 @@ framework::DataProcessorSpec getStatusMapCreatorSpec(std::string_view specName) input += "rejectlist:MCH/REJECTLIST/0?lifetime=condition&ccdb-path=MCH/Calib/RejectList"; } - std::string output = "statusmap:MCH/STATUSMAP/0?lifetime=sporadic"; + std::string output = "statusmap:MCH/STATUSMAP/0"; std::vector outputs; auto matchers = select(output.c_str()); From e3d5dfc984a4494446a0ea2c0d310ed48e1de197 Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Thu, 20 Jul 2023 19:57:31 +0200 Subject: [PATCH 044/324] TPC SpaceCharge: add scaling of sc density per stack and IFC models - Adding function to add the boundary potential from other space-charge objects to be able to get the combined model from single models - Adding function to scale the space-charge density for single stacks. This can be used to emulate the impact on the distortions of IBF variations across chambers - Adding some functions which can be used with the Python interface - Adding functions for the inner field cage charging up effect - Fixing some small bugs --- .../include/TPCSpaceCharge/DataContainer3D.h | 1 + .../include/TPCSpaceCharge/SpaceCharge.h | 29 ++- .../TPC/spacecharge/src/DataContainer3D.cxx | 7 + Detectors/TPC/spacecharge/src/SpaceCharge.cxx | 193 +++++++++++++++++- 4 files changed, 219 insertions(+), 11 deletions(-) diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/DataContainer3D.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/DataContainer3D.h index 9c457141e5cee..79400c3d3d214 100644 --- a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/DataContainer3D.h +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/DataContainer3D.h @@ -189,6 +189,7 @@ struct DataContainer3D { /// operator overload DataContainer3D& operator*=(const DataT value); DataContainer3D& operator+=(const DataContainer3D& other); + DataContainer3D& operator*=(const DataContainer3D& other); DataContainer3D& operator-=(const DataContainer3D& other); private: diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h index 62109f009e436..014be1f2cc50e 100644 --- a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h @@ -180,6 +180,14 @@ class SpaceCharge /// \param formulaStruct struct containing a method to evaluate the potential void setPotentialBoundaryFromFormula(const AnalyticalFields& formulaStruct); + /// adding the boundary potential from other sc object which same number of vertices! + /// \param other other SC object which boundary potential witll be added + /// \param scaling sclaing factor which used to scale the others boundary potential + void addBoundaryPotential(const SpaceCharge& other, const Side side, const float scaling = 1); + + /// setting the boundary potential to 0 for zzMax + void resetBoundaryPotentialToZeroInRangeZ(float zMin, float zMax, const Side side); + /// step 0: this function fills the potential using an analytical formula /// \param formulaStruct struct containing a method to evaluate the potential void setPotentialFromFormula(const AnalyticalFields& formulaStruct); @@ -292,6 +300,9 @@ class SpaceCharge /// \param scalingFactor scaling factor for the space-charge density void scaleChargeDensitySector(const float scalingFactor, const Sector sector); + /// scaling the space-charge density for given stack + void scaleChargeDensityStack(const float scalingFactor, const Sector sector, const GEMstack stack); + /// add space charge density from other object (this.mDensity = this.mDensity + other.mDensity) /// \param otherSC other space-charge object, which charge will be added to current object void addChargeDensity(const SpaceCharge& otherSC); @@ -320,6 +331,9 @@ class SpaceCharge template > void calcGlobalCorrections(const Fields& formulaStruct, const int type = 3); + /// calculate the global corrections using the electric fields (interface for python) + void calcGlobalCorrectionsEField(const Side side, const int type = 3) { calcGlobalCorrections(getElectricFieldsInterpolator(side), type); } + /// step 5: calculate global distortions by using the electric field or the local distortions (SLOW) /// \param formulaStruct struct containing a method to evaluate the electric field Er, Ez, Ephi or the local distortions /// \param maxIterations maximum steps which are are performed to reach the central electrode (in general this is not necessary, but in case of problems this value aborts the calculation) @@ -372,6 +386,9 @@ class SpaceCharge /// \param phi global phi coordinate DataT getPotentialCyl(const DataT z, const DataT r, const DataT phi, const Side side) const; + /// get the potential for list of given coordinate + std::vector getPotentialCyl(const std::vector& z, const std::vector& r, const std::vector& phi, const Side side) const; + /// get the electric field for given coordinate /// \param z global z coordinate /// \param r global r coordinate @@ -1112,11 +1129,19 @@ class SpaceCharge /// \param deltaPot delta potential which will be set at the copper rod void setDeltaVoltageRotatedClipOFC(const float deltaPot, const Side side, const int sector) { initRodAlignmentVoltages(MisalignmentType::RotatedClip, FCType::OFC, sector, side, deltaPot); } + /// IFC charge up: set a linear rising delta potential from the CE to given z + /// \param deltaPot maximum value of the delta potential in V + /// \param zMaxDeltaPot z position where the maximum delta potential of deltaPot will be set + /// \param type functional form of the delta potential: 0=linear, 1= 1/x, 2=flat, 3=linear falling, 4=flat no z dependence + /// \param zStart usually at 0 to start the rising of the potential at the IFC + void setIFCChargeUpRisingPot(const float deltaPot, const float zMaxDeltaPot, const int type, const float zStart, const float offs, const Side side); + /// IFC charge up: set a linear rising delta potential from the CE to given z position which falls linear down to 0 at the readout /// \param deltaPot maximum value of the delta potential in V - /// \param cutOff set the delta potential to 0 for z>zMaxDeltaPot /// \param zMaxDeltaPot z position where the maximum delta potential of deltaPot will be set - void setIFCChargeUpLinear(const float deltaPot, const float zMaxDeltaPot, const bool cutOff, const Side side); + /// \param type function which is used to set falling potential: 0=linear falling off, 1=1/x falling off, 2=1/x steeply falling, 3=linear with offset + /// \param offs if offs != 0 the potential doesnt fall to 0. E.g. deltaPot=400V and offs=-10V -> Potential falls from 400V at zMaxDeltaPot to -10V at z=250cm + void setIFCChargeUpFallingPot(const float deltaPot, const float zMaxDeltaPot, const int type, const float zEnd, const float offs, const Side side); /// setting the global corrections directly from input function provided in global coordinates /// \param gCorr function returning global corrections for given global coordinate diff --git a/Detectors/TPC/spacecharge/src/DataContainer3D.cxx b/Detectors/TPC/spacecharge/src/DataContainer3D.cxx index c3ca2cbe75b11..c9a39e940873d 100644 --- a/Detectors/TPC/spacecharge/src/DataContainer3D.cxx +++ b/Detectors/TPC/spacecharge/src/DataContainer3D.cxx @@ -247,6 +247,13 @@ DataContainer3D& DataContainer3D::operator-=(const DataContainer3D return *this; } +template +DataContainer3D& DataContainer3D::operator*=(const DataContainer3D& other) +{ + std::transform(mData.begin(), mData.end(), other.mData.begin(), mData.begin(), std::multiplies<>()); + return *this; +} + template size_t DataContainer3D::getIndexZ(size_t index, const int nz, const int nr, const int nphi) { diff --git a/Detectors/TPC/spacecharge/src/SpaceCharge.cxx b/Detectors/TPC/spacecharge/src/SpaceCharge.cxx index 96e86853deae5..3ed00345159bc 100644 --- a/Detectors/TPC/spacecharge/src/SpaceCharge.cxx +++ b/Detectors/TPC/spacecharge/src/SpaceCharge.cxx @@ -1290,7 +1290,8 @@ void SpaceCharge::calcGlobalDistortions(const Fields& formulaStruct, cons } const DataT z0Tmp = z0 + dzDist + iter * stepSize; // starting z position - if (getSide(z0Tmp) != side) { + // do not do check for first iteration + if ((getSide(z0Tmp) != side) && iter) { LOGP(error, "Aborting calculation of distortions for iZ: {}, iR: {}, iPhi: {} due to change in the sides!", iZ, iR, iPhi); break; } @@ -1561,6 +1562,18 @@ DataT SpaceCharge::getPotentialCyl(const DataT z, const DataT r, const Da return mInterpolatorPotential[side](z, r, phi); } +template +std::vector SpaceCharge::getPotentialCyl(const std::vector& z, const std::vector& r, const std::vector& phi, const Side side) const +{ + const auto nPoints = z.size(); + std::vector potential(nPoints); +#pragma omp parallel for num_threads(sNThreads) + for (size_t i = 0; i < nPoints; ++i) { + potential[i] = getPotentialCyl(z[i], r[i], phi[i], side); + } + return potential; +} + template void SpaceCharge::getElectricFieldsCyl(const DataT z, const DataT r, const DataT phi, const Side side, DataT& eZ, DataT& eR, DataT& ePhi) const { @@ -1607,7 +1620,7 @@ void SpaceCharge::getCorrectionsCyl(const std::vector& z, const st corrRPhi.resize(nPoints); #pragma omp parallel for num_threads(sNThreads) for (size_t i = 0; i < nPoints; ++i) { - getLocalCorrectionsCyl(z[i], r[i], phi[i], side, corrZ[i], corrR[i], corrRPhi[i]); + getCorrectionsCyl(z[i], r[i], phi[i], side, corrZ[i], corrR[i], corrRPhi[i]); } } @@ -3296,19 +3309,156 @@ void SpaceCharge::initRodAlignmentVoltages(const MisalignmentType misalig } template -void SpaceCharge::setIFCChargeUpLinear(const float deltaPot, const float zMaxDeltaPot, const bool cutOff, const Side side) +void SpaceCharge::addBoundaryPotential(const SpaceCharge& other, const Side side, const float scaling) +{ + if (other.mPotential[side].getData().empty()) { + LOGP(info, "Other space-charge object is empty!"); + return; + } + + if ((mParamGrid.NRVertices != other.mParamGrid.NRVertices) || (mParamGrid.NZVertices != other.mParamGrid.NZVertices) || (mParamGrid.NPhiVertices != other.mParamGrid.NPhiVertices)) { + LOGP(info, "Different number of vertices found in input file. Initializing new space charge object with nR {} nZ {} nPhi {} vertices", other.mParamGrid.NRVertices, other.mParamGrid.NZVertices, other.mParamGrid.NPhiVertices); + SpaceCharge scTmp(mBField.getBField(), other.mParamGrid.NZVertices, other.mParamGrid.NRVertices, other.mParamGrid.NPhiVertices, false); + scTmp.mC0 = mC0; + scTmp.mC1 = mC1; + scTmp.mC2 = mC2; + *this = std::move(scTmp); + } + + initContainer(mPotential[side], true); + + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + for (size_t iZ = 1; iZ < mParamGrid.NZVertices; ++iZ) { + const size_t iRFirst = 0; + mPotential[side](iZ, iRFirst, iPhi) += scaling * other.mPotential[side](iZ, iRFirst, iPhi); + + const size_t iRLast = mParamGrid.NRVertices - 1; + mPotential[side](iZ, iRLast, iPhi) += scaling * other.mPotential[side](iZ, iRLast, iPhi); + } + } + + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + const size_t iZFirst = 0; + mPotential[side](iZFirst, iR, iPhi) += scaling * other.mPotential[side](iZFirst, iR, iPhi); + + const size_t iZLast = mParamGrid.NZVertices - 1; + mPotential[side](iZLast, iR, iPhi) += scaling * other.mPotential[side](iZLast, iR, iPhi); + } + } +} + +template +void SpaceCharge::resetBoundaryPotentialToZeroInRangeZ(float zMin, float zMax, const Side side) { - std::function chargeUpIFCLinear = [cutOff, zMax = getZMax(Side::A), deltaPot, zMaxDeltaPot](const DataT z) { + const float zMaxAbs = std::abs(zMax); + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + for (size_t iZ = 1; iZ < mParamGrid.NZVertices; ++iZ) { + const DataT z = std::abs(getZVertex(iZ, side)); + if ((z < zMin) || (z > zMax)) { + const size_t iRFirst = 0; + mPotential[side](iZ, iRFirst, iPhi) = 0; + + const size_t iRLast = mParamGrid.NRVertices - 1; + mPotential[side](iZ, iRLast, iPhi) = 0; + } + } + } + + for (size_t iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { + for (size_t iR = 0; iR < mParamGrid.NRVertices; ++iR) { + const size_t iZFirst = 0; + const float zFirst = std::abs(getZVertex(iZFirst, side)); + if ((zFirst < zMin) || (zFirst > zMax)) { + mPotential[side](iZFirst, iR, iPhi) = 0; + } + + const size_t iZLast = mParamGrid.NZVertices - 1; + const float zLast = std::abs(getZVertex(iZLast, side)); + if ((zLast < zMin) || (zLast > zMax)) { + mPotential[side](iZLast, iR, iPhi) = 0; + } + } + } +} + +template +void SpaceCharge::setIFCChargeUpRisingPot(const float deltaPot, const float zMaxDeltaPot, const int type, const float zStart, const float offs, const Side side) +{ + std::function chargeUpIFCLinear = [zStart, type, offs, deltaPot, zMaxDeltaPot](const DataT z) { const float absZ = std::abs(z); const float absZMaxDeltaPot = std::abs(zMaxDeltaPot); - if (absZ <= absZMaxDeltaPot) { - return static_cast(deltaPot / absZMaxDeltaPot * absZ); + if ((absZ <= absZMaxDeltaPot) && (absZ >= zStart)) { + // 1/x + if (type == 1) { + const float offsZ = 1; + const float zMaxDeltaPotTmp = zMaxDeltaPot - zStart + offsZ; + const float p1 = deltaPot / (1 / offsZ - 1 / zMaxDeltaPotTmp); + const float p2 = -p1 / zMaxDeltaPotTmp; + const float absZShifted = zMaxDeltaPotTmp - (absZ - zStart); + DataT pot = p2 + p1 / absZShifted; + return pot; + } else if (type == 0 || type == 4) { + // linearly rising potential + return static_cast(deltaPot / (absZMaxDeltaPot - zStart) * (absZ - zStart) + offs); + } else if (type == 2) { + // flat + return DataT(deltaPot); + } else if (type == 3) { + // linear falling + return static_cast(-deltaPot / (absZMaxDeltaPot - zStart) * (absZ - zStart) + deltaPot); + } else { + return DataT(0); + } + } else if (type == 4) { + // flat no z dependence + return DataT(offs); } else { - if (cutOff) { + return DataT(0); + } + }; + setPotentialBoundaryInnerRadius(chargeUpIFCLinear, side); +} + +template +void SpaceCharge::setIFCChargeUpFallingPot(const float deltaPot, const float zMaxDeltaPot, const int type, const float zEnd, const float offs, const Side side) +{ + std::function chargeUpIFCLinear = [zEnd, type, offs, zMax = getZMax(Side::A), deltaPot, zMaxDeltaPot](const DataT z) { + const float absZ = std::abs(z); + const float absZMaxDeltaPot = std::abs(zMaxDeltaPot); + + bool check = (absZ >= absZMaxDeltaPot); + if (type == 0 || type == 3) { + check = (absZ >= absZMaxDeltaPot); + } + + if (check && (absZ <= zEnd)) { + // 1/x dependency + if (type == 1) { + const float p1 = (deltaPot - offs) / (1 / zMaxDeltaPot - 1 / zEnd); + const float p2 = offs - p1 / zEnd; + DataT pot = p2 + p1 / absZ; + return pot; + } else if (type == 2) { + // 1/x dependency steep fall off! + const float offsZ = 1; + const float zEndTmp = zEnd - zMaxDeltaPot + offsZ; + const float p1 = deltaPot / (1 / offsZ - 1 / zEndTmp); + const float p2 = -p1 / zEndTmp; + const float absZShifted = absZ - zMaxDeltaPot; + DataT pot = p2 + p1 / absZShifted; + return pot; + } else if (type == 0 || type == 3) { + // linearly falling potential + const float zPos = absZ - zEnd; + return static_cast(deltaPot / (absZMaxDeltaPot - zEnd) * zPos + offs); + } else { return DataT(0); } - const float zPos = absZ - zMax; - return static_cast(deltaPot / (absZMaxDeltaPot - zMax) * zPos); + } else if (type == 3) { + return DataT(offs); + } else { + return DataT(0); } }; setPotentialBoundaryInnerRadius(chargeUpIFCLinear, side); @@ -3519,6 +3669,31 @@ void SpaceCharge::scaleChargeDensitySector(const float scalingFactor, con } } +template +void SpaceCharge::scaleChargeDensityStack(const float scalingFactor, const Sector sector, const GEMstack stack) +{ + const Side side = sector.side(); + initContainer(mDensity[side], true); + const int verticesPerSector = mParamGrid.NPhiVertices / SECTORSPERSIDE; + const int sectorInSide = sector % SECTORSPERSIDE; + const int iPhiFirst = sectorInSide * verticesPerSector; + const int iPhiLast = iPhiFirst + verticesPerSector; + for (unsigned int iR = 0; iR < mParamGrid.NRVertices; ++iR) { + const DataT radius = getRVertex(iR, side); + for (unsigned int iPhi = iPhiFirst; iPhi < iPhiLast; ++iPhi) { + const DataT phi = getPhiVertex(iR, side); + const GlobalPosition3D pos(getXFromPolar(radius, phi), getYFromPolar(radius, phi), ((side == Side::A) ? 10 : -10)); + const auto& mapper = o2::tpc::Mapper::instance(); + const o2::tpc::DigitPos digiPadPos = mapper.findDigitPosFromGlobalPosition(pos); + if (digiPadPos.isValid() && digiPadPos.getCRU().gemStack() == stack) { + for (unsigned int iZ = 0; iZ < mParamGrid.NZVertices; ++iZ) { + mDensity[side](iZ, iR, iPhi) *= scalingFactor; + } + } + } + } +} + using DataTD = double; template class o2::tpc::SpaceCharge; From 8463c432e5ef9da3dd0fa2f70481c21a21257ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tuba=20G=C3=BCndem?= <48834043+tubagundem@users.noreply.github.com> Date: Sat, 16 Sep 2023 13:24:34 +0200 Subject: [PATCH 045/324] =?UTF-8?q?GPU:=20Add=20a=20switch=20to=20enable/d?= =?UTF-8?q?isable=20the=20TPC=20PID=20response=20during=20recon=E2=80=A6?= =?UTF-8?q?=20(#11893)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * GPU: Add a switch to enable/disable the TPC PID response during reconstruction * GPU: Reorder enablePID entry in settings list for memory efficiency --- GPU/GPUTracking/Definitions/GPUSettingsList.h | 1 + GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 046cfe9c46f4b..6c3ded345c39c 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -92,6 +92,7 @@ AddOptionRTC(retryRefit, char, 1, "", 0, "Retry refit when fit fails") AddOptionRTC(loopInterpolationInExtraPass, char, -1, "", 0, "Perform loop interpolation in an extra pass") AddOptionRTC(mergerReadFromTrackerDirectly, char, 1, "", 0, "Forward data directly from tracker to merger on GPU") AddOptionRTC(dropSecondaryLegsInOutput, char, 1, "", 0, "Do not store secondary legs of looping track in TrackTPC") +AddOptionRTC(enablePID, char, 1, "", 0, "Enable PID response") AddHelp("help", 'h') EndConfig() diff --git a/GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx b/GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx index 7fbbeafed3cf6..34ef99924c11f 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx @@ -143,7 +143,7 @@ GPUdii() void GPUTPCGMO2Output::Thread(int nBlocks, in outerPar.C[6], outerPar.C[7], outerPar.C[8], outerPar.C[9], outerPar.C[10], outerPar.C[11], outerPar.C[12], outerPar.C[13], outerPar.C[14]})); - if (merger.Param().par.dodEdx) { + if (merger.Param().par.dodEdx && merger.Param().rec.tpc.enablePID) { PIDResponse pidResponse{}; const auto pid = pidResponse.getMostProbablePID(oTrack, merger.Param().rec.tpc.PID_EKrangeMin, merger.Param().rec.tpc.PID_EKrangeMax, merger.Param().rec.tpc.PID_EPrangeMin, merger.Param().rec.tpc.PID_EPrangeMax); oTrack.setPID(pid); From 5db00e901c6892430ef1fd52257c7f05cf34bb14 Mon Sep 17 00:00:00 2001 From: shahoian Date: Sat, 16 Sep 2023 17:10:34 +0200 Subject: [PATCH 046/324] Adjust packet counter of fake RDH with SOX --- Detectors/Raw/src/RawDumpSpec.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/Detectors/Raw/src/RawDumpSpec.cxx b/Detectors/Raw/src/RawDumpSpec.cxx index c58c7e8365624..345eba5cefdc0 100644 --- a/Detectors/Raw/src/RawDumpSpec.cxx +++ b/Detectors/Raw/src/RawDumpSpec.cxx @@ -192,6 +192,7 @@ void RawDump::run(ProcessingContext& pc) o2::raw::RDHUtils::setTriggerOrbit(lInfo.rdhSOX, mFirstIR.orbit); o2::raw::RDHUtils::setOffsetToNext(lInfo.rdhSOX, sizeof(o2::header::RDHAny)); o2::raw::RDHUtils::setMemorySize(lInfo.rdhSOX, sizeof(o2::header::RDHAny)); + o2::raw::RDHUtils::setPacketCounter(lInfo.rdhSOX, o2::raw::RDHUtils::getPacketCounter(lInfo.rdhSOX) - 1); trig = isRORC(lInfo.detID) ? o2::trigger::SOT : (o2::trigger::SOC | o2::trigger::ORBIT | o2::trigger::HB | o2::trigger::TF); o2::raw::RDHUtils::setTriggerType(lInfo.rdhSOX, trig); o2::raw::RDHUtils::setStop(lInfo.rdhSOX, 0x1); From adcdd90355bc6bfa894b6c9ed93bbe036674a05b Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sat, 16 Sep 2023 11:25:38 +0200 Subject: [PATCH 047/324] GPU QA: With latest ROOT, no longer necessary to unset LC_NUMERIC before --- GPU/GPUTracking/Benchmark/standalone.cxx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/GPU/GPUTracking/Benchmark/standalone.cxx b/GPU/GPUTracking/Benchmark/standalone.cxx index a0fcf59400f3e..166d664118087 100644 --- a/GPU/GPUTracking/Benchmark/standalone.cxx +++ b/GPU/GPUTracking/Benchmark/standalone.cxx @@ -120,8 +120,8 @@ int ReadConfiguration(int argc, char** argv) configStandalone.proc.debugLevel = 0; } #ifndef _WIN32 - setlocale(LC_ALL, ""); - setlocale(LC_NUMERIC, ""); + setlocale(LC_ALL, "en_US.utf-8"); + setlocale(LC_NUMERIC, "en_US.utf-8"); if (configStandalone.cpuAffinity != -1) { cpu_set_t mask; CPU_ZERO(&mask); @@ -183,12 +183,6 @@ int ReadConfiguration(int argc, char** argv) return 1; } #endif - if (configStandalone.proc.runQA) { - if (getenv("LC_NUMERIC")) { - printf("Please unset the LC_NUMERIC env variable, otherwise ROOT will not be able to fit correctly\n"); // BUG: ROOT Problem - return 1; - } - } if (configStandalone.proc.doublePipeline && configStandalone.testSyncAsync) { printf("Cannot run asynchronous processing with double pipeline\n"); return 1; From 020de3a43ad887802a8b0df9364ff500629220e3 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sat, 16 Sep 2023 11:25:49 +0200 Subject: [PATCH 048/324] GPU QA: Shut up root during histogram divide --- GPU/GPUTracking/qa/GPUQA.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/GPU/GPUTracking/qa/GPUQA.cxx b/GPU/GPUTracking/qa/GPUQA.cxx index 7df17011078fa..95de3f3430e52 100644 --- a/GPU/GPUTracking/qa/GPUQA.cxx +++ b/GPU/GPUTracking/qa/GPUQA.cxx @@ -2061,14 +2061,20 @@ int GPUQA::DrawQAHistograms(TObjArray* qcout) if (k == 0 && mConfig.inputHistogramsOnly == 0 && ii != 5) { if (l == 0) { // Divide eff, compute all for fake/clone + auto oldLevel = gErrorIgnoreLevel; + gErrorIgnoreLevel = kError; mEffResult[0][j / 2][j % 2][i]->Divide(mEff[l][j / 2][j % 2][i], mEff[3][j / 2][j % 2][i], "cl=0.683 b(1,1) mode"); + gErrorIgnoreLevel = oldLevel; mEff[3][j / 2][j % 2][i]->Reset(); // Sum up rec + clone + fake for clone/fake rate mEff[3][j / 2][j % 2][i]->Add(mEff[0][j / 2][j % 2][i]); mEff[3][j / 2][j % 2][i]->Add(mEff[1][j / 2][j % 2][i]); mEff[3][j / 2][j % 2][i]->Add(mEff[2][j / 2][j % 2][i]); } else { // Divide fake/clone + auto oldLevel = gErrorIgnoreLevel; + gErrorIgnoreLevel = kError; mEffResult[l][j / 2][j % 2][i]->Divide(mEff[l][j / 2][j % 2][i], mEff[3][j / 2][j % 2][i], "cl=0.683 b(1,1) mode"); + gErrorIgnoreLevel = oldLevel; } } @@ -2477,7 +2483,10 @@ int GPUQA::DrawQAHistograms(TObjArray* qcout) } for (int i = 0; i < N_CLS_HIST - 1; i++) { + auto oldLevel = gErrorIgnoreLevel; + gErrorIgnoreLevel = kError; mClusters[N_CLS_HIST + i]->Divide(mClusters[i], mClusters[N_CLS_HIST - 1], 1, 1, "B"); + gErrorIgnoreLevel = oldLevel; mClusters[N_CLS_HIST + i]->SetMinimum(-0.02); mClusters[N_CLS_HIST + i]->SetMaximum(1.02); } From 74f9456f718445b7d937c1d521ca0cdd83fa0414 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 11 Aug 2023 23:30:45 +0200 Subject: [PATCH 049/324] GPU TPC: Add configurable error parameterization for TPC --- GPU/GPUTracking/Base/GPUParam.cxx | 25 +++++++++++++ GPU/GPUTracking/Base/GPUParam.h | 5 +++ GPU/GPUTracking/Base/GPUParam.inc | 37 +++++++++++++------ GPU/GPUTracking/Definitions/GPUSettingsList.h | 14 +++++-- .../GPUTrackingLinkDef_O2_DataTypes.h | 1 + .../Global/GPUChainTrackingClusterizer.cxx | 4 +- .../GPUO2InterfaceConfigurableParam.h | 2 +- GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx | 11 ++++-- GPU/GPUTracking/Merger/GPUTPCGMPropagator.h | 7 ++-- GPU/GPUTracking/SliceTracker/GPUTPCGeometry.h | 1 + GPU/GPUTracking/utils/qconfig.h | 3 +- GPU/GPUTracking/utils/qconfig_helpers.h | 2 + 12 files changed, 84 insertions(+), 28 deletions(-) diff --git a/GPU/GPUTracking/Base/GPUParam.cxx b/GPU/GPUTracking/Base/GPUParam.cxx index f030625c7e5d6..cfdc0709bee20 100644 --- a/GPU/GPUTracking/Base/GPUParam.cxx +++ b/GPU/GPUTracking/Base/GPUParam.cxx @@ -42,6 +42,12 @@ void GPUParam::SetDefaults(float solenoidBz) new (&tpcGeometry) GPUTPCGeometry; new (&rec) GPUSettingsRec; +#ifdef GPUCA_TPC_GEOMETRY_O2 + const float kErrorsY[4] = {0.06, 0.24, 0.12, 0.1}; + const float kErrorsZ[4] = {0.06, 0.24, 0.15, 0.1}; + + UpdateRun3ClusterErrors(kErrorsY, kErrorsZ); +#else // clang-format off const float kParamS0Par[2][3][6] = { @@ -80,6 +86,7 @@ void GPUParam::SetDefaults(float solenoidBz) } } } +#endif par.dAlpha = 0.349066f; bzkG = solenoidBz; @@ -142,6 +149,7 @@ void GPUParam::UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessi if (p) { par.debugLevel = p->debugLevel; par.resetTimers = p->resetTimers; + UpdateRun3ClusterErrors(p->param.tpcErrorParamY, p->param.tpcErrorParamZ); } } @@ -159,6 +167,23 @@ void GPUParam::SetDefaults(const GPUSettingsGRP* g, const GPUSettingsRec* r, con } UpdateSettings(g, p); } + +void GPUParam::UpdateRun3ClusterErrors(const float* yErrorParam, const float* zErrorParam) +{ +#ifdef GPUCA_TPC_GEOMETRY_O2 + for (int yz = 0; yz < 2; yz++) { + const float* param = yz ? zErrorParam : yErrorParam; + for (int rowType = 0; rowType < 4; rowType++) { + constexpr int regionMap[4] = {0, 4, 6, 8}; + ParamErrors[yz][rowType][0] = param[0] * param[0]; + ParamErrors[yz][rowType][1] = param[1] * param[1] * tpcGeometry.PadHeightByRegion(regionMap[rowType]); + ParamErrors[yz][rowType][2] = param[2] * param[2] / tpcGeometry.TPCLength() / tpcGeometry.PadHeightByRegion(regionMap[rowType]); + ParamErrors[yz][rowType][3] = param[3] * param[3]; + } + } +#endif +} + #ifndef GPUCA_ALIROOT_LIB void GPUParam::LoadClusterErrors(bool Print) { diff --git a/GPU/GPUTracking/Base/GPUParam.h b/GPU/GPUTracking/Base/GPUParam.h index 48bc8b2f731ce..cc3405eb9ae9f 100644 --- a/GPU/GPUTracking/Base/GPUParam.h +++ b/GPU/GPUTracking/Base/GPUParam.h @@ -63,8 +63,12 @@ struct GPUParam_t { GPUParamSlice SliceParam[GPUCA_NSLICES]; protected: +#ifdef GPUCA_TPC_GEOMETRY_O2 + float ParamErrors[2][4][4]; +#else float ParamErrorsSeeding0[2][3][4]; // cluster shape parameterization coeficients float ParamS0Par[2][3][6]; // cluster error parameterization coeficients +#endif }; } // namespace internal @@ -78,6 +82,7 @@ struct GPUParam : public internal::GPUParam_t void UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p = nullptr); void LoadClusterErrors(bool Print = 0); o2::base::Propagator* GetDefaultO2Propagator(bool useGPUField = false) const; + void UpdateRun3ClusterErrors(const float* yErrorParam, const float* zErrorParam); #endif GPUd() float Alpha(int iSlice) const diff --git a/GPU/GPUTracking/Base/GPUParam.inc b/GPU/GPUTracking/Base/GPUParam.inc index 0302af6ec30e2..2a281b0435e25 100644 --- a/GPU/GPUTracking/Base/GPUParam.inc +++ b/GPU/GPUTracking/Base/GPUParam.inc @@ -41,11 +41,30 @@ GPUdi() void MEM_LG(GPUParam)::Global2Slice(int iSlice, float X, float Y, float *z = Z; } +#ifdef GPUCA_TPC_GEOMETRY_O2 + MEM_CLASS_PRE() -GPUdi() float MEM_LG(GPUParam)::GetClusterErrorSeeding(int yz, int type, float z, float angle2) const +GPUdi() void MEM_LG(GPUParam)::GetClusterErrorsSeeding2(int iRow, float z, float sinPhi, float DzDs, float& ErrY2, float& ErrZ2) const { - //* recalculate the cluster ErrorsSeeding wih respect to the track slope + GetClusterErrors2(iRow, z, sinPhi, DzDs, ErrY2, ErrZ2); +} +MEM_CLASS_PRE() +GPUdi() float MEM_LG(GPUParam)::GetClusterError2(int yz, int type, float z, float angle2) const +{ + MakeType(const float*) c = ParamErrors[yz][type]; + float v = c[0] + c[1] * angle2 + c[2] * z + c[3] * 0; + v = CAMath::Abs(v); + v *= yz ? rec.tpc.clusterError2CorrectionZ : rec.tpc.clusterError2CorrectionY; + v += yz ? rec.tpc.clusterError2AdditionalZ : rec.tpc.clusterError2AdditionalY; + return v; +} + +#else // GPUCA_TPC_GEOMETRY_O2 + +MEM_CLASS_PRE() +GPUdi() float MEM_LG(GPUParam)::GetClusterErrorSeeding(int yz, int type, float z, float angle2) const +{ MakeType(const float*) c = ParamErrorsSeeding0[yz][type]; float v = c[0] + c[1] * z + c[2] * angle2; v = CAMath::Abs(v); @@ -56,10 +75,7 @@ MEM_CLASS_PRE() GPUdi() void MEM_LG(GPUParam)::GetClusterErrorsSeeding2(int iRow, float z, float sinPhi, float DzDs, float& ErrY2, float& ErrZ2) const { int rowType = tpcGeometry.GetROC(iRow); - if (rowType > 2) { - rowType = 2; // TODO: Add type 3 - } - z = CAMath::Abs(GPUTPCGeometry::TPCLength() - CAMath::Abs(z)); + z = CAMath::Abs(tpcGeometry.TPCLength() - CAMath::Abs(z)); float s2 = sinPhi * sinPhi; if (s2 > 0.95f * 0.95f) { s2 = 0.95f * 0.95f; @@ -77,8 +93,6 @@ GPUdi() void MEM_LG(GPUParam)::GetClusterErrorsSeeding2(int iRow, float z, float MEM_CLASS_PRE() GPUdi() float MEM_LG(GPUParam)::GetClusterError2(int yz, int type, float z, float angle2) const { - //* recalculate the cluster error wih respect to the track slope - MakeType(const float*) c = ParamS0Par[yz][type]; float v = c[0] + c[1] * z + c[2] * angle2 + c[3] * z * z + c[4] * angle2 * angle2 + c[5] * z * angle2; v = CAMath::Abs(v); @@ -90,15 +104,14 @@ GPUdi() float MEM_LG(GPUParam)::GetClusterError2(int yz, int type, float z, floa return v; } +#endif // !GPUCA_TPC_GEOMETRY_O2 + MEM_CLASS_PRE() GPUdi() void MEM_LG(GPUParam)::GetClusterErrors2(int iRow, float z, float sinPhi, float DzDs, float& ErrY2, float& ErrZ2) const { // Calibrated cluster error from OCDB for Y and Z int rowType = tpcGeometry.GetROC(iRow); - if (rowType > 2) { - rowType = 2; // TODO: Add type 3 - } - z = CAMath::Abs(GPUTPCGeometry::TPCLength() - CAMath::Abs(z)); + z = CAMath::Abs(tpcGeometry.TPCLength() - CAMath::Abs(z)); float s2 = sinPhi * sinPhi; if (s2 > 0.95f * 0.95f) { s2 = 0.95f * 0.95f; diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 6c3ded345c39c..504032b4f14de 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -33,7 +33,7 @@ using namespace GPUCA_NAMESPACE::gpu; BeginNamespace(GPUCA_NAMESPACE) BeginNamespace(gpu) -// Settings concerning the reconstruction +// Settings concerning the reconstruction, stored as parameters in GPU constant memory // There must be no bool in here, use char, as sizeof(bool) is compiler dependent and fails on GPUs!!!!!! BeginSubConfig(GPUSettingsRecTPC, tpc, configStandalone.rec, "RECTPC", 0, "Reconstruction settings", rec_tpc) AddOptionRTC(rejectQPtB5, float, 1.f / GPUCA_MIN_TRACK_PTB5_REJECT, "", 0, "QPt threshold to reject clusters of TPC tracks (Inverse Pt, scaled to B=0.5T!!!)") @@ -88,7 +88,7 @@ AddOptionRTC(dropLoopers, unsigned char, 0, "", 0, "Drop looping tracks starting AddOptionRTC(mergerCovSource, unsigned char, 2, "", 0, "Method to obtain covariance in track merger: 0 = simple filterErrors method, 1 = use cov from track following, 2 = refit (default)") AddOptionRTC(mergerInterpolateErrors, unsigned char, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergeCE, unsigned char, 1, "", 0, "Merge tracks accross the central electrode") -AddOptionRTC(retryRefit, char, 1, "", 0, "Retry refit when fit fails") +AddOptionRTC(retryRefit, char, 1, "", 0, "Retry refit with seeding errors and without cluster rejection when fit fails") AddOptionRTC(loopInterpolationInExtraPass, char, -1, "", 0, "Perform loop interpolation in an extra pass") AddOptionRTC(mergerReadFromTrackerDirectly, char, 1, "", 0, "Forward data directly from tracker to merger on GPU") AddOptionRTC(dropSecondaryLegsInOutput, char, 1, "", 0, "Do not store secondary legs of looping track in TrackTPC") @@ -133,7 +133,7 @@ AddSubConfig(GPUSettingsRecTRD, trd) AddHelp("help", 'h') EndConfig() -// Settings steering the processing once the device was selected +// Settings steering the processing once the device was selected, only available on the host BeginSubConfig(GPUSettingsProcessingRTC, rtc, configStandalone.proc, "RTC", 0, "Processing settings", proc_rtc) AddOption(cacheOutput, bool, false, "", 0, "Cache RTC compilation results") AddOption(optConstexpr, bool, true, "", 0, "Replace constant variables by static constexpr expressions") @@ -142,6 +142,12 @@ AddOption(enable, bool, false, "", 0, "Use RTC to optimize GPU code") AddHelp("help", 'h') EndConfig() +BeginSubConfig(GPUSettingsProcessingParam, param, configStandalone.proc, "PARAM", 0, "Processing settings", proc_param) +AddOptionArray(tpcErrorParamY, float, 4, (0.06, 0.24, 0.12, 0.1), "", 0, "TPC Cluster Y Error Parameterization") +AddOptionArray(tpcErrorParamZ, float, 4, (0.06, 0.24, 0.15, 0.1), "", 0, "TPC Cluster Z Error Parameterization") +AddHelp("help", 'h') +EndConfig() + BeginSubConfig(GPUSettingsProcessing, proc, configStandalone, "PROC", 0, "Processing settings", proc) AddOption(platformNum, int, -1, "", 0, "Platform to use, in case the backend provides multiple platforms (-1 = auto-select)") AddOption(deviceNum, int, -1, "gpuDevice", 0, "Set GPU device to use (-1: automatic, -2: for round-robin usage in timeslice-pipeline)") @@ -211,6 +217,7 @@ AddOption(outputSanityCheck, bool, false, "", 0, "Run some simple sanity checks AddOption(tpcSingleSector, int, -1, "", 0, "Restrict TPC processing to a single sector") AddVariable(eventDisplay, GPUCA_NAMESPACE::gpu::GPUDisplayFrontendInterface*, nullptr) AddSubConfig(GPUSettingsProcessingRTC, rtc) +AddSubConfig(GPUSettingsProcessingParam, param) AddHelp("help", 'h') EndConfig() @@ -300,7 +307,6 @@ AddOption(uniformBuffersInDeviceMemory, bool, 1, "", 0, "Have uniform buffers in AddHelp("help", 'h') EndConfig() - // Settings concerning the event display (fixed settings, cannot be changed) BeginSubConfig(GPUSettingsDisplay, display, configStandalone, "GL", 'g', "OpenGL display settings", display) AddOption(showTPCTracksFromO2Format, bool, false, "", 0, "Use TPC tracks in O2 output format instead of GPU format") diff --git a/GPU/GPUTracking/GPUTrackingLinkDef_O2_DataTypes.h b/GPU/GPUTracking/GPUTrackingLinkDef_O2_DataTypes.h index 531dc2dbe1d13..16f9b769123f7 100644 --- a/GPU/GPUTracking/GPUTrackingLinkDef_O2_DataTypes.h +++ b/GPU/GPUTracking/GPUTrackingLinkDef_O2_DataTypes.h @@ -29,6 +29,7 @@ #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsRecTPC + ; #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsRecTRD + ; #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsProcessing + ; +#pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsProcessingParam + ; #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsProcessingRTC + ; #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsDisplay + ; #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsDisplayLight + ; diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index 7e829cba83afb..338493b989033 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -177,7 +177,7 @@ std::pair GPUChainTracking::TPCClusterizerDecodeZSCo unsigned int pageCounter = 0; unsigned int emptyPages = 0; for (unsigned int k = 0; k < mIOPtrs.tpcZS->slice[iSlice].count[j]; k++) { - if (GetProcessingSettings().tpcSingleSector != -1 && GetProcessingSettings().tpcSingleSector != iSlice) { + if (GetProcessingSettings().tpcSingleSector != -1 && GetProcessingSettings().tpcSingleSector != (int)iSlice) { break; } nPages += mIOPtrs.tpcZS->slice[iSlice].nZSPtr[j][k]; @@ -701,7 +701,7 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) } } - if (GetProcessingSettings().tpcSingleSector == -1 || GetProcessingSettings().tpcSingleSector == iSlice) { + if (GetProcessingSettings().tpcSingleSector == -1 || GetProcessingSettings().tpcSingleSector == (int)iSlice) { if (not mIOPtrs.tpcZS) { runKernel(GetGrid(1, lane), {iSlice}, {}, mIOPtrs.tpcZS == nullptr); TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.h b/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.h index a296567ecb269..cd2d037a11c11 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.h @@ -49,7 +49,7 @@ #define AddVariableRTC(...) AddVariable(__VA_ARGS__) #define AddOptionSet(name, type, value, optname, optnameshort, help, ...) #define AddOptionVec(name, type, optname, optnameshort, help, ...) -#define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) type name[count] = {default}; +#define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) type name[count] = {GPUCA_M_STRIP(default)}; #define AddSubConfig(name, instance) #define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, o2prefix) \ struct GPUCA_M_CAT(GPUConfigurableParam, name) : public o2::conf::ConfigurableParamHelper { \ diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx index 765a5ef0fe13b..7318950ff1b8f 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx @@ -599,10 +599,13 @@ GPUd() int GPUTPCGMPropagator::GetPropagatedYZ(float x, float& GPUrestrict() pro GPUd() void GPUTPCGMPropagator::GetErr2(float& GPUrestrict() err2Y, float& GPUrestrict() err2Z, const GPUParam& GPUrestrict() param, float posZ, int iRow, short clusterState) const { - if (!mSeedingErrors) { - param.GetClusterErrors2(iRow, posZ, mT0.GetSinPhi(), mT0.DzDs(), err2Y, err2Z); - } else { +#ifndef GPUCA_TPC_GEOMETRY_O2 + if (mSeedingErrors) { param.GetClusterErrorsSeeding2(iRow, posZ, mT0.GetSinPhi(), mT0.DzDs(), err2Y, err2Z); + } else +#endif + { + param.GetClusterErrors2(iRow, posZ, mT0.GetSinPhi(), mT0.DzDs(), err2Y, err2Z); } param.UpdateClusterError2ByState(clusterState, err2Y, err2Z); mStatErrors.GetOfflineStatisticalErrors(err2Y, err2Z, mT0.SinPhi(), mT0.DzDs(), clusterState); @@ -782,7 +785,7 @@ GPUd() int GPUTPCGMPropagator::Update(float posY, float posZ, short clusterState } float dChi2 = chiY + chiZ; // GPUInfo("hits %d chi2 %f, new %f %f (dy %f dz %f)", N, mChi2, chiY, chiZ, z0, z1); - if (!mSeedingErrors && rejectChi2 == 1 && RejectCluster(chiY * param->rec.tpc.clusterRejectChi2TolleranceY, chiZ * param->rec.tpc.clusterRejectChi2TolleranceZ, clusterState)) { + if (rejectChi2 == 1 && RejectCluster(chiY * param->rec.tpc.clusterRejectChi2TolleranceY, chiZ * param->rec.tpc.clusterRejectChi2TolleranceZ, clusterState)) { return 2; } mT->Chi2() += dChi2; diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h index 88c4644db9b99..7c0f071dd977e 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h @@ -168,22 +168,21 @@ class GPUTPCGMPropagator GPUd() float getGlobalY(float X, float Y) const; const GPUTPCGMPolynomialField* mField = nullptr; - FieldRegion mFieldRegion = TPC; - + const o2::base::MatLayerCylSet* mMatLUT = nullptr; GPUTPCGMTrackParam* mT = nullptr; float mAlpha = 0.f; // rotation angle of the track coordinate system float mCosAlpha = 1.f; // cos of the rotation angle float mSinAlpha = 0.f; // sin of the rotation angle + float mMaxSinPhi = GPUCA_MAX_SIN_PHI; GPUTPCGMPhysicalTrackModel mT0; MaterialCorrection mMaterial; + FieldRegion mFieldRegion = TPC; bool mSeedingErrors = 0; bool mFitInProjections = 1; // fit (Y,SinPhi,QPt) and (Z,DzDs) paramteres separatelly bool mPropagateBzOnly = 0; // Use Bz only in propagation bool mToyMCEvents = 0; // events are simulated with simple home-made simulation - float mMaxSinPhi = GPUCA_MAX_SIN_PHI; GPUTPCGMOfflineStatisticalErrors mStatErrors; - const o2::base::MatLayerCylSet* mMatLUT = nullptr; }; GPUdi() void GPUTPCGMPropagator::GetBxByBz(float Alpha, float X, float Y, float Z, float B[3]) const diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCGeometry.h b/GPU/GPUTracking/SliceTracker/GPUTPCGeometry.h index 59172aeb736b6..30086b92e6206 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCGeometry.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCGeometry.h @@ -107,6 +107,7 @@ class GPUTPCGeometry // TODO: Make values constexpr GPUd() static CONSTEXPR float TPCLength() { return 250.f - 0.275f; } GPUd() float Row2X(int row) const { return (mX[row]); } GPUd() float PadHeight(int row) const { return (mPadHeight[GetRegion(row)]); } + GPUd() float PadHeightByRegion(int region) const { return (mPadHeight[region]); } GPUd() float PadWidth(int row) const { return (mPadWidth[GetRegion(row)]); } GPUd() unsigned char NPads(int row) const { return mNPads[row]; } diff --git a/GPU/GPUTracking/utils/qconfig.h b/GPU/GPUTracking/utils/qconfig.h index 3834b0ff7eba8..ae9de854772ac 100644 --- a/GPU/GPUTracking/utils/qconfig.h +++ b/GPU/GPUTracking/utils/qconfig.h @@ -283,7 +283,8 @@ enum qConfigRetVal { qcrOK = 0, #if !defined(QCONFIG_GPU) #define AddOption(name, type, default, optname, optnameshort, help, ...) type name = default; #define AddVariable(name, type, default) type name = default; -#define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) type name[count] = {default}; +#define _AddOptionArray_INTERNAL_EXPAND(...) __VA_ARGS__ +#define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) type name[count] = {_AddOptionArray_INTERNAL_EXPAND default}; #define AddOptionVec(name, type, optname, optnameshort, help, ...) std::vector name; #else #define AddOption(name, type, default, optname, optnameshort, help, ...) type name; diff --git a/GPU/GPUTracking/utils/qconfig_helpers.h b/GPU/GPUTracking/utils/qconfig_helpers.h index 5ca2c8a693f61..4c80963d949a5 100644 --- a/GPU/GPUTracking/utils/qconfig_helpers.h +++ b/GPU/GPUTracking/utils/qconfig_helpers.h @@ -24,6 +24,8 @@ #define qon_mxcat3(a, b, c) qon_mcat3(a, b, c) #define qon_mstr(a) #a #define qon_mxstr(a) qon_mstr(a) +#define qon_mexp(...) __VA_ARGS__ +#define qon_mxexp(X) qon_mexp X namespace qConfig { From 08a667d0fa5238a77b60e20c620676acb57dc565 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 23 Aug 2023 10:17:04 +0200 Subject: [PATCH 050/324] GPU TPC: Make more tacking settings configurable --- GPU/GPUTracking/Base/GPUParam.inc | 16 +++++----- .../Definitions/GPUDefConstantsAndSettings.h | 16 +--------- GPU/GPUTracking/Definitions/GPUSettingsList.h | 29 ++++++++++++++++++- GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx | 25 ++++++++-------- GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx | 4 +-- .../SliceTracker/GPUTPCGlobalTracking.cxx | 16 +++++----- .../GPUTPCTrackletConstructor.cxx | 6 ++-- 7 files changed, 62 insertions(+), 50 deletions(-) diff --git a/GPU/GPUTracking/Base/GPUParam.inc b/GPU/GPUTracking/Base/GPUParam.inc index 2a281b0435e25..f2ab1a0d66b5a 100644 --- a/GPU/GPUTracking/Base/GPUParam.inc +++ b/GPU/GPUTracking/Base/GPUParam.inc @@ -128,20 +128,20 @@ MEM_CLASS_PRE() GPUdi() void MEM_LG(GPUParam)::UpdateClusterError2ByState(short clusterState, float& ErrY2, float& ErrZ2) const { if (clusterState & GPUTPCGMMergedTrackHit::flagEdge) { - ErrY2 += 0.35f; - ErrZ2 += 0.15f; + ErrY2 += rec.tpc.extraClusterErrorEdgeY2; + ErrZ2 += rec.tpc.extraClusterErrorEdgeZ2; } if (clusterState & GPUTPCGMMergedTrackHit::flagSingle) { - ErrY2 += 0.2f; - ErrZ2 += 0.2f; + ErrY2 += rec.tpc.extraClusterErrorSingleY2; + ErrZ2 += rec.tpc.extraClusterErrorSingleZ2; } if (clusterState & (GPUTPCGMMergedTrackHit::flagSplitPad | GPUTPCGMMergedTrackHit::flagShared | GPUTPCGMMergedTrackHit::flagSingle)) { - ErrY2 += 0.03f; - ErrY2 *= 3; + ErrY2 += rec.tpc.extraClusterErrorSplitPadSharedSingleY2; + ErrY2 *= rec.tpc.extraClusterErrorFactorSplitPadSharedSingleY2; } if (clusterState & (GPUTPCGMMergedTrackHit::flagSplitTime | GPUTPCGMMergedTrackHit::flagShared | GPUTPCGMMergedTrackHit::flagSingle)) { - ErrZ2 += 0.03f; - ErrZ2 *= 3; + ErrZ2 += rec.tpc.extraClusterErrorSplitTimeSharedSingleZ2; + ErrZ2 *= rec.tpc.extraClusterErrorFactorSplitTimeSharedSingleZ2; } } diff --git a/GPU/GPUTracking/Definitions/GPUDefConstantsAndSettings.h b/GPU/GPUTracking/Definitions/GPUDefConstantsAndSettings.h index c402b2ed2b845..2688b416e9ecd 100644 --- a/GPU/GPUTracking/Definitions/GPUDefConstantsAndSettings.h +++ b/GPU/GPUTracking/Definitions/GPUDefConstantsAndSettings.h @@ -32,25 +32,11 @@ #define GPUCA_TRACKLET_SELECTOR_MIN_HITS_B5(QPTB5) (CAMath::Abs(QPTB5) > 10 ? 10 : (CAMath::Abs(QPTB5) > 5 ? 15 : 29)) // Minimum hits should depend on Pt, low Pt tracks can have few hits. 29 Hits default, 15 for < 200 mev, 10 for < 100 mev -#define GPUCA_GLOBAL_TRACKING_RANGE 45 // Number of rows from the upped/lower limit to search for global track candidates in for -#define GPUCA_GLOBAL_TRACKING_Y_RANGE_UPPER 0.85f // Inner portion of y-range in slice that is not used in searching for global track candidates -#define GPUCA_GLOBAL_TRACKING_Y_RANGE_LOWER 0.85f -#define GPUCA_GLOBAL_TRACKING_MIN_ROWS 10 // Min num of rows an additional global track must span over -#define GPUCA_GLOBAL_TRACKING_MIN_HITS 8 // Min num of hits for an additional global track - -#define GPUCA_MERGER_CE_ROWLIMIT 5 //Distance from first / last row in order to attempt merging accross CE -#define GPUCA_MERGER_LOOPER_QPTB5_LIMIT 4 // Min Q/Pt (@B=0.5T) to run special looper merging procedure -#define GPUCA_MERGER_HORIZONTAL_DOUBLE_QPTB5_LIMIT 2 // Min Q/Pt (@B=0.5T) to attempt second horizontal merge between slices after a vertical merge was found #define GPUCA_MERGER_MAX_TRACK_CLUSTERS 1000 // Maximum number of clusters a track may have after merging -#define GPUCA_Y_FACTOR 4 // Weight of y residual vs z residual in tracklet constructor #define GPUCA_MAXN 40 // Maximum number of neighbor hits to consider in one row in neightbors finder -#define GPUCA_TRACKLET_CONSTRUCTOR_MAX_ROW_GAP 4 // Maximum number of consecutive rows without hit in track following -#define GPUCA_TRACKLET_CONSTRUCTOR_MAX_ROW_GAP_SEED 2 // Same, but during fit of seed -#define GPUCA_MERGER_MAXN_MISSED_HARD 10 // Hard limit for number of missed rows in fit / propagation -#define GPUCA_MERGER_COV_LIMIT 1000 // Abort fit when y/z cov exceed the limit #define GPUCA_MIN_TRACK_PTB5_DEFAULT 0.010 // Default setting for minimum track Pt at some places (at B=0.5T) -#define GPUCA_MIN_TRACK_PTB5_REJECT 0.050f // Default setting for Pt (at B=0.5T) where tracks are rejected +#define GPUCA_MIN_TRACK_PTB5_REJECT_DEFAULT 0.050f // Default setting for Pt (at B=0.5T) where tracks are rejected #define GPUCA_MAX_SIN_PHI_LOW 0.99f // Limits for maximum sin phi during fit #define GPUCA_MAX_SIN_PHI 0.999f // Must be preprocessor define because c++ pre 11 cannot use static constexpr for initializes diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 504032b4f14de..9c2cf3fae91de 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -36,7 +36,7 @@ BeginNamespace(gpu) // Settings concerning the reconstruction, stored as parameters in GPU constant memory // There must be no bool in here, use char, as sizeof(bool) is compiler dependent and fails on GPUs!!!!!! BeginSubConfig(GPUSettingsRecTPC, tpc, configStandalone.rec, "RECTPC", 0, "Reconstruction settings", rec_tpc) -AddOptionRTC(rejectQPtB5, float, 1.f / GPUCA_MIN_TRACK_PTB5_REJECT, "", 0, "QPt threshold to reject clusters of TPC tracks (Inverse Pt, scaled to B=0.5T!!!)") +AddOptionRTC(rejectQPtB5, float, 1.f / GPUCA_MIN_TRACK_PTB5_REJECT_DEFAULT, "", 0, "QPt threshold to reject clusters of TPC tracks (Inverse Pt, scaled to B=0.5T!!!)") AddOptionRTC(hitPickUpFactor, float, 1.f, "", 0, "multiplier for the combined cluster+track error during track following") AddOptionRTC(hitSearchArea2, float, 2.f, "", 0, "square of maximum search road of hits during seeding") AddOptionRTC(neighboursSearchArea, float, 3.f, "", 0, "area in cm for the search of neighbours, only used if searchWindowDZDR = 0") @@ -60,9 +60,36 @@ AddOptionRTC(PID_EKrangeMin, float, 0.38, "", 0, "min P of electron/K BB bands c AddOptionRTC(PID_EKrangeMax, float, 0.48, "", 0, "max P of electron/K BB bands crossing") AddOptionRTC(PID_EPrangeMin, float, 0.75, "", 0, "min P of electron/p BB bands crossing") AddOptionRTC(PID_EPrangeMax, float, 0.85, "", 0, "max P of electron/p BB bands crossing") +AddOptionRTC(extraClusterErrorEdgeY2, float, 0.35, "", 0, "Additive extra cluster error for Y2 if edge flag set") +AddOptionRTC(extraClusterErrorEdgeZ2, float, 0.15, "", 0, "Additive extra cluster error for Z2 if edge flag set") +AddOptionRTC(extraClusterErrorSingleY2, float, 0.2, "", 0, "Additive extra cluster error for Y2 if edge single set") +AddOptionRTC(extraClusterErrorSingleZ2, float, 0.2, "", 0, "Additive extra cluster error for Z2 if edge single set") +AddOptionRTC(extraClusterErrorSplitPadSharedSingleY2, float, 0.03, "", 0, "Additive extra cluster error for Y2 if splitpad, shared, or single set") +AddOptionRTC(extraClusterErrorFactorSplitPadSharedSingleY2, float, 3.0, "", 0, "Multiplicative extra cluster error for Y2 if splitpad, shared, or single set") +AddOptionRTC(extraClusterErrorSplitTimeSharedSingleZ2, float, 0.03, "", 0, "Additive extra cluster error for Z2 if splittime, shared, or single set") +AddOptionRTC(extraClusterErrorFactorSplitTimeSharedSingleZ2, float, 3.0, "", 0, "Multiplicative extra cluster error for Z2 if splittime, shared, or single set") +AddOptionRTC(globalTrackingYRangeUpper, float, 0.85, "", 0, "Inner portion of y-range in slice that is not used in searching for global track candidates") +AddOptionRTC(globalTrackingYRangeLower, float, 0.85, "", 0, "Inner portion of y-range in slice that is not used in searching for global track candidates") +AddOptionRTC(trackFollowingYFactor, float, 4, "", 0, "Weight of y residual vs z residual in tracklet constructor") +AddOptionRTC(trackMergerFactor2YS, float, 1.5 * 1.5, "", 0, "factor2YS for track merging") +AddOptionRTC(trackMergerFactor2ZT, float, 1.5 * 1.5, "", 0, "factor2ZT for track merging") +AddOptionRTC(trackMergerFactor2K, float, 2.0 * 2.0, "", 0, "factor2K for track merging") +AddOptionRTC(trackMergerFactor2General, float, 3.5 * 3.5, "", 0, "General factor for track merging") AddOptionRTC(maxTimeBinAboveThresholdIn1000Bin, unsigned short, 500, "", 0, "Except pad from cluster finding if total number of charges in a fragment is above this baseline (disable = 0)") AddOptionRTC(maxConsecTimeBinAboveThreshold, unsigned short, 200, "", 0, "Except pad from cluster finding if number of consecutive charges in a fragment is above this baseline (disable = 0)") AddOptionRTC(noisyPadSaturationThreshold, unsigned short, 700, "", 0, "Threshold where a timebin is considered saturated, disabling the noisy pad check for that pad") +AddOptionRTC(trackFitCovLimit, unsigned short, 1000, "", 0, "Abort fit when y/z cov exceed the limit") +AddOptionRTC(trackMergerMinPartHits, unsigned char, 10, "", 0, "Minimum hits of track part during track merging") +AddOptionRTC(trackMergerMinTotalHits, unsigned char, 20, "", 0, "Minimum total of track part during track merging") +AddOptionRTC(mergerCERowLimit, unsigned char, 5, "", 0, "Distance from first / last row in order to attempt merging accross CE") +AddOptionRTC(mergerLooperQPtB5Limit, unsigned char, 4, "", 0, "Min Q/Pt (@B=0.5T) to run special looper merging procedure") +AddOptionRTC(mergerLooperSecondHorizontalQPtB5Limit, unsigned char, 2, "", 0, "Min Q/Pt (@B=0.5T) to attempt second horizontal merge between slices after a vertical merge was found") +AddOptionRTC(trackFollowingMaxRowGap, unsigned char, 4, "", 0, "Maximum number of consecutive rows without hit in track following") +AddOptionRTC(trackFollowingMaxRowGapSeed, unsigned char, 2, "", 0, "Maximum number of consecutive rows without hit in track following during fit of seed") +AddOptionRTC(trackFitMaxRowMissedHard, unsigned char, 10, "", 0, "Hard limit for number of missed rows in fit / propagation") +AddOptionRTC(globalTrackingRowRange, unsigned char, 45, "", 0, "Number of rows from the upped/lower limit to search for global track candidates in for") +AddOptionRTC(globalTrackingMinRows, unsigned char, 10, "", 0, "Min num of rows an additional global track must span over") +AddOptionRTC(globalTrackingMinHits, unsigned char, 8, "", 0, "Min num of hits for an additional global track") AddOptionRTC(noisyPadsQuickCheck, unsigned char, 1, "", 0, "Only check first fragment for noisy pads instead of all fragments (when test is enabled).") AddOptionRTC(cfQMaxCutoff, unsigned char, 3, "", 0, "Cluster Finder rejects cluster with qmax below or equal to this threshold") AddOptionRTC(cfQTotCutoff, unsigned char, 5, "", 0, "Cluster Finder rejects cluster with qtot below or equal to this threshold") diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx index 5be266e3e19b4..5b2f6358044fe 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx @@ -684,7 +684,7 @@ GPUd() void GPUTPCGMMerger::MakeBorderTracks(int nBlocks, int nThreads, int iBlo continue; } if (useOrigTrackParam) { // TODO: Check how far this makes sense with slice track refit - if (CAMath::Abs(track->QPt()) * Param().qptB5Scaler < GPUCA_MERGER_LOOPER_QPTB5_LIMIT) { + if (CAMath::Abs(track->QPt()) * Param().qptB5Scaler < Param().rec.tpc.mergerLooperQPtB5Limit) { continue; } const GPUTPCGMSliceTrack* trackMin = track; @@ -702,7 +702,7 @@ GPUd() void GPUTPCGMMerger::MakeBorderTracks(int nBlocks, int nThreads, int iBlo trackTmp.Set(this, trackMin->OrigTrack(), trackMin->Alpha(), trackMin->Slice()); } } else { - if (CAMath::Abs(track->QPt()) * Param().qptB5Scaler < GPUCA_MERGER_HORIZONTAL_DOUBLE_QPTB5_LIMIT) { + if (CAMath::Abs(track->QPt()) * Param().qptB5Scaler < Param().rec.tpc.mergerLooperSecondHorizontalQPtB5Limit) { if (iBorder == 0 && track->NextNeighbour() >= 0) { continue; } @@ -841,16 +841,17 @@ template <> GPUd() void GPUTPCGMMerger::MergeBorderTracks<2>(int nBlocks, int nThreads, int iBlock, int iThread, int iSlice1, GPUTPCGMBorderTrack* B1, int N1, int iSlice2, GPUTPCGMBorderTrack* B2, int N2, int mergeMode) { // int statAll = 0, statMerged = 0; - float factor2ys = 1.5; // 1.5;//SG!!! - float factor2zt = 1.5; // 1.5;//SG!!! - float factor2k = 2.0; // 2.2; + float factor2ys = Param().rec.tpc.trackMergerFactor2YS; + float factor2zt = Param().rec.tpc.trackMergerFactor2ZT; + float factor2k = Param().rec.tpc.trackMergerFactor2K; + float factor2General = Param().rec.tpc.trackMergerFactor2General; - factor2k = 3.5 * 3.5 * factor2k * factor2k; - factor2ys = 3.5 * 3.5 * factor2ys * factor2ys; - factor2zt = 3.5 * 3.5 * factor2zt * factor2zt; + factor2k = factor2General * factor2k; + factor2ys = factor2General * factor2ys; + factor2zt = factor2General * factor2zt; - int minNPartHits = 10; // SG!!! - int minNTotalHits = 20; + int minNPartHits = Param().rec.tpc.trackMergerMinPartHits; + int minNTotalHits = Param().rec.tpc.trackMergerMinTotalHits; bool sameSlice = (iSlice1 == iSlice2); @@ -1314,11 +1315,9 @@ GPUd() void GPUTPCGMMerger::MergeCEFill(const GPUTPCGMSliceTrack* track, const G return; } -#ifdef GPUCA_MERGER_CE_ROWLIMIT - if (CAMath::Abs(track->QPt()) * Param().qptB5Scaler < 0.3 && (cls.row < GPUCA_MERGER_CE_ROWLIMIT || cls.row >= GPUCA_ROW_COUNT - GPUCA_MERGER_CE_ROWLIMIT)) { + if (Param().rec.tpc.mergerCERowLimit > 0 && CAMath::Abs(track->QPt()) * Param().qptB5Scaler < 0.3 && (cls.row < Param().rec.tpc.mergerCERowLimit || cls.row >= GPUCA_ROW_COUNT - Param().rec.tpc.mergerCERowLimit)) { return; } -#endif float z = 0; if (Param().par.earlyTpcTransform) { diff --git a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx index 095316f6505a1..738418d5ae8e4 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx @@ -145,7 +145,7 @@ GPUd() bool GPUTPCGMTrackParam::Fit(GPUTPCGMMerger* GPUrestrict() merger, int iT unsigned char clusterState = clusters[ihit].state; const float clAlpha = param.Alpha(clusters[ihit].slice); - if ((param.rec.tpc.trackFitRejectMode > 0 && nMissed >= param.rec.tpc.trackFitRejectMode) || nMissed2 >= GPUCA_MERGER_MAXN_MISSED_HARD || clusters[ihit].state & GPUTPCGMMergedTrackHit::flagReject) { + if ((param.rec.tpc.trackFitRejectMode > 0 && nMissed >= param.rec.tpc.trackFitRejectMode) || nMissed2 >= param.rec.tpc.trackFitMaxRowMissedHard || clusters[ihit].state & GPUTPCGMMergedTrackHit::flagReject) { CADEBUG(printf("\tSkipping hit, %d hits rejected, flag %X\n", nMissed, (int)clusters[ihit].state)); if (iWay + 2 >= nWays && !(clusters[ihit].state & GPUTPCGMMergedTrackHit::flagReject)) { clusters[ihit].state |= GPUTPCGMMergedTrackHit::flagRejectErr; @@ -271,7 +271,7 @@ GPUd() bool GPUTPCGMTrackParam::Fit(GPUTPCGMMerger* GPUrestrict() merger, int iT const int err2 = mNDF > 0 && CAMath::Abs(prop.GetSinPhi0()) >= maxSinForUpdate; if (err || err2) { - if (mC[0] > GPUCA_MERGER_COV_LIMIT || mC[2] > GPUCA_MERGER_COV_LIMIT) { + if (mC[0] > param.rec.tpc.trackFitCovLimit || mC[2] > param.rec.tpc.trackFitCovLimit) { break; } MarkClusters(clusters, ihitMergeFirst, ihit, wayDirection, GPUTPCGMMergedTrackHit::flagNotFit); diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.cxx index 9cebcedb096e9..fd1d7b42be407 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.cxx @@ -71,7 +71,7 @@ GPUd() int GPUTPCGlobalTracking::PerformGlobalTrackingRun(GPUTPCTracker& tracker calink rowHits[GPUCA_ROW_COUNT]; int nHits = GPUTPCTrackletConstructor::GPUTPCTrackletConstructorGlobalTracking(tracker, smem, tParam, rowIndex, direction, 0, rowHits); - if (nHits >= GPUCA_GLOBAL_TRACKING_MIN_HITS) { + if (nHits >= tracker.Param().rec.tpc.globalTrackingMinHits) { // GPUInfo("%d hits found", nHits); unsigned int hitId = CAMath::AtomicAdd(&tracker.CommonMemory()->nTrackHits, (unsigned int)nHits); if (hitId + nHits > tracker.NMaxTrackHits()) { @@ -117,7 +117,7 @@ GPUd() int GPUTPCGlobalTracking::PerformGlobalTrackingRun(GPUTPCTracker& tracker track.SetLocalTrackId((sliceSource.ISlice() << 24) | sliceSource.Tracks()[iTrack].LocalTrackId()); } - return (nHits >= GPUCA_GLOBAL_TRACKING_MIN_HITS); + return (nHits >= tracker.Param().rec.tpc.globalTrackingMinHits); } GPUd() void GPUTPCGlobalTracking::PerformGlobalTracking(int nBlocks, int nThreads, int iBlock, int iThread, const GPUTPCTracker& tracker, GPUsharedref() MEM_LOCAL(GPUSharedMemory) & smem, GPUTPCTracker& GPUrestrict() sliceTarget, bool right) @@ -125,15 +125,15 @@ GPUd() void GPUTPCGlobalTracking::PerformGlobalTracking(int nBlocks, int nThread for (int i = iBlock * nThreads + iThread; i < tracker.CommonMemory()->nLocalTracks; i += nThreads * nBlocks) { { const int tmpHit = tracker.Tracks()[i].FirstHitID(); - if (tracker.TrackHits()[tmpHit].RowIndex() >= GPUCA_GLOBAL_TRACKING_MIN_ROWS && tracker.TrackHits()[tmpHit].RowIndex() < GPUCA_GLOBAL_TRACKING_RANGE) { + if (tracker.TrackHits()[tmpHit].RowIndex() >= tracker.Param().rec.tpc.globalTrackingMinRows && tracker.TrackHits()[tmpHit].RowIndex() < tracker.Param().rec.tpc.globalTrackingRowRange) { int rowIndex = tracker.TrackHits()[tmpHit].RowIndex(); const GPUTPCRow& GPUrestrict() row = tracker.Row(rowIndex); float Y = (float)tracker.Data().HitDataY(row, tracker.TrackHits()[tmpHit].HitIndex()) * row.HstepY() + row.Grid().YMin(); - if (!right && Y < -row.MaxY() * GPUCA_GLOBAL_TRACKING_Y_RANGE_LOWER) { + if (!right && Y < -row.MaxY() * tracker.Param().rec.tpc.globalTrackingYRangeLower) { // GPUInfo("Track %d, lower row %d, left border (%f of %f)", i, mTrackHits[tmpHit].RowIndex(), Y, -row.MaxY()); PerformGlobalTrackingRun(sliceTarget, smem, tracker, i, rowIndex, -tracker.Param().par.dAlpha, -1); } - if (right && Y > row.MaxY() * GPUCA_GLOBAL_TRACKING_Y_RANGE_LOWER) { + if (right && Y > row.MaxY() * tracker.Param().rec.tpc.globalTrackingYRangeLower) { // GPUInfo("Track %d, lower row %d, right border (%f of %f)", i, mTrackHits[tmpHit].RowIndex(), Y, row.MaxY()); PerformGlobalTrackingRun(sliceTarget, smem, tracker, i, rowIndex, tracker.Param().par.dAlpha, -1); } @@ -142,15 +142,15 @@ GPUd() void GPUTPCGlobalTracking::PerformGlobalTracking(int nBlocks, int nThread { const int tmpHit = tracker.Tracks()[i].FirstHitID() + tracker.Tracks()[i].NHits() - 1; - if (tracker.TrackHits()[tmpHit].RowIndex() < GPUCA_ROW_COUNT - GPUCA_GLOBAL_TRACKING_MIN_ROWS && tracker.TrackHits()[tmpHit].RowIndex() >= GPUCA_ROW_COUNT - GPUCA_GLOBAL_TRACKING_RANGE) { + if (tracker.TrackHits()[tmpHit].RowIndex() < GPUCA_ROW_COUNT - tracker.Param().rec.tpc.globalTrackingMinRows && tracker.TrackHits()[tmpHit].RowIndex() >= GPUCA_ROW_COUNT - tracker.Param().rec.tpc.globalTrackingRowRange) { int rowIndex = tracker.TrackHits()[tmpHit].RowIndex(); const GPUTPCRow& GPUrestrict() row = tracker.Row(rowIndex); float Y = (float)tracker.Data().HitDataY(row, tracker.TrackHits()[tmpHit].HitIndex()) * row.HstepY() + row.Grid().YMin(); - if (!right && Y < -row.MaxY() * GPUCA_GLOBAL_TRACKING_Y_RANGE_UPPER) { + if (!right && Y < -row.MaxY() * tracker.Param().rec.tpc.globalTrackingYRangeUpper) { // GPUInfo("Track %d, upper row %d, left border (%f of %f)", i, mTrackHits[tmpHit].RowIndex(), Y, -row.MaxY()); PerformGlobalTrackingRun(sliceTarget, smem, tracker, i, rowIndex, -tracker.Param().par.dAlpha, 1); } - if (right && Y > row.MaxY() * GPUCA_GLOBAL_TRACKING_Y_RANGE_UPPER) { + if (right && Y > row.MaxY() * tracker.Param().rec.tpc.globalTrackingYRangeUpper) { // GPUInfo("Track %d, upper row %d, right border (%f of %f)", i, mTrackHits[tmpHit].RowIndex(), Y, row.MaxY()); PerformGlobalTrackingRun(sliceTarget, smem, tracker, i, rowIndex, tracker.Param().par.dAlpha, 1); } diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx index 141c35ad800f0..bfddf3c5de8b4 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx @@ -215,7 +215,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int dy = y - tParam.Y(); dz = z - tParam.Z(); if (dy * dy > sy2 || dz * dz > sz2) { - if (++r.mNMissed >= GPUCA_TRACKLET_CONSTRUCTOR_MAX_ROW_GAP_SEED) { + if (++r.mNMissed >= tracker.Param().rec.tpc.trackFollowingMaxRowGapSeed) { r.mCurrIH = CALINK_INVAL; } rowHit = CALINK_INVAL; @@ -253,7 +253,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int if (r.mStage == 2 && iRow > r.mEndRow) { break; } - if (r.mNMissed > GPUCA_TRACKLET_CONSTRUCTOR_MAX_ROW_GAP) { + if (r.mNMissed > tracker.Param().rec.tpc.trackFollowingMaxRowGap) { r.mGo = 0; break; } @@ -328,7 +328,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int float dy = y - yUncorrected; float dz = z - zUncorrected; if (dy * dy < sy2 && dz * dz < sz2) { - float dds = GPUCA_Y_FACTOR * CAMath::Abs(dy) + CAMath::Abs(dz); + float dds = tracker.Param().rec.tpc.trackFollowingYFactor * CAMath::Abs(dy) + CAMath::Abs(dz); if (dds < ds) { ds = dds; best = ih; From a3ca94fafdca8d9acbe115f33fef6a7feacb200b Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 17 Aug 2023 16:15:12 +0200 Subject: [PATCH 051/324] TPC GPU: Debug Streamers --- .../Utils/include/CommonUtils/DebugStreamer.h | 19 ++++--- Common/Utils/src/DebugStreamer.cxx | 6 +- GPU/GPUTracking/CMakeLists.txt | 2 +- GPU/GPUTracking/GPUTrackingLinkDef_O2.h | 5 ++ GPU/GPUTracking/Merger/GPUTPCGMBorderTrack.h | 2 + GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx | 5 ++ GPU/GPUTracking/Merger/GPUTPCGMMerger.h | 5 ++ GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx | 55 +++++++++++++++++++ GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.h | 6 +- 9 files changed, 91 insertions(+), 14 deletions(-) diff --git a/Common/Utils/include/CommonUtils/DebugStreamer.h b/Common/Utils/include/CommonUtils/DebugStreamer.h index 0c1ac9af6eef7..30fc74bf2b158 100644 --- a/Common/Utils/include/CommonUtils/DebugStreamer.h +++ b/Common/Utils/include/CommonUtils/DebugStreamer.h @@ -30,15 +30,16 @@ namespace o2::utils /// struct defining the flags which can be used to check if a certain debug streamer is used enum StreamFlags { - streamdEdx = 1 << 0, ///< stream corrections and cluster properties used for the dE/dx - streamDigitFolding = 1 << 1, ///< stream ion tail and saturatio information - streamDigits = 1 << 2, ///< stream digit information - streamFastTransform = 1 << 3, ///< stream tpc fast transform - streamITCorr = 1 << 4, ///< stream ion tail correction information - streamDistortionsSC = 1 << 5, ///< stream distortions applied in the TPC space-charge class (used for example in the tpc digitizer) - streamUpdateTrack = 1 << 6, ///< stream update track informations - streamRejectCluster = 1 << 7, ///< stream cluster rejection informations - streamFlagsCount = 8 ///< total number of streamers + streamdEdx = 1 << 0, ///< stream corrections and cluster properties used for the dE/dx + streamDigitFolding = 1 << 1, ///< stream ion tail and saturatio information + streamDigits = 1 << 2, ///< stream digit information + streamFastTransform = 1 << 3, ///< stream tpc fast transform + streamITCorr = 1 << 4, ///< stream ion tail correction information + streamDistortionsSC = 1 << 5, ///< stream distortions applied in the TPC space-charge class (used for example in the tpc digitizer) + streamUpdateTrack = 1 << 6, ///< stream update track informations + streamRejectCluster = 1 << 7, ///< stream cluster rejection informations + streamMergeBorderTracks = 1 << 8, ///< stream MergeBorderTracks + streamFlagsCount = 9 ///< total number of streamers }; enum SamplingTypes { diff --git a/Common/Utils/src/DebugStreamer.cxx b/Common/Utils/src/DebugStreamer.cxx index 502c9797924c4..d146ecc808c2f 100644 --- a/Common/Utils/src/DebugStreamer.cxx +++ b/Common/Utils/src/DebugStreamer.cxx @@ -145,13 +145,15 @@ int o2::utils::DebugStreamer::getNTrees(const size_t id) const { return isStream void o2::utils::DebugStreamer::mergeTrees(const char* inpFile, const char* outFile, const char* option) { TFile fInp(inpFile, "READ"); - std::unordered_map lists; + std::unordered_map lists; for (TObject* keyAsObj : *fInp.GetListOfKeys()) { const auto key = dynamic_cast(keyAsObj); TTree* tree = (TTree*)fInp.Get(key->GetName()); // perform simple check on the number of entries to merge only TTree with same content (ToDo: Do check on name of branches) const int entries = tree->GetListOfBranches()->GetEntries(); - lists[entries].Add(tree); + const std::string brName = key->GetName(); + const std::string nameBr = brName.substr(0, brName.find_last_of("_")); + lists[nameBr].Add(tree); } TFile fOut(outFile, "RECREATE"); diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index 5591ccf8ff06d..7d31b844ce74d 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -82,7 +82,7 @@ set(SRCS_O2_DATATYPE_HEADERS set(SRCS_O2_DATATYPES ${SRCS_DATATYPES} Interface/GPUO2InterfaceConfigurableParam.cxx) -set(HDRS_CINT_O2 Merger/GPUTPCGMMergedTrack.h) +set(HDRS_CINT_O2 Merger/GPUTPCGMMergedTrack.h Merger/GPUTPCGMSliceTrack.h Merger/GPUTPCGMBorderTrack.h) set(HDRS_CINT_O2_DATATYPES DataTypes/GPUDataTypes.h DataTypes/GPUTPCGMMergedTrackHit.h) set(HDRS_CIND_O2_CONFIGURABLEPARAM Interface/GPUO2InterfaceConfigurableParam.h) set(HDRS_CINT_O2_ADDITIONAL DataTypes/GPUSettings.h Definitions/GPUSettingsList.h DataTypes/GPUDataTypes.h DataTypes/GPUTRDTrack.h DataTypes/CalibdEdxTrackTopologyPol.h DataTypes/CalibdEdxTrackTopologySpline.h) # Manual dependencies for ROOT dictionary generation diff --git a/GPU/GPUTracking/GPUTrackingLinkDef_O2.h b/GPU/GPUTracking/GPUTrackingLinkDef_O2.h index 47cf2a6f2b3d2..431e283aa6390 100644 --- a/GPU/GPUTracking/GPUTrackingLinkDef_O2.h +++ b/GPU/GPUTracking/GPUTrackingLinkDef_O2.h @@ -19,7 +19,12 @@ #pragma link off all functions; #pragma link C++ class o2::gpu::GPUTPCGMMergedTrack + ; +#pragma link C++ class o2::gpu::GPUTPCGMSliceTrack + ; +#pragma link C++ class o2::gpu::GPUTPCGMBorderTrack + ; #pragma link C++ class o2::gpu::GPUTPCGMTrackParam + ; +#pragma link C++ class o2::gpu::GPUTPCTrack + ; +#pragma link C++ struct o2::gpu::GPUTPCBaseTrackParam + ; +#pragma link C++ struct o2::gpu::GPUTPCGMSliceTrack::sliceTrackParam + ; #pragma link C++ class o2::gpu::gputpcgmmergertypes::GPUTPCOuterParam + ; #pragma link C++ class o2::gpu::gputpcgmmergertypes::InterpolationErrorHit + ; diff --git a/GPU/GPUTracking/Merger/GPUTPCGMBorderTrack.h b/GPU/GPUTracking/Merger/GPUTPCGMBorderTrack.h index 285166006db2e..7c7ab6a17d421 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMBorderTrack.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMBorderTrack.h @@ -124,6 +124,8 @@ class GPUTPCGMBorderTrack float mZOffsetLinear; // Z Offset, in case of T offset scaled linearly to Z with nominal vDrift. Used only for matching / merging float mC[5]; float mD[2]; + + ClassDefNV(GPUTPCGMBorderTrack, 1); }; } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx index 5b2f6358044fe..d752ded575504 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx @@ -906,6 +906,9 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<2>(int nBlocks, int nThreads, int CADEBUG2(continue, printf("!CE SinPhi/Tgl\n")); // Crude cut to avoid totally wrong matches, TODO: check cut } } + + GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamMergeBorderTracks, b1.TrackID())) { MergedTrackStreamer(b1, b2, "merge_all_tracks", iSlice1, iSlice2, mergeMode); }); + if (!b1.CheckChi2Y(b2, factor2ys)) { CADEBUG2(continue, printf("!Y\n")); } @@ -938,6 +941,8 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<2>(int nBlocks, int nThreads, int if (iBest2 < 0) { continue; } + GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamMergeBorderTracks, b1.TrackID())) { MergedTrackStreamer(b1, MergedTrackStreamerFindBorderTrack(B2, N2, iBest2), "merge_best_track", iSlice1, iSlice2, mergeMode); }); + // statMerged++; CADEBUG(GPUInfo("Found match %d %d", b1.TrackID(), iBest2)); diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.h b/GPU/GPUTracking/Merger/GPUTPCGMMerger.h index ac2312b2bd71f..6cba252a69710 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.h @@ -193,6 +193,11 @@ class GPUTPCGMMerger : public GPUProcessor void DumpFitPrepare(std::ostream& out); void DumpRefit(std::ostream& out); void DumpFinal(std::ostream& out); + + template + void MergedTrackStreamerInternal(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int slice1, int slice2, int mergeMode); + void MergedTrackStreamer(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int slice1, int slice2, int mergeMode); + const GPUTPCGMBorderTrack& MergedTrackStreamerFindBorderTrack(const GPUTPCGMBorderTrack* tracks, int N, int trackId); #endif private: diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx index dd3f8452e4f52..192ffec35f942 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx @@ -32,6 +32,7 @@ #include "GPUTPCGMSliceTrack.h" #include "GPUTPCGMBorderTrack.h" #include "GPUReconstruction.h" +#include "GPUDebugStreamer.h" using namespace GPUCA_NAMESPACE::gpu; using namespace gputpcgmmergertypes; @@ -180,3 +181,57 @@ void GPUTPCGMMerger::DumpFinal(std::ostream& out) out << " Cluster attachment " << i << ": " << getTrackOrderReverse(mClusterAttachment[i] & attachTrackMask) << " / " << (mClusterAttachment[i] & attachFlagMask) << "\n"; } } + +template +inline void GPUTPCGMMerger::MergedTrackStreamerInternal(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int slice1, int slice2, int mergeMode) +{ +#ifdef DEBUG_STREAMER + std::vector hits1(152), hits2(152); + for (int i = 0; i < 152; i++) { + hits1[i] = hits2[i] = -1; + } + const GPUTPCTracker& tracker1 = GetConstantMem()->tpcTrackers[slice1]; + const GPUTPCGMSliceTrack& sliceTrack1 = mSliceTrackInfos[b1.TrackID()]; + const GPUTPCTrack& inTrack1 = *sliceTrack1.OrigTrack(); + for (int i = 0; i < inTrack1.NHits(); i++) { + const GPUTPCHitId& ic1 = tracker1.TrackHits()[inTrack1.FirstHitID() + i]; + int clusterIndex = tracker1.Data().ClusterDataIndex(tracker1.Data().Row(ic1.RowIndex()), ic1.HitIndex()); + hits1[ic1.RowIndex()] = clusterIndex; + } + const GPUTPCTracker& tracker2 = GetConstantMem()->tpcTrackers[slice2]; + const GPUTPCGMSliceTrack& sliceTrack2 = mSliceTrackInfos[b2.TrackID()]; + const GPUTPCTrack& inTrack2 = *sliceTrack2.OrigTrack(); + for (int i = 0; i < inTrack2.NHits(); i++) { + const GPUTPCHitId& ic2 = tracker2.TrackHits()[inTrack2.FirstHitID() + i]; + int clusterIndex = tracker2.Data().ClusterDataIndex(tracker2.Data().Row(ic2.RowIndex()), ic2.HitIndex()); + hits2[ic2.RowIndex()] = clusterIndex; + } + + std::string debugname = std::string("debug_") + name; + std::string treename = std::string("tree_") + name; + o2::utils::DebugStreamer::instance()->getStreamer(debugname.c_str(), "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName(treename.c_str()).data() << "slice1=" << slice1 << "slice2=" << slice2 << "b1=" << b1 << "b2=" << b2 << "clusters1=" << hits1 << "clusters2=" << hits2 << "sliceTrack1=" << sliceTrack1 << "sliceTrack2=" << sliceTrack2 << "mergeMode=" << mergeMode << "\n"; +#endif +} + +void GPUTPCGMMerger::MergedTrackStreamer(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int slice1, int slice2, int mergeMode) +{ +#ifdef DEBUG_STREAMER + if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamMergeBorderTracks, b1.TrackID())) { + if (mergeMode == 0) { + MergedTrackStreamerInternal<0>(b1, b2, name, slice1, slice2, mergeMode); + } else if (mergeMode >= 1 && mergeMode <= 0) { + // MergedTrackStreamerInternal<1>(b1, b2, name, slice1, slice2, mergeMode); Not yet working + } + } +#endif +} + +const GPUTPCGMBorderTrack& GPUTPCGMMerger::MergedTrackStreamerFindBorderTrack(const GPUTPCGMBorderTrack* tracks, int N, int trackId) +{ + for (int i = 0; i < N; i++) { + if (tracks[i].TrackID() == trackId) { + return tracks[i]; + } + } + throw std::runtime_error("didn't find border track"); +} diff --git a/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.h b/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.h index 30e4307a4e51f..ec67e1848aadb 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.h @@ -119,12 +119,12 @@ class GPUTPCGMSliceTrack GPUd() bool TransportToX(GPUTPCGMMerger* merger, float x, float Bz, GPUTPCGMBorderTrack& b, float maxSinPhi, bool doCov = true) const; GPUd() bool TransportToXAlpha(GPUTPCGMMerger* merger, float x, float sinAlpha, float cosAlpha, float Bz, GPUTPCGMBorderTrack& b, float maxSinPhi) const; GPUd() void CopyBaseTrackCov(); - - private: struct sliceTrackParam { float mX, mY, mZ, mSinPhi, mDzDs, mQPt, mCosPhi, mSecPhi; // parameters float mC0, mC2, mC3, mC5, mC7, mC9, mC10, mC12, mC14; // covariances }; + + private: const GPUTPCTrack* mOrigTrack; // pointer to original slice track sliceTrackParam mParam; // Track parameters sliceTrackParam mParam2; // Parameters at other side @@ -138,6 +138,8 @@ class GPUTPCGMSliceTrack int mGlobalTrackIds[2]; // IDs of associated global tracks unsigned char mSlice; // slice of this track segment unsigned char mLeg; // Leg of this track segment + + ClassDefNV(GPUTPCGMSliceTrack, 1); }; } // namespace gpu } // namespace GPUCA_NAMESPACE From 48ea9f820d812a2c28defe59f014f28a20c4d428 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 28 Aug 2023 21:49:13 +0200 Subject: [PATCH 052/324] GPU: Add Exp function to CAMath --- GPU/Common/GPUCommonMath.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/GPU/Common/GPUCommonMath.h b/GPU/Common/GPUCommonMath.h index 1a3a18ddcbdf9..dd385853e99bc 100644 --- a/GPU/Common/GPUCommonMath.h +++ b/GPU/Common/GPUCommonMath.h @@ -81,6 +81,8 @@ class GPUCommonMath GPUhdni() static float Hypot(float x, float y, float z, float w); GPUd() static float Log(float x); + GPUd() static float Exp(float x); + template GPUdi() static T AtomicExch(GPUglobalref() GPUgeneric() GPUAtomic(T) * addr, T val) { @@ -412,6 +414,7 @@ GPUdi() float GPUCommonMath::ASin(float x) { return CHOICE(asinf(x), asinf(x), a GPUdi() float GPUCommonMath::ACos(float x) { return CHOICE(acosf(x), acosf(x), acos(x)); } GPUdi() float GPUCommonMath::Log(float x) { return CHOICE(logf(x), logf(x), log(x)); } +GPUdi() float GPUCommonMath::Exp(float x) { return CHOICE(expf(x), expf(x), exp(x)); } GPUhdi() float GPUCommonMath::Copysign(float x, float y) { From 43fb67e156e5f5007419698b86bc591f1a88918d Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 28 Aug 2023 20:48:18 +0200 Subject: [PATCH 053/324] GPU TPC: Add extra systematic cluster errors at IFC --- GPU/GPUTracking/Base/GPUParam.h | 1 + GPU/GPUTracking/Base/GPUParam.inc | 35 +++++++++++++++ GPU/GPUTracking/Definitions/GPUSettingsList.h | 44 ++++++++++--------- GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx | 2 +- GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx | 13 +++--- GPU/GPUTracking/Merger/GPUTPCGMPropagator.h | 6 +-- GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx | 12 ++--- GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h | 2 +- GPU/GPUTracking/Refit/GPUTrackingRefit.cxx | 2 +- .../GPUTPCTrackletConstructor.cxx | 8 ++++ 10 files changed, 88 insertions(+), 37 deletions(-) diff --git a/GPU/GPUTracking/Base/GPUParam.h b/GPU/GPUTracking/Base/GPUParam.h index cc3405eb9ae9f..f6fe0ed950e09 100644 --- a/GPU/GPUTracking/Base/GPUParam.h +++ b/GPU/GPUTracking/Base/GPUParam.h @@ -97,6 +97,7 @@ struct GPUParam : public internal::GPUParam_t } GPUd() float GetClusterErrorSeeding(int yz, int type, float z, float angle2) const; GPUd() void GetClusterErrorsSeeding2(int row, float z, float sinPhi, float DzDs, float& ErrY2, float& ErrZ2) const; + GPUd() float GetSystematicClusterErrorIFC2(float x, float z, bool sideC) const; GPUd() float GetClusterError2(int yz, int type, float z, float angle2) const; GPUd() void GetClusterErrors2(int row, float z, float sinPhi, float DzDs, float& ErrY2, float& ErrZ2) const; diff --git a/GPU/GPUTracking/Base/GPUParam.inc b/GPU/GPUTracking/Base/GPUParam.inc index f2ab1a0d66b5a..f05c072a42e2b 100644 --- a/GPU/GPUTracking/Base/GPUParam.inc +++ b/GPU/GPUTracking/Base/GPUParam.inc @@ -60,6 +60,35 @@ GPUdi() float MEM_LG(GPUParam)::GetClusterError2(int yz, int type, float z, floa return v; } +MEM_CLASS_PRE() +GPUdi() float MEM_LG(GPUParam)::GetSystematicClusterErrorIFC2(float x, float z, bool sideC) const +{ + const float kEpsZBoundary = 1.e-6f; // to disentangle A,C and A+C-common regions + const float kMaxExpArg = 9.f; // limit r-dumped error to this exp. argument + const float kMaxExpArgZ = CAMath::Sqrt(2.f * kMaxExpArg); + + double sysErr = 0; + if (rec.tpc.sysClusErrorInner0 > 0.f) { + double dr = CAMath::Abs(x - 85.f); + float argExp = dr / rec.tpc.sysClusErrorInner1; // is the Z-range limited ? + if (argExp < kMaxExpArg) { + if (rec.tpc.sysClusErrorZRegion < -kEpsZBoundary && !sideC) { + return 0; // don't apply to A-side clusters if the Z-boundary is for C-region + } else if (rec.tpc.sysClusErrorZRegion > kEpsZBoundary && sideC) { + return 0; // don't apply to C-side clusters if the Z-boundary is for A-region + } + const float dz = CAMath::Abs((rec.tpc.sysClusErrorZRegion-z)*rec.tpc.sysClusErrorZRegionSigInv); + if (dz < kMaxExpArgZ) { // is it small enough to call exp? + argExp += 0.5f * dz*dz; + if (argExp 500, auto = 1000)") AddOptionRTC(zsThreshold, float, 2.0f, "", 0, "Zero-Suppression threshold") AddOptionRTC(tubeChi2, float, 5.f * 5.f, "", 0, "Max chi2 to mark cluster adjacent to track") @@ -56,25 +60,25 @@ AddOptionRTC(tubeMaxSize2, float, 2.5f * 2.5f, "", 0, "Square of max tube size ( AddOptionRTC(clustersShiftTimebins, float, 0, "", 0, "Shift of TPC clusters (applied during CTF cluster decoding)") AddOptionRTC(clustersShiftTimebinsClusterizer, float, 0, "", 0, "Shift of TPC clusters (applied during CTF clusterization)") AddOptionRTC(defaultZOffsetOverR, float, 0.5210953f, "", 0, "Shift of TPC clusters (applied during CTF cluster decoding)") -AddOptionRTC(PID_EKrangeMin, float, 0.38, "", 0, "min P of electron/K BB bands crossing") -AddOptionRTC(PID_EKrangeMax, float, 0.48, "", 0, "max P of electron/K BB bands crossing") -AddOptionRTC(PID_EPrangeMin, float, 0.75, "", 0, "min P of electron/p BB bands crossing") -AddOptionRTC(PID_EPrangeMax, float, 0.85, "", 0, "max P of electron/p BB bands crossing") -AddOptionRTC(extraClusterErrorEdgeY2, float, 0.35, "", 0, "Additive extra cluster error for Y2 if edge flag set") -AddOptionRTC(extraClusterErrorEdgeZ2, float, 0.15, "", 0, "Additive extra cluster error for Z2 if edge flag set") -AddOptionRTC(extraClusterErrorSingleY2, float, 0.2, "", 0, "Additive extra cluster error for Y2 if edge single set") -AddOptionRTC(extraClusterErrorSingleZ2, float, 0.2, "", 0, "Additive extra cluster error for Z2 if edge single set") -AddOptionRTC(extraClusterErrorSplitPadSharedSingleY2, float, 0.03, "", 0, "Additive extra cluster error for Y2 if splitpad, shared, or single set") -AddOptionRTC(extraClusterErrorFactorSplitPadSharedSingleY2, float, 3.0, "", 0, "Multiplicative extra cluster error for Y2 if splitpad, shared, or single set") -AddOptionRTC(extraClusterErrorSplitTimeSharedSingleZ2, float, 0.03, "", 0, "Additive extra cluster error for Z2 if splittime, shared, or single set") -AddOptionRTC(extraClusterErrorFactorSplitTimeSharedSingleZ2, float, 3.0, "", 0, "Multiplicative extra cluster error for Z2 if splittime, shared, or single set") -AddOptionRTC(globalTrackingYRangeUpper, float, 0.85, "", 0, "Inner portion of y-range in slice that is not used in searching for global track candidates") -AddOptionRTC(globalTrackingYRangeLower, float, 0.85, "", 0, "Inner portion of y-range in slice that is not used in searching for global track candidates") -AddOptionRTC(trackFollowingYFactor, float, 4, "", 0, "Weight of y residual vs z residual in tracklet constructor") -AddOptionRTC(trackMergerFactor2YS, float, 1.5 * 1.5, "", 0, "factor2YS for track merging") -AddOptionRTC(trackMergerFactor2ZT, float, 1.5 * 1.5, "", 0, "factor2ZT for track merging") -AddOptionRTC(trackMergerFactor2K, float, 2.0 * 2.0, "", 0, "factor2K for track merging") -AddOptionRTC(trackMergerFactor2General, float, 3.5 * 3.5, "", 0, "General factor for track merging") +AddOptionRTC(PID_EKrangeMin, float, 0.38f, "", 0, "min P of electron/K BB bands crossing") +AddOptionRTC(PID_EKrangeMax, float, 0.48f, "", 0, "max P of electron/K BB bands crossing") +AddOptionRTC(PID_EPrangeMin, float, 0.75f, "", 0, "min P of electron/p BB bands crossing") +AddOptionRTC(PID_EPrangeMax, float, 0.85f, "", 0, "max P of electron/p BB bands crossing") +AddOptionRTC(extraClusterErrorEdgeY2, float, 0.35f, "", 0, "Additive extra cluster error for Y2 if edge flag set") +AddOptionRTC(extraClusterErrorEdgeZ2, float, 0.15f, "", 0, "Additive extra cluster error for Z2 if edge flag set") +AddOptionRTC(extraClusterErrorSingleY2, float, 0.2f, "", 0, "Additive extra cluster error for Y2 if edge single set") +AddOptionRTC(extraClusterErrorSingleZ2, float, 0.2f, "", 0, "Additive extra cluster error for Z2 if edge single set") +AddOptionRTC(extraClusterErrorSplitPadSharedSingleY2, float, 0.03f, "", 0, "Additive extra cluster error for Y2 if splitpad, shared, or single set") +AddOptionRTC(extraClusterErrorFactorSplitPadSharedSingleY2, float, 3.0f, "", 0, "Multiplicative extra cluster error for Y2 if splitpad, shared, or single set") +AddOptionRTC(extraClusterErrorSplitTimeSharedSingleZ2, float, 0.03f, "", 0, "Additive extra cluster error for Z2 if splittime, shared, or single set") +AddOptionRTC(extraClusterErrorFactorSplitTimeSharedSingleZ2, float, 3.0f, "", 0, "Multiplicative extra cluster error for Z2 if splittime, shared, or single set") +AddOptionRTC(globalTrackingYRangeUpper, float, 0.85f, "", 0, "Inner portion of y-range in slice that is not used in searching for global track candidates") +AddOptionRTC(globalTrackingYRangeLower, float, 0.85f, "", 0, "Inner portion of y-range in slice that is not used in searching for global track candidates") +AddOptionRTC(trackFollowingYFactor, float, 4.f, "", 0, "Weight of y residual vs z residual in tracklet constructor") +AddOptionRTC(trackMergerFactor2YS, float, 1.5f * 1.5f, "", 0, "factor2YS for track merging") +AddOptionRTC(trackMergerFactor2ZT, float, 1.5f * 1.5f, "", 0, "factor2ZT for track merging") +AddOptionRTC(trackMergerFactor2K, float, 2.0f * 2.0f, "", 0, "factor2K for track merging") +AddOptionRTC(trackMergerFactor2General, float, 3.5f * 3.5f, "", 0, "General factor for track merging") AddOptionRTC(maxTimeBinAboveThresholdIn1000Bin, unsigned short, 500, "", 0, "Except pad from cluster finding if total number of charges in a fragment is above this baseline (disable = 0)") AddOptionRTC(maxConsecTimeBinAboveThreshold, unsigned short, 200, "", 0, "Except pad from cluster finding if number of consecutive charges in a fragment is above this baseline (disable = 0)") AddOptionRTC(noisyPadSaturationThreshold, unsigned short, 700, "", 0, "Threshold where a timebin is considered saturated, disabling the noisy pad check for that pad") diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx index d752ded575504..01872cb5d2c64 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx @@ -507,7 +507,7 @@ GPUd() int GPUTPCGMMerger::RefitSliceTrack(GPUTPCGMSliceTrack& sliceTrack, const return way == 0; } trk.ConstrainSinPhi(); - if (prop.Update(y, z, row, Param(), flags & GPUTPCGMMergedTrackHit::clustererAndSharedFlags, 0, nullptr, false)) { + if (prop.Update(y, z, row, Param(), flags & GPUTPCGMMergedTrackHit::clustererAndSharedFlags, 0, nullptr, false, slice > 18)) { return way == 0; } trk.ConstrainSinPhi(); diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx index 7318950ff1b8f..5b2b86c49842c 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx @@ -597,7 +597,7 @@ GPUd() int GPUTPCGMPropagator::GetPropagatedYZ(float x, float& GPUrestrict() pro return 0; } -GPUd() void GPUTPCGMPropagator::GetErr2(float& GPUrestrict() err2Y, float& GPUrestrict() err2Z, const GPUParam& GPUrestrict() param, float posZ, int iRow, short clusterState) const +GPUd() void GPUTPCGMPropagator::GetErr2(float& GPUrestrict() err2Y, float& GPUrestrict() err2Z, const GPUParam& GPUrestrict() param, float posZ, int iRow, short clusterState, bool sideC) const { #ifndef GPUCA_TPC_GEOMETRY_O2 if (mSeedingErrors) { @@ -608,13 +608,16 @@ GPUd() void GPUTPCGMPropagator::GetErr2(float& GPUrestrict() err2Y, float& GPUre param.GetClusterErrors2(iRow, posZ, mT0.GetSinPhi(), mT0.DzDs(), err2Y, err2Z); } param.UpdateClusterError2ByState(clusterState, err2Y, err2Z); + float statErr2 = param.GetSystematicClusterErrorIFC2(mT->GetX(), posZ, sideC); + err2Y += statErr2; + err2Z += statErr2; mStatErrors.GetOfflineStatisticalErrors(err2Y, err2Z, mT0.SinPhi(), mT0.DzDs(), clusterState); } -GPUd() float GPUTPCGMPropagator::PredictChi2(float posY, float posZ, int iRow, const GPUParam& GPUrestrict() param, short clusterState) const +GPUd() float GPUTPCGMPropagator::PredictChi2(float posY, float posZ, int iRow, const GPUParam& GPUrestrict() param, short clusterState, bool sideC) const { float err2Y, err2Z; - GetErr2(err2Y, err2Z, param, posZ, iRow, clusterState); + GetErr2(err2Y, err2Z, param, posZ, iRow, clusterState, sideC); return PredictChi2(posY, posZ, err2Y, err2Z); } @@ -645,10 +648,10 @@ GPUd() float GPUTPCGMPropagator::PredictChi2(float posY, float posZ, float err2Y } } -GPUd() int GPUTPCGMPropagator::Update(float posY, float posZ, int iRow, const GPUParam& GPUrestrict() param, short clusterState, char rejectChi2, gputpcgmmergertypes::InterpolationErrorHit* inter, bool refit GPUCA_DEBUG_STREAMER_CHECK(, int iTrk)) +GPUd() int GPUTPCGMPropagator::Update(float posY, float posZ, int iRow, const GPUParam& GPUrestrict() param, short clusterState, char rejectChi2, gputpcgmmergertypes::InterpolationErrorHit* inter, bool refit, bool sideC GPUCA_DEBUG_STREAMER_CHECK(, int iTrk)) { float err2Y, err2Z; - GetErr2(err2Y, err2Z, param, posZ, iRow, clusterState); + GetErr2(err2Y, err2Z, param, posZ, iRow, clusterState, sideC); if (rejectChi2 >= 2) { if (rejectChi2 == 3 && inter->errorY < (GPUCA_MERGER_INTERPOLATION_ERROR_TYPE)0) { diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h index 7c0f071dd977e..77a4eb7cdc123 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h @@ -99,10 +99,10 @@ class GPUTPCGMPropagator GPUd() int PropagateToXAlphaBz(float posX, float posAlpha, bool inFlyDirection); - GPUd() int Update(float posY, float posZ, int iRow, const GPUParam& param, short clusterState, char rejectChi2, gputpcgmmergertypes::InterpolationErrorHit* inter, bool refit GPUCA_DEBUG_STREAMER_CHECK(, int iTrk = 0)); + GPUd() int Update(float posY, float posZ, int iRow, const GPUParam& param, short clusterState, char rejectChi2, gputpcgmmergertypes::InterpolationErrorHit* inter, bool refit, bool sideC GPUCA_DEBUG_STREAMER_CHECK(, int iTrk = 0)); GPUd() int Update(float posY, float posZ, short clusterState, bool rejectChi2, float err2Y, float err2Z, const GPUParam* param = nullptr); GPUd() int InterpolateReject(const GPUParam& param, float posY, float posZ, short clusterState, char rejectChi2, gputpcgmmergertypes::InterpolationErrorHit* inter, float err2Y, float err2Z); - GPUd() float PredictChi2(float posY, float posZ, int iRow, const GPUParam& param, short clusterState) const; + GPUd() float PredictChi2(float posY, float posZ, int iRow, const GPUParam& param, short clusterState, bool sideC) const; GPUd() float PredictChi2(float posY, float posZ, float err2Y, float err2Z) const; GPUd() int RejectCluster(float chiY, float chiZ, unsigned char clusterState) { @@ -128,7 +128,7 @@ class GPUTPCGMPropagator /// Bx,By,Bz in local coordinates rotated to Alpha GPUd() void GetBxByBz(float Alpha, float X, float Y, float Z, float B[3]) const; - GPUd() void GetErr2(float& err2Y, float& err2Z, const GPUParam& param, float posZ, int iRow, short clusterState) const; + GPUd() void GetErr2(float& err2Y, float& err2Z, const GPUParam& param, float posZ, int iRow, short clusterState, bool sideC) const; GPUd() float GetAlpha() const { return mAlpha; } GPUd() void SetAlpha(float v) { mAlpha = v; } diff --git a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx index 738418d5ae8e4..3c88951d20e38 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx @@ -197,7 +197,7 @@ GPUd() bool GPUTPCGMTrackParam::Fit(GPUTPCGMMerger* GPUrestrict() merger, int iT } } if (tryFollow) { - MirrorTo(prop, yy, zz, inFlyDirection, param, clusters[ihit].row, clusterState, false); + MirrorTo(prop, yy, zz, inFlyDirection, param, clusters[ihit].row, clusterState, false, clusters[ihit].slice > 18); lastUpdateX = mX; lastLeg = clusters[ihit].leg; lastSlice = clusters[ihit].slice; @@ -249,7 +249,7 @@ GPUd() bool GPUTPCGMTrackParam::Fit(GPUTPCGMMerger* GPUrestrict() merger, int iT if (allowModification) { AttachClustersMirror<0>(merger, clusters[ihit].slice, clusters[ihit].row, iTrk, yy, prop); // TODO: Never true, will always call FollowCircle above, really??? } - MirrorTo(prop, yy, zz, inFlyDirection, param, clusters[ihit].row, clusterState, true); + MirrorTo(prop, yy, zz, inFlyDirection, param, clusters[ihit].row, clusterState, true, clusters[ihit].slice > 18); noFollowCircle = false; lastUpdateX = mX; @@ -307,7 +307,7 @@ GPUd() bool GPUTPCGMTrackParam::Fit(GPUTPCGMMerger* GPUrestrict() merger, int iT tup.Fill((float)clusters[ihit].row, xx, yy, zz, clAlpha, mX, ImP0, ImP1, mP[2], mP[3], mP[4], ImC0, ImC2, mC[14]); } #endif - retVal = prop.Update(yy, zz, clusters[ihit].row, param, clusterState, rejectChi2, &interpolation.hit[ihit], refit GPUCA_DEBUG_STREAMER_CHECK(, iTrk)); + retVal = prop.Update(yy, zz, clusters[ihit].row, param, clusterState, rejectChi2, &interpolation.hit[ihit], refit, clusters[ihit].slice > 18 GPUCA_DEBUG_STREAMER_CHECK(, iTrk)); GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamUpdateTrack, iTrk)) { o2::utils::DebugStreamer::instance()->getStreamer("debug_update_track", "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName("tree_update_track").data() << "iTrk=" << iTrk << "ihit=" << ihit << "yy=" << yy << "zz=" << zz << "cluster=" << clusters[ihit] << "track=" << this << "rejectChi2=" << rejectChi2 << "interpolationhit=" << interpolation.hit[ihit] << "refit=" << refit << "retVal=" << retVal << "\n"; }) @@ -421,13 +421,13 @@ GPUdni() void GPUTPCGMTrackParam::MoveToReference(GPUTPCGMPropagator& prop, cons } } -GPUd() void GPUTPCGMTrackParam::MirrorTo(GPUTPCGMPropagator& GPUrestrict() prop, float toY, float toZ, bool inFlyDirection, const GPUParam& param, unsigned char row, unsigned char clusterState, bool mirrorParameters) +GPUd() void GPUTPCGMTrackParam::MirrorTo(GPUTPCGMPropagator& GPUrestrict() prop, float toY, float toZ, bool inFlyDirection, const GPUParam& param, unsigned char row, unsigned char clusterState, bool mirrorParameters, bool cSide) { if (mirrorParameters) { prop.Mirror(inFlyDirection); } float err2Y, err2Z; - prop.GetErr2(err2Y, err2Z, param, toZ, row, clusterState); + prop.GetErr2(err2Y, err2Z, param, toZ, row, clusterState, cSide); prop.Model().Y() = mP[0] = toY; prop.Model().Z() = mP[1] = toZ; if (mC[0] < err2Y) { @@ -452,7 +452,7 @@ GPUd() int GPUTPCGMTrackParam::MergeDoubleRowClusters(int& ihit, int wayDirectio { if (ihit + wayDirection >= 0 && ihit + wayDirection < maxN && clusters[ihit].row == clusters[ihit + wayDirection].row && clusters[ihit].slice == clusters[ihit + wayDirection].slice && clusters[ihit].leg == clusters[ihit + wayDirection].leg) { float maxDistY, maxDistZ; - prop.GetErr2(maxDistY, maxDistZ, merger->Param(), zz, clusters[ihit].row, 0); + prop.GetErr2(maxDistY, maxDistZ, merger->Param(), zz, clusters[ihit].row, 0, clusters[ihit].slice > 18); maxDistY = (maxDistY + mC[0]) * 20.f; maxDistZ = (maxDistZ + mC[2]) * 20.f; int noReject = 0; // Cannot reject if simple estimation of y/z fails (extremely unlike case) diff --git a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h index 594936991e21e..282c6752011af 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h @@ -145,7 +145,7 @@ class GPUTPCGMTrackParam GPUd() bool Fit(GPUTPCGMMerger* merger, int iTrk, GPUTPCGMMergedTrackHit* clusters, GPUTPCGMMergedTrackHitXYZ* clustersXYZ, int& N, int& NTolerated, float& Alpha, int attempt = 0, float maxSinPhi = GPUCA_MAX_SIN_PHI, gputpcgmmergertypes::GPUTPCOuterParam* outerParam = nullptr); GPUd() void MoveToReference(GPUTPCGMPropagator& prop, const GPUParam& param, float& alpha); - GPUd() void MirrorTo(GPUTPCGMPropagator& prop, float toY, float toZ, bool inFlyDirection, const GPUParam& param, unsigned char row, unsigned char clusterState, bool mirrorParameters); + GPUd() void MirrorTo(GPUTPCGMPropagator& prop, float toY, float toZ, bool inFlyDirection, const GPUParam& param, unsigned char row, unsigned char clusterState, bool mirrorParameters, bool cSide); GPUd() int MergeDoubleRowClusters(int& ihit, int wayDirection, GPUTPCGMMergedTrackHit* clusters, GPUTPCGMMergedTrackHitXYZ* clustersXYZ, const GPUTPCGMMerger* merger, GPUTPCGMPropagator& prop, float& xx, float& yy, float& zz, int maxN, float clAlpha, unsigned char& clusterState, bool rejectChi2); GPUd() void AttachClustersPropagate(const GPUTPCGMMerger* GPUrestrict() Merger, int slice, int lastRow, int toRow, int iTrack, bool goodLeg, GPUTPCGMPropagator& prop, bool inFlyDirection, float maxSinPhi = GPUCA_MAX_SIN_PHI); diff --git a/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx b/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx index 3fd29ab96a31b..6bc3b1405fd5e 100644 --- a/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx +++ b/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx @@ -328,7 +328,7 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) trk.ResetCovariance(); } CADEBUG(printf("\t%21sPropaga Alpha %8.3f , X %8.3f - Y %8.3f, Z %8.3f - QPt %7.2f (%7.2f), SP %5.2f (%5.2f) --- Res %8.3f %8.3f --- Cov sY %8.3f sZ %8.3f sSP %8.3f sPt %8.3f - YPt %8.3f\n", "", prop.GetAlpha(), x, trk.Par()[0], trk.Par()[1], trk.Par()[4], prop.GetQPt0(), trk.Par()[2], prop.GetSinPhi0(), trk.Par()[0] - y, trk.Par()[1] - z, sqrtf(trk.Cov()[0]), sqrtf(trk.Cov()[2]), sqrtf(trk.Cov()[5]), sqrtf(trk.Cov()[14]), trk.Cov()[10])); - if (prop.Update(y, z, row, *mPparam, clusterState, 0, nullptr, true)) { + if (prop.Update(y, z, row, *mPparam, clusterState, 0, nullptr, true, sector > 18)) { IgnoreErrors(trk.GetSinPhi()); return -3; } diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx index bfddf3c5de8b4..3d059b1f4970e 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx @@ -203,6 +203,9 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int tracker.GetErrors2Seeding(iRow, tParam.GetZ(), sinPhi, tParam.GetDzDs(), err2Y, err2Z); if (r.mNHits >= 10) { + const float sErr2 = tracker.Param().GetSystematicClusterErrorIFC2(x, tParam.GetZ(), tracker.ISlice() > 18); + err2Y += sErr2; + err2Z += sErr2; const float kFactor = tracker.Param().rec.tpc.hitPickUpFactor * tracker.Param().rec.tpc.hitPickUpFactor * 3.5f * 3.5f; float sy2 = kFactor * (tParam.Err2Y() + err2Y); float sz2 = kFactor * (tParam.Err2Z() + err2Z); @@ -298,6 +301,11 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int float err2Y, err2Z; tracker.GetErrors2Seeding(iRow, *((MEM_LG2(GPUTPCTrackParam)*)&tParam), err2Y, err2Z); + if (r.mNHits >= 10) { + const float sErr2 = tracker.Param().GetSystematicClusterErrorIFC2(x, tParam.GetZ(), tracker.ISlice() > 18); + err2Y += sErr2; + err2Z += sErr2; + } if (CAMath::Abs(yUncorrected) < x * MEM_GLOBAL(GPUTPCRow)::getTPCMaxY1X()) { // search for the closest hit const float kFactor = tracker.Param().rec.tpc.hitPickUpFactor * tracker.Param().rec.tpc.hitPickUpFactor * 7.0f * 7.0f; const float maxWindow2 = tracker.Param().rec.tpc.hitSearchArea2; From 5f19cee1edf5af8334c66a929e7db06ddaeeabef Mon Sep 17 00:00:00 2001 From: David Rohr Date: Tue, 29 Aug 2023 18:09:20 +0200 Subject: [PATCH 054/324] GPU: Add functions to add errors to GPU track model covariance --- GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx | 21 +++++++++++++++++++ GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h | 3 +++ 2 files changed, 24 insertions(+) diff --git a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx index 3c88951d20e38..352d1993fefd5 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx @@ -1183,3 +1183,24 @@ GPUd() void GPUTPCGMTrackParam::Rotate(float alpha) mC[11] = -mC[11]; } } + +GPUd() void GPUTPCGMTrackParam::AddCovDiagErrors(const float* GPUrestrict() errors2) +{ + mC[0] += errors2[0]; + mC[2] += errors2[1]; + mC[5] += errors2[2]; + mC[9] += errors2[3]; + mC[14] += errors2[4]; +} + +GPUd() void GPUTPCGMTrackParam::AddCovDiagErrorsWithCorrelations(const float* GPUrestrict() errors2) +{ + const int diagMap[5] = {0, 2, 5, 9, 14}; + const float oldDiag[5] = {mC[0], mC[2], mC[5], mC[9], mC[14]}; + for (int i = 0; i < 5; i++) { + mC[diagMap[i]] += errors2[i]; + for (int j = 0; j < i; j++) { + mC[diagMap[i - 1] + j + 1] *= gpu::CAMath::Sqrt(mC[diagMap[i]] * mC[diagMap[j]] / (oldDiag[i] * oldDiag[j])); + } + } +} diff --git a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h index 282c6752011af..4dd66924bf6f4 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.h @@ -160,6 +160,9 @@ class GPUTPCGMTrackParam GPUd() void StoreOuter(gputpcgmmergertypes::GPUTPCOuterParam* outerParam, const GPUTPCGMPropagator& prop, int phase); GPUd() static void RefitLoop(const GPUTPCGMMerger* GPUrestrict() Merger, int loopIdx); + GPUd() void AddCovDiagErrors(const float* GPUrestrict() errors2); + GPUd() void AddCovDiagErrorsWithCorrelations(const float* GPUrestrict() errors2); + GPUdi() void MarkClusters(GPUTPCGMMergedTrackHit* GPUrestrict() clusters, int ihitFirst, int ihitLast, int wayDirection, unsigned char state) { clusters[ihitFirst].state |= state; From 41afb955a6f170c580a96f094635ba026a00a001 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 14 Sep 2023 07:46:04 +0200 Subject: [PATCH 055/324] GPU: Temporary workaround to avoid false GCC compiler warnings --- GPU/GPUTracking/Refit/GPUTrackingRefit.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx b/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx index 6bc3b1405fd5e..73f77dbecb275 100644 --- a/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx +++ b/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx @@ -249,7 +249,7 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) short clusterState = 0, nextState; int nFitted = 0; for (int i = start; i != stop; i += cl ? 0 : direction) { - float x, y, z, charge = 0.f; + float x = 0, y = 0, z = 0, charge = 0; // FIXME: initialization unneeded, but GCC incorrectly produces uninitialized warnings otherwise int clusters = 0; while (true) { if (!cl) { From 8e4e1f9e44628227a5e57b06442768561403f71e Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 14 Sep 2023 07:47:07 +0200 Subject: [PATCH 056/324] GPU Configuration: can use C array configurable as constexpr in RTC --- .../GPUO2InterfaceConfigurableParam.cxx | 4 ++++ .../GPUO2InterfaceConfigurableParam.h | 2 ++ GPU/GPUTracking/utils/qconfig.h | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx index e4063ff922730..da625dd704ab6 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx @@ -26,6 +26,7 @@ using namespace o2::gpu; #define AddOptionSet(name, type, value, optname, optnameshort, help, ...) #define AddOptionVec(name, type, optname, optnameshort, help, ...) #define AddOptionArray(name, type, count, default, optname, optnameshort, help, ...) +#define AddOptionArrayRTC(...) AddOptionArray(__VA_ARGS__) #define AddSubConfig(name, instance) #define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, o2prefix) O2ParamImpl(GPUCA_M_CAT(GPUConfigurableParam, name)) #define BeginHiddenConfig(...) @@ -43,6 +44,7 @@ using namespace o2::gpu; #undef AddOptionSet #undef AddOptionVec #undef AddOptionArray +#undef AddOptionArrayRTC #undef AddSubConfig #undef BeginSubConfig #undef BeginHiddenConfig @@ -65,6 +67,7 @@ GPUSettingsO2 GPUO2InterfaceConfiguration::ReadConfigurableParam_internal() for (int i = 0; i < count; i++) { \ dst.name[i] = src.name[i]; \ } +#define AddOptionArrayRTC(...) AddOptionArray(__VA_ARGS__) #define AddSubConfig(name, instance) dst.instance = instance; #define BeginSubConfig(name, instance, parent, preoptname, preoptnameshort, descr, o2prefix) \ name instance; \ @@ -86,6 +89,7 @@ GPUSettingsO2 GPUO2InterfaceConfiguration::ReadConfigurableParam_internal() #undef AddOptionSet #undef AddOptionVec #undef AddOptionArray +#undef AddOptionArrayRTC #undef AddSubConfig #undef BeginSubConfig #undef BeginHiddenConfig diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.h b/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.h index cd2d037a11c11..bb92eca425336 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.h @@ -62,6 +62,7 @@ #define AddHelp(...) #define AddShortcut(...) #define AddOptionRTC(...) AddOption(__VA_ARGS__) +#define AddOptionArrayRTC(...) AddOptionArray(__VA_ARGS__) #include "GPUSettingsList.h" #undef BeginNamespace #undef EndNamespace @@ -72,6 +73,7 @@ #undef AddOptionSet #undef AddOptionVec #undef AddOptionArray +#undef AddOptionArrayRTC #undef AddSubConfig #undef BeginSubConfig #undef BeginHiddenConfig diff --git a/GPU/GPUTracking/utils/qconfig.h b/GPU/GPUTracking/utils/qconfig.h index ae9de854772ac..b58b40a1d3b36 100644 --- a/GPU/GPUTracking/utils/qconfig.h +++ b/GPU/GPUTracking/utils/qconfig.h @@ -254,6 +254,17 @@ enum qConfigRetVal { qcrOK = 0, AddOption(name, type, default, optname, optnameshort, help); \ } #define AddOptionRTC(name, type, default, optname, optnameshort, help, ...) AddVariableRTC(name, type, default) +#define AddOptionArrayRTC(name, type, count, default, optname, optnameshort, help, ...) \ + if (useConstexpr) { \ + out << "static constexpr " << qon_mxstr(type) << " " << qon_mxstr(name) << "[" << count << "] = {" << qConfig::print_type(std::get(tSrc)->name[0]); \ + for (int i = 1; i < count; i++) { \ + out << ", " << qConfig::print_type(std::get(tSrc)->name[i]); \ + } \ + out << "};\n"; \ + out << qon_mxstr(type) << " " << qon_mxstr(qon_mxcat(_dummy_, name)) << ";\n"; \ + } else { \ + AddOptionArray(name, type, count, default, optname, optnameshort, help); \ + } #define BeginConfig(name, instance) \ { \ using qConfigCurrentType = name; \ @@ -297,6 +308,10 @@ enum qConfigRetVal { qcrOK = 0, static constexpr type name = default; \ type _dummy_##name = default; #define AddOptionRTC(name, type, default, optname, optnameshort, help, ...) AddVariableRTC(name, type, default) +#define _AddOptionArray_INTERNAL_EXPAND(...) __VA_ARGS__ +#define AddOptionArrayRTC(name, type, count, default, optname, optnameshort, help, ...) \ + static constexpr type name[count] = {_AddOptionArray_INTERNAL_EXPAND default}; \ + type _dummy_##name[count] = {_AddOptionArray_INTERNAL_EXPAND default}; #else #define AddCustomCPP(...) __VA_ARGS__ #endif @@ -345,6 +360,9 @@ enum qConfigRetVal { qcrOK = 0, #ifndef AddVariableRTC #define AddVariableRTC(...) AddVariable(__VA_ARGS__) #endif +#ifndef AddOptionArrayRTC +#define AddOptionArrayRTC(...) AddOptionArray(__VA_ARGS__) +#endif #ifndef BeginHiddenConfig #define BeginHiddenConfig(name, instance) BeginSubConfig(name, instance, , , , ) #endif @@ -358,6 +376,7 @@ enum qConfigRetVal { qcrOK = 0, #undef AddOptionSet #undef AddOptionVec #undef AddOptionArray +#undef AddOptionArrayRTC #undef AddArrayDefaults #undef AddSubConfig #undef BeginConfig From b9d1d31bcb6756677188cbc390d87e3e97cb852d Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 14 Sep 2023 07:47:24 +0200 Subject: [PATCH 057/324] GPU TPC: Add optional additional track errors when crossing the central electrode --- GPU/GPUTracking/Definitions/GPUSettingsList.h | 2 ++ GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx | 15 +++++++++--- GPU/GPUTracking/Refit/GPUTrackingRefit.cxx | 24 +++++++++++++++++-- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 3ca270ad39872..c3942404d4190 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -72,6 +72,7 @@ AddOptionRTC(extraClusterErrorSplitPadSharedSingleY2, float, 0.03f, "", 0, "Addi AddOptionRTC(extraClusterErrorFactorSplitPadSharedSingleY2, float, 3.0f, "", 0, "Multiplicative extra cluster error for Y2 if splitpad, shared, or single set") AddOptionRTC(extraClusterErrorSplitTimeSharedSingleZ2, float, 0.03f, "", 0, "Additive extra cluster error for Z2 if splittime, shared, or single set") AddOptionRTC(extraClusterErrorFactorSplitTimeSharedSingleZ2, float, 3.0f, "", 0, "Multiplicative extra cluster error for Z2 if splittime, shared, or single set") +AddOptionArrayRTC(errorsCECrossing, float, 5, (0.f, 0.f, 0.f, 0.f, 0.f), "", 0, "Extra errors to add to track when crossing CE, depending on addErrorsCECrossing") AddOptionRTC(globalTrackingYRangeUpper, float, 0.85f, "", 0, "Inner portion of y-range in slice that is not used in searching for global track candidates") AddOptionRTC(globalTrackingYRangeLower, float, 0.85f, "", 0, "Inner portion of y-range in slice that is not used in searching for global track candidates") AddOptionRTC(trackFollowingYFactor, float, 4.f, "", 0, "Weight of y residual vs z residual in tracklet constructor") @@ -83,6 +84,7 @@ AddOptionRTC(maxTimeBinAboveThresholdIn1000Bin, unsigned short, 500, "", 0, "Exc AddOptionRTC(maxConsecTimeBinAboveThreshold, unsigned short, 200, "", 0, "Except pad from cluster finding if number of consecutive charges in a fragment is above this baseline (disable = 0)") AddOptionRTC(noisyPadSaturationThreshold, unsigned short, 700, "", 0, "Threshold where a timebin is considered saturated, disabling the noisy pad check for that pad") AddOptionRTC(trackFitCovLimit, unsigned short, 1000, "", 0, "Abort fit when y/z cov exceed the limit") +AddOption(addErrorsCECrossing, unsigned char, 0, "", 0, "Add additional custom track errors when crossing CE, 0 = no custom errors but att 0.5 to sigma_z^2, 1 = only to cov diagonal, 2 = preserve correlations") AddOptionRTC(trackMergerMinPartHits, unsigned char, 10, "", 0, "Minimum hits of track part during track merging") AddOptionRTC(trackMergerMinTotalHits, unsigned char, 20, "", 0, "Minimum total of track part during track merging") AddOptionRTC(mergerCERowLimit, unsigned char, 5, "", 0, "Distance from first / last row in order to attempt merging accross CE") diff --git a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx index 352d1993fefd5..907e7e8cd7627 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx @@ -129,9 +129,6 @@ GPUd() bool GPUTPCGMTrackParam::Fit(GPUTPCGMMerger* GPUrestrict() merger, int iT if (crossCE) { lastSlice = clusters[ihit].slice; noFollowCircle2 = true; - if (mC[2] < 0.5f) { - mC[2] = 0.5f; - } } if (storeOuter == 2 && clusters[ihit].leg == clusters[maxN - 1].leg - 1) { @@ -241,6 +238,18 @@ GPUd() bool GPUTPCGMTrackParam::Fit(GPUTPCGMMerger* GPUrestrict() merger, int iT CADEBUG(printf("\t%21sPropaga Alpha %8.3f , X %8.3f - Y %8.3f, Z %8.3f - QPt %7.2f (%7.2f), SP %5.2f (%5.2f) --- Res %8.3f %8.3f --- Cov sY %8.3f sZ %8.3f sSP %8.3f sPt %8.3f - YPt %8.3f - Err %d", "", prop.GetAlpha(), mX, mP[0], mP[1], mP[4], prop.GetQPt0(), mP[2], prop.GetSinPhi0(), mP[0] - yy, mP[1] - zz, sqrtf(mC[0]), sqrtf(mC[2]), sqrtf(mC[5]), sqrtf(mC[14]), mC[10], err)); // clang-format on + if (crossCE) { + if (param.rec.tpc.addErrorsCECrossing) { + if (param.rec.tpc.addErrorsCECrossing >= 2) { + AddCovDiagErrorsWithCorrelations(param.rec.tpc.errorsCECrossing); + } else { + AddCovDiagErrors(param.rec.tpc.errorsCECrossing); + } + } else if (mC[2] < 0.5f) { + mC[2] = 0.5f; + } + } + if (err == 0 && changeDirection) { const float mirrordY = prop.GetMirroredYTrack(); CADEBUG(printf(" -- MirroredY: %f --> %f", mP[0], mirrordY)); diff --git a/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx b/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx index 73f77dbecb275..f90f4193f6156 100644 --- a/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx +++ b/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx @@ -245,8 +245,9 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) int start = outward ? count - 1 : begin; int stop = outward ? begin - 1 : count; const ClusterNative* cl = nullptr; - uint8_t sector, row = 0, currentSector = 0, currentRow = 0; - short clusterState = 0, nextState; + uint8_t sector = 255, row = 255; + int lastSector = -1, currentSector = -1, currentRow = -1; + short clusterState = 0, nextState = 0; int nFitted = 0; for (int i = start; i != stop; i += cl ? 0 : direction) { float x = 0, y = 0, z = 0, charge = 0; // FIXME: initialization unneeded, but GCC incorrectly produces uninitialized warnings otherwise @@ -324,10 +325,22 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) IgnoreErrors(trk.GetSinPhi()); return -2; } + if (lastSector != -1 && (lastSector < 18) != (sector < 18)) { + if (mPparam->rec.tpc.addErrorsCECrossing) { + if (mPparam->rec.tpc.addErrorsCECrossing >= 2) { + trk.AddCovDiagErrorsWithCorrelations(mPparam->rec.tpc.errorsCECrossing); + } else { + trk.AddCovDiagErrors(mPparam->rec.tpc.errorsCECrossing); + } + } else if (trk.Cov()[2] < 0.5f) { + trk.Cov()[2] = 0.5f; + } + } if (resetCov) { trk.ResetCovariance(); } CADEBUG(printf("\t%21sPropaga Alpha %8.3f , X %8.3f - Y %8.3f, Z %8.3f - QPt %7.2f (%7.2f), SP %5.2f (%5.2f) --- Res %8.3f %8.3f --- Cov sY %8.3f sZ %8.3f sSP %8.3f sPt %8.3f - YPt %8.3f\n", "", prop.GetAlpha(), x, trk.Par()[0], trk.Par()[1], trk.Par()[4], prop.GetQPt0(), trk.Par()[2], prop.GetSinPhi0(), trk.Par()[0] - y, trk.Par()[1] - z, sqrtf(trk.Cov()[0]), sqrtf(trk.Cov()[2]), sqrtf(trk.Cov()[5]), sqrtf(trk.Cov()[14]), trk.Cov()[10])); + lastSector = sector; if (prop.Update(y, z, row, *mPparam, clusterState, 0, nullptr, true, sector > 18)) { IgnoreErrors(trk.GetSinPhi()); return -3; @@ -342,6 +355,13 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) IgnoreErrors(trk.getSnp()); return -2; } + if (lastSector != -1 && (lastSector < 18) != (sector < 18)) { + if (mPparam->rec.tpc.addErrorsCECrossing) { + trk.updateCov(mPparam->rec.tpc.errorsCECrossing, mPparam->rec.tpc.addErrorsCECrossing >= 2); + } else if (trk.getCov()[2] < 0.5f) { + trk.setCov(0.5f, 2); + } + } if (resetCov) { trk.resetCovariance(); float bzkG = prop->getNominalBz(), qptB5Scale = CAMath::Abs(bzkG) > 0.1 ? CAMath::Abs(bzkG) / 5.006680f : 1.f; From db4d76067c164749f650a599b29f50a69e74aa12 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sat, 16 Sep 2023 22:39:33 +0200 Subject: [PATCH 058/324] GPU TPC: Fix application of additional cluster errors on SeedingErrors --- GPU/GPUTracking/Base/GPUParam.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GPUTracking/Base/GPUParam.inc b/GPU/GPUTracking/Base/GPUParam.inc index f05c072a42e2b..2cb5f2275b13d 100644 --- a/GPU/GPUTracking/Base/GPUParam.inc +++ b/GPU/GPUTracking/Base/GPUParam.inc @@ -115,8 +115,8 @@ GPUdi() void MEM_LG(GPUParam)::GetClusterErrorsSeeding2(int iRow, float z, float ErrY2 = GetClusterErrorSeeding(0, rowType, z, angleY2); ErrZ2 = GetClusterErrorSeeding(1, rowType, z, angleZ2); - ErrY2 *= ErrY2 * rec.tpc.clusterError2CorrectionY + rec.tpc.clusterError2AdditionalY; - ErrZ2 *= ErrZ2 * rec.tpc.clusterError2CorrectionZ + rec.tpc.clusterError2AdditionalZ; + ErrY2 = ErrY2 * ErrY2 * rec.tpc.clusterError2CorrectionY + rec.tpc.clusterError2AdditionalY; + ErrZ2 = ErrZ2 * ErrZ2 * rec.tpc.clusterError2CorrectionZ + rec.tpc.clusterError2AdditionalZ; } MEM_CLASS_PRE() From b53bc2cd6ce0468e56003d05cb6ca3aeb587d110 Mon Sep 17 00:00:00 2001 From: shahoian Date: Mon, 18 Sep 2023 14:15:28 +0200 Subject: [PATCH 059/324] fix misleading comment in the dpl-workflow --- prodtests/full-system-test/dpl-workflow.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 5f0c585b2417c..9bc2e738a50f9 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -31,7 +31,7 @@ fi : ${CTF_MAX_FREE_DISK_WAIT:="600"} # if not enough disk space after this time throw error # entropy encoding/decoding mode, default "" is equivalent to '--ans-version compat' (compatible with < 09/2023 data), -# use '--ans-version 1.0 --ccdb-dict none' for the new per-TF dictionary mode +# use '--ans-version 1.0 --ctf-dict none' for the new per-TF dictionary mode : ${RANS_OPT:=""} workflow_has_parameter CTF && export SAVECTF=1 From 2e970ab1a27494301fa80a4d5a024f47aa018a27 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 18 Sep 2023 09:55:10 +0200 Subject: [PATCH 060/324] GPU: Fix compilation without O2 headers --- GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx b/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx index 5c42cd2f3bdf3..6cc0f9f12ecf3 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx @@ -249,6 +249,7 @@ void GPUChainTracking::PrintOutputStat() void GPUChainTracking::SanityCheck() { +#ifdef GPUCA_HAVE_O2HEADERS size_t nErrors = 0; for (unsigned int i = 0; i < mIOPtrs.nOutputTracksTPCO2; i++) { @@ -289,4 +290,5 @@ void GPUChainTracking::SanityCheck() } else { GPUError("Sanity check found %lu errors", nErrors); } +#endif } From 47caba44b0837ab659530c40d6f3b2682007f042 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 18 Sep 2023 09:56:09 +0200 Subject: [PATCH 061/324] GPU: Remove obsolete functions --- GPU/GPUTracking/Global/GPUChainTracking.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index 7b5fca14e8bf0..df4947a522fc8 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -189,11 +189,6 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega void SetUpdateCalibObjects(const GPUCalibObjectsConst& obj, const GPUNewCalibValues& vals); void SetDefaultInternalO2Propagator(bool useGPUField); void LoadClusterErrors(); - void SetOutputControlCompressedClusters(GPUOutputControl* v) { mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::compressedClusters)] = v; } - void SetOutputControlClustersNative(GPUOutputControl* v) { mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clustersNative)] = v; } - void SetOutputControlTPCTracks(GPUOutputControl* v) { mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTracks)] = v; } - void SetOutputControlClusterLabels(GPUOutputControl* v) { mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clusterLabels)] = v; } - void SetOutputControlSharedClusterMap(GPUOutputControl* v) { mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::sharedClusterMap)] = v; } void SetSubOutputControl(int i, GPUOutputControl* v) { mSubOutputControls[i] = v; } const GPUSettingsDisplay* mConfigDisplay = nullptr; // Abstract pointer to Standalone Display Configuration Structure From 77d1fcf4e51f1017439d3f41cf5fb37eb67d166a Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 18 Sep 2023 14:37:51 +0200 Subject: [PATCH 062/324] GPU: Some cleanup --- GPU/GPUTracking/Base/GPUMemoryResource.h | 2 -- GPU/GPUTracking/Base/GPUReconstruction.cxx | 2 +- .../include/GPUWorkflow/GPUWorkflowSpec.h | 6 ++--- GPU/Workflow/src/GPUWorkflowSpec.cxx | 24 +++++++++---------- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/GPU/GPUTracking/Base/GPUMemoryResource.h b/GPU/GPUTracking/Base/GPUMemoryResource.h index 0d73da0f8b5f7..b8967787d7399 100644 --- a/GPU/GPUTracking/Base/GPUMemoryResource.h +++ b/GPU/GPUTracking/Base/GPUMemoryResource.h @@ -78,12 +78,10 @@ class GPUMemoryResource ALLOCATION_INDIVIDUAL = 1, ALLOCATION_GLOBAL = 2 }; -#ifndef GPUCA_GPUCODE GPUMemoryResource(GPUProcessor* proc, void* (GPUProcessor::*setPtr)(void*), MemoryType type, const char* name = "") : mProcessor(proc), mPtr(nullptr), mPtrDevice(nullptr), mSetPointers(setPtr), mName(name), mSize(0), mOverrideSize(0), mReuse(-1), mType(type) { } GPUMemoryResource(const GPUMemoryResource&) CON_DEFAULT; -#endif void* SetPointers(void* ptr) { diff --git a/GPU/GPUTracking/Base/GPUReconstruction.cxx b/GPU/GPUTracking/Base/GPUReconstruction.cxx index 94a9a446ca6db..166c02889d439 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.cxx +++ b/GPU/GPUTracking/Base/GPUReconstruction.cxx @@ -531,7 +531,7 @@ size_t GPUReconstruction::AllocateRegisteredMemoryHelper(GPUMemoryResource* res, return retVal; } if (memorypool == nullptr) { - GPUInfo("Memory pool uninitialized"); + GPUError("Cannot allocate memory from uninitialized pool"); throw std::bad_alloc(); } size_t retVal; diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index 38324b974f078..e06fa669635a1 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -84,6 +84,8 @@ class GPURecoWorkflowSpec : public o2::framework::Task using CompletionPolicyData = std::vector; struct Config { + int itsTriggerType = 0; + int lumiScaleMode = 0; bool decompressTPC = false; bool decompressTPCFromROOT = false; bool caClusterer = false; @@ -104,9 +106,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task bool requireCTPLumi = false; bool outputErrorQA = false; bool runITSTracking = false; - int itsTriggerType = 0; bool itsOverrBeamEst = false; - int lumiScaleMode = 0; }; GPURecoWorkflowSpec(CompletionPolicyData* policyData, Config const& specconfig, std::vector const& tpcsectors, unsigned long tpcSectorMask, std::shared_ptr& ggr); @@ -134,7 +134,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task bool fetchCalibsCCDBTPC(o2::framework::ProcessingContext& pc, T& newCalibObjects); bool fetchCalibsCCDBITS(o2::framework::ProcessingContext& pc); /// storing the new calib objects by overwritting the old calibs - void storeUpdatedCalibsTPCPtrs(); + void cleanOldCalibsTPCPtrs(); void doCalibUpdates(o2::framework::ProcessingContext& pc); diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 58a1ea70b2638..51841e85dc398 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -720,7 +720,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) o2::utils::DebugStreamer::instance()->flush(); // setting TPC calibration objects - storeUpdatedCalibsTPCPtrs(); + cleanOldCalibsTPCPtrs(); mTracker->Clear(false); @@ -1312,17 +1312,17 @@ Outputs GPURecoWorkflowSpec::outputs() } if (mSpecConfig.runITSTracking) { - outputSpecs.emplace_back("ITS", "TRACKS", 0, Lifetime::Timeframe); - outputSpecs.emplace_back("ITS", "TRACKCLSID", 0, Lifetime::Timeframe); - outputSpecs.emplace_back("ITS", "ITSTrackROF", 0, Lifetime::Timeframe); - outputSpecs.emplace_back("ITS", "VERTICES", 0, Lifetime::Timeframe); - outputSpecs.emplace_back("ITS", "VERTICESROF", 0, Lifetime::Timeframe); - outputSpecs.emplace_back("ITS", "IRFRAMES", 0, Lifetime::Timeframe); + outputSpecs.emplace_back(gDataOriginITS, "TRACKS", 0, Lifetime::Timeframe); + outputSpecs.emplace_back(gDataOriginITS, "TRACKCLSID", 0, Lifetime::Timeframe); + outputSpecs.emplace_back(gDataOriginITS, "ITSTrackROF", 0, Lifetime::Timeframe); + outputSpecs.emplace_back(gDataOriginITS, "VERTICES", 0, Lifetime::Timeframe); + outputSpecs.emplace_back(gDataOriginITS, "VERTICESROF", 0, Lifetime::Timeframe); + outputSpecs.emplace_back(gDataOriginITS, "IRFRAMES", 0, Lifetime::Timeframe); if (mSpecConfig.processMC) { - outputSpecs.emplace_back("ITS", "VERTICESMCTR", 0, Lifetime::Timeframe); - outputSpecs.emplace_back("ITS", "TRACKSMCTR", 0, Lifetime::Timeframe); - outputSpecs.emplace_back("ITS", "ITSTrackMC2ROF", 0, Lifetime::Timeframe); + outputSpecs.emplace_back(gDataOriginITS, "VERTICESMCTR", 0, Lifetime::Timeframe); + outputSpecs.emplace_back(gDataOriginITS, "TRACKSMCTR", 0, Lifetime::Timeframe); + outputSpecs.emplace_back(gDataOriginITS, "ITSTrackMC2ROF", 0, Lifetime::Timeframe); } } @@ -1681,16 +1681,14 @@ bool GPURecoWorkflowSpec::fetchCalibsCCDBTPC(ProcessingContext& pc, T& newCalibO return false; } -void GPURecoWorkflowSpec::storeUpdatedCalibsTPCPtrs() +void GPURecoWorkflowSpec::cleanOldCalibsTPCPtrs() { if (mdEdxCalibContainerBufferNew) { mdEdxCalibContainer = std::move(mdEdxCalibContainerBufferNew); } - if (mTPCPadGainCalibBufferNew) { mTPCPadGainCalib = std::move(mTPCPadGainCalibBufferNew); } - if (mFastTransformNew) { mFastTransform = std::move(mFastTransformNew); } From f3db0813a6910f499fced65dccd1176cef0e79bf Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 18 Sep 2023 14:36:45 +0200 Subject: [PATCH 063/324] GPU TPC: Add trigger word handling during GPU decoding --- .../include/TPCWorkflow/RecoWorkflow.h | 1 + Detectors/TPC/workflow/src/RecoWorkflow.cxx | 4 +- .../TPC/workflow/src/tpc-reco-workflow.cxx | 2 +- GPU/GPUTracking/CMakeLists.txt | 1 + GPU/GPUTracking/DataTypes/GPUOutputControl.h | 1 + GPU/GPUTracking/DataTypes/GPUTriggerOutputs.h | 52 +++++++++++++++++++ GPU/GPUTracking/Definitions/GPUSettingsList.h | 1 + GPU/GPUTracking/Global/GPUChainTracking.cxx | 3 +- GPU/GPUTracking/Global/GPUChainTracking.h | 2 + .../Global/GPUChainTrackingClusterizer.cxx | 31 +++++++++++ GPU/GPUTracking/Global/GPUChainTrackingIO.cxx | 1 + .../include/GPUWorkflow/GPUWorkflowSpec.h | 1 + GPU/Workflow/src/GPUWorkflowSpec.cxx | 5 ++ GPU/Workflow/src/gpu-reco-workflow.cxx | 9 ++-- prodtests/full-system-test/dpl-workflow.sh | 1 + 15 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 GPU/GPUTracking/DataTypes/GPUTriggerOutputs.h diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h b/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h index f9a945cef7434..6d4275398ab5d 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h @@ -65,6 +65,7 @@ enum struct OutputType { Digits, ZSRaw, QA, NoSharedClusterMap, + TPCTriggers }; using CompletionPolicyData = std::vector; diff --git a/Detectors/TPC/workflow/src/RecoWorkflow.cxx b/Detectors/TPC/workflow/src/RecoWorkflow.cxx index 6f49db19b3c29..d409ffbf6e593 100644 --- a/Detectors/TPC/workflow/src/RecoWorkflow.cxx +++ b/Detectors/TPC/workflow/src/RecoWorkflow.cxx @@ -91,7 +91,8 @@ const std::unordered_map OutputMap{ {"send-clusters-per-sector", OutputType::SendClustersPerSector}, {"zsraw", OutputType::ZSRaw}, {"qa", OutputType::QA}, - {"no-shared-cluster-map", OutputType::NoSharedClusterMap}}; + {"no-shared-cluster-map", OutputType::NoSharedClusterMap}, + {"tpc-triggers", OutputType::TPCTriggers}}; framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vector const& tpcSectors, unsigned long tpcSectorMask, std::vector const& laneConfiguration, bool propagateMC, unsigned nLanes, std::string const& cfgInput, std::string const& cfgOutput, bool disableRootInput, @@ -445,6 +446,7 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto cfg.processMC = propagateMC; cfg.sendClustersPerSector = isEnabled(OutputType::SendClustersPerSector); cfg.askDISTSTF = askDISTSTF; + cfg.tpcTriggerHandling = isEnabled(OutputType::TPCTriggers); Inputs ggInputs; auto ggRequest = std::make_shared(false, true, false, true, true, o2::base::GRPGeomRequest::Aligned, ggInputs, true); diff --git a/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx b/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx index 89bd5151faa64..f72405cbebf7f 100644 --- a/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx +++ b/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx @@ -56,7 +56,7 @@ void customize(std::vector& workflowOptions) std::vector options{ {"input-type", VariantType::String, "digits", {"digitizer, digits, zsraw, clustershw, clusters, compressed-clusters, compressed-clusters-ctf, pass-through"}}, - {"output-type", VariantType::String, "tracks", {"digits, zsraw, clustershw, clusters, tracks, compressed-clusters, encoded-clusters, disable-writer, send-clusters-per-sector, qa, no-shared-cluster-map"}}, + {"output-type", VariantType::String, "tracks", {"digits, zsraw, clustershw, clusters, tracks, compressed-clusters, encoded-clusters, disable-writer, send-clusters-per-sector, qa, no-shared-cluster-map, tpc-triggers"}}, {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, {"no-ca-clusterer", VariantType::Bool, false, {"Use HardwareClusterer instead of clusterer of GPUCATracking"}}, {"disable-mc", VariantType::Bool, false, {"disable sending of MC information"}}, diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index 7d31b844ce74d..c01aa66519903 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -153,6 +153,7 @@ set(HDRS_INSTALL DataTypes/GPUO2FakeClasses.h Definitions/GPUSettingsList.h DataTypes/GPUOutputControl.h + DataTypes/GPUTriggerOutputs.h DataTypes/GPUO2DataTypes.h DataTypes/GPUHostDataTypes.h DataTypes/GPUdEdxInfo.h diff --git a/GPU/GPUTracking/DataTypes/GPUOutputControl.h b/GPU/GPUTracking/DataTypes/GPUOutputControl.h index 4db0fc9eec37d..639b92e9aa381 100644 --- a/GPU/GPUTracking/DataTypes/GPUOutputControl.h +++ b/GPU/GPUTracking/DataTypes/GPUOutputControl.h @@ -74,6 +74,7 @@ struct GPUTrackingOutputs { GPUOutputControl tpcTracksO2; GPUOutputControl tpcTracksO2ClusRefs; GPUOutputControl tpcTracksO2Labels; + GPUOutputControl tpcTriggerWords; static constexpr size_t count() { return sizeof(GPUTrackingOutputs) / sizeof(GPUOutputControl); } GPUOutputControl* asArray() { return (GPUOutputControl*)this; } diff --git a/GPU/GPUTracking/DataTypes/GPUTriggerOutputs.h b/GPU/GPUTracking/DataTypes/GPUTriggerOutputs.h new file mode 100644 index 0000000000000..41427e331cab2 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUTriggerOutputs.h @@ -0,0 +1,52 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUTriggerOutputs.h +/// \author David Rohr + +#ifndef GPUTRIGGEROUTPUTS_H +#define GPUTRIGGEROUTPUTS_H + +#include "GPUCommonDef.h" +#include +#include +#ifdef GPUCA_HAVE_O2HEADERS +#include "DataFormatsTPC/ZeroSuppression.h" +#endif + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ + +struct GPUTriggerOutputs { +#ifdef GPUCA_HAVE_O2HEADERS + struct hasher { + size_t operator()(const std::array& key) const + { + std::hash std_hasher; + size_t result = 0; + for (size_t i = 0; i < key.size(); ++i) { + result ^= std_hasher(key[i]); + } + return result; + } + }; + + std::unordered_set, hasher> triggers; + static_assert(o2::tpc::TPCZSHDRV2::TRIGGER_WORD_SIZE % sizeof(unsigned long) == 0); +#endif +}; + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index c3942404d4190..d718cf1cacc8d 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -178,6 +178,7 @@ EndConfig() BeginSubConfig(GPUSettingsProcessingParam, param, configStandalone.proc, "PARAM", 0, "Processing settings", proc_param) AddOptionArray(tpcErrorParamY, float, 4, (0.06, 0.24, 0.12, 0.1), "", 0, "TPC Cluster Y Error Parameterization") AddOptionArray(tpcErrorParamZ, float, 4, (0.06, 0.24, 0.15, 0.1), "", 0, "TPC Cluster Z Error Parameterization") +AddOption(tpcTriggerHandling, bool, false, "", 0, "Enable TPC trigger handling") AddHelp("help", 'h') EndConfig() diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index b4c078f6200eb..dbb95870d9275 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -42,6 +42,7 @@ #include "GPUMemorySizeScalers.h" #include "GPUTrackingInputProvider.h" #include "GPUNewCalibValues.h" +#include "GPUTriggerOutputs.h" #ifdef GPUCA_HAVE_O2HEADERS #include "GPUTPCClusterStatistics.h" @@ -65,7 +66,7 @@ using namespace GPUCA_NAMESPACE::gpu; using namespace o2::tpc; using namespace o2::trd; -GPUChainTracking::GPUChainTracking(GPUReconstruction* rec, unsigned int maxTPCHits, unsigned int maxTRDTracklets) : GPUChain(rec), mIOPtrs(processors()->ioPtrs), mInputsHost(new GPUTrackingInputProvider), mInputsShadow(new GPUTrackingInputProvider), mClusterNativeAccess(new ClusterNativeAccess), mMaxTPCHits(maxTPCHits), mMaxTRDTracklets(maxTRDTracklets), mDebugFile(new std::ofstream) +GPUChainTracking::GPUChainTracking(GPUReconstruction* rec, unsigned int maxTPCHits, unsigned int maxTRDTracklets) : GPUChain(rec), mIOPtrs(processors()->ioPtrs), mInputsHost(new GPUTrackingInputProvider), mInputsShadow(new GPUTrackingInputProvider), mClusterNativeAccess(new ClusterNativeAccess), mTriggerBuffer(new GPUTriggerOutputs), mMaxTPCHits(maxTPCHits), mMaxTRDTracklets(maxTRDTracklets), mDebugFile(new std::ofstream) { ClearIOPointers(); mFlatObjectsShadow.mChainTracking = this; diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index df4947a522fc8..3bf3fbaa2f371 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -64,6 +64,7 @@ class GPUTrackingInputProvider; struct GPUChainTrackingFinalContext; struct GPUTPCCFChainContext; struct GPUNewCalibValues; +struct GPUTriggerOutputs; class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelegateBase { @@ -266,6 +267,7 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega // Ptrs to internal buffers std::unique_ptr mClusterNativeAccess; std::array mSubOutputControls = {nullptr}; + std::unique_ptr mTriggerBuffer; // (Ptrs to) configuration objects std::unique_ptr mCFContext; diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index 338493b989033..e522cbd52a5f2 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -24,6 +24,7 @@ #include "CommonDataFormat/InteractionRecord.h" #endif #ifdef GPUCA_HAVE_O2HEADERS +#include "GPUTriggerOutputs.h" #include "GPUHostDataTypes.h" #include "GPUTPCCFChainContext.h" #include "DataFormatsTPC/ZeroSuppression.h" @@ -198,6 +199,15 @@ std::pair GPUChainTracking::TPCClusterizerDecodeZSCo const TPCZSHDR* const hdr = (const TPCZSHDR*)(rdh_utils::getLink(o2::raw::RDHUtils::getFEEID(*rdh)) == rdh_utils::DLBZSLinkID ? (page + o2::raw::RDHUtils::getMemorySize(*rdh) - sizeof(TPCZSHDRV2)) : (page + sizeof(o2::header::RAWDataHeader))); if (mCFContext->zsVersion == -1) { mCFContext->zsVersion = hdr->version; + if (GetProcessingSettings().param.tpcTriggerHandling && mCFContext->zsVersion < ZSVersion::ZSVersionDenseLinkBased) { + GPUError("Trigger handling only possible with TPC Dense Link Based data, received version %d", mCFContext->zsVersion); + if (GetProcessingSettings().ignoreNonFatalGPUErrors) { + mCFContext->abandonTimeframe = true; + return {0, 0}; + } else { + GPUFatal("Cannot process with invalid TPC ZS data, exiting"); + } + } } else if (mCFContext->zsVersion != (int)hdr->version) { GPUError("Received TPC ZS 8kb page of mixed versions, expected %d, received %d (linkid %d, feeCRU %d, feeEndpoint %d, feelinkid %d)", mCFContext->zsVersion, (int)hdr->version, (int)o2::raw::RDHUtils::getLinkID(*rdh), (int)rdh_utils::getCRU(*rdh), (int)rdh_utils::getEndPoint(*rdh), (int)rdh_utils::getLink(*rdh)); constexpr size_t bufferSize = 3 * std::max(sizeof(*rdh), sizeof(*hdr)) + 1; @@ -219,6 +229,15 @@ std::pair GPUChainTracking::TPCClusterizerDecodeZSCo GPUFatal("Cannot process with invalid TPC ZS data, exiting"); } } + if (GetProcessingSettings().param.tpcTriggerHandling) { + const TPCZSHDRV2* const hdr2 = (const TPCZSHDRV2*)hdr; + if (hdr2->flags & TPCZSHDRV2::ZSFlags::TriggerWordPresent) { + const char* triggerWord = (const char*)hdr - TPCZSHDRV2::TRIGGER_WORD_SIZE; + std::array tmp; + memcpy((void*)tmp.data(), triggerWord, TPCZSHDRV2::TRIGGER_WORD_SIZE); + mTriggerBuffer->triggers.emplace(tmp); + } + } nDigits += hdr->nADCsamples; endpointAdcSamples[j] += hdr->nADCsamples; unsigned int timeBin = (hdr->timeOffset + (o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstHBF) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN; @@ -459,6 +478,9 @@ int GPUChainTracking::RunTPCClusterizer_prepare(bool restorePointers) if (mIOPtrs.tpcZS) { unsigned int nDigitsFragmentMax[NSLICES]; mCFContext->zsVersion = -1; + if (GetProcessingSettings().param.tpcTriggerHandling) { + mTriggerBuffer->triggers.clear(); + } for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { if (mIOPtrs.tpcZS->slice[iSlice].count[0]) { const void* rdh = mIOPtrs.tpcZS->slice[iSlice].zsPtr[0][0]; @@ -484,6 +506,15 @@ int GPUChainTracking::RunTPCClusterizer_prepare(bool restorePointers) processors()->tpcClusterer[iSlice].mPmemory->counters.nDigits = x.first; mRec->MemoryScalers()->nTPCdigits += x.first; } + if (GetProcessingSettings().param.tpcTriggerHandling) { + GPUOutputControl* triggerOutput = mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTriggerWords)]; + if (triggerOutput && triggerOutput->allocator) { + GPUInfo("Storing %lu trigger words", mTriggerBuffer->triggers.size()); + auto* outputBuffer = (decltype(mTriggerBuffer->triggers)::value_type*)triggerOutput->allocator(mTriggerBuffer->triggers.size() * sizeof(decltype(mTriggerBuffer->triggers)::value_type)); + std::copy(mTriggerBuffer->triggers.begin(), mTriggerBuffer->triggers.end(), outputBuffer); + } + mTriggerBuffer->triggers.clear(); + } for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { unsigned int nDigitsBase = nDigitsFragmentMax[iSlice]; unsigned int threshold = 40000000; diff --git a/GPU/GPUTracking/Global/GPUChainTrackingIO.cxx b/GPU/GPUTracking/Global/GPUChainTrackingIO.cxx index 443186f5d3305..c1068c15ae740 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingIO.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingIO.cxx @@ -33,6 +33,7 @@ #include "GPUMemorySizeScalers.h" #include "GPUTrackingInputProvider.h" #include "TPCZSLinkMapping.h" +#include "GPUTriggerOutputs.h" #ifdef GPUCA_HAVE_O2HEADERS #include "SimulationDataFormat/MCCompLabel.h" diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index e06fa669635a1..9711356c62aeb 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -107,6 +107,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task bool outputErrorQA = false; bool runITSTracking = false; bool itsOverrBeamEst = false; + bool tpcTriggerHandling = false; }; GPURecoWorkflowSpec(CompletionPolicyData* policyData, Config const& specconfig, std::vector const& tpcsectors, unsigned long tpcSectorMask, std::shared_ptr& ggr); diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 51841e85dc398..12faeb00a65e5 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -230,6 +230,7 @@ void GPURecoWorkflowSpec::init(InitContext& ic) mConfig->configProcessing.outputSharedClusterMap = true; } mConfig->configProcessing.createO2Output = mSpecConfig.outputTracks ? 2 : 0; // Disable O2 TPC track format output if no track output requested + mConfig->configProcessing.param.tpcTriggerHandling = mSpecConfig.tpcTriggerHandling; if (mConfParam->transformationFile.size() || mConfParam->transformationSCFile.size()) { LOG(fatal) << "Deprecated configurable param options GPU_global.transformationFile or transformationSCFile used\n" @@ -639,6 +640,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) setOutputAllocator("TRACKS", mSpecConfig.outputTracks, outputRegions.tpcTracksO2, std::make_tuple(gDataOriginTPC, (DataDescription) "TRACKS", 0)); setOutputAllocator("CLUSREFS", mSpecConfig.outputTracks, outputRegions.tpcTracksO2ClusRefs, std::make_tuple(gDataOriginTPC, (DataDescription) "CLUSREFS", 0)); setOutputAllocator("TRACKSMCLBL", mSpecConfig.outputTracks && mSpecConfig.processMC, outputRegions.tpcTracksO2Labels, std::make_tuple(gDataOriginTPC, (DataDescription) "TRACKSMCLBL", 0)); + setOutputAllocator("TRIGGERWORDS", mSpecConfig.zsDecoder && mConfig->configProcessing.param.tpcTriggerHandling, outputRegions.tpcTriggerWords, std::make_tuple(gDataOriginTPC, (DataDescription) "TRIGGERWORDS", 0)); o2::tpc::ClusterNativeHelper::ConstMCLabelContainerViewWithBuffer clustersMCBuffer; if (mSpecConfig.processMC && mSpecConfig.caClusterer) { outputRegions.clusterLabels.allocator = [&clustersMCBuffer](size_t size) -> void* { return &clustersMCBuffer; }; @@ -1304,6 +1306,9 @@ Outputs GPURecoWorkflowSpec::outputs() if (mSpecConfig.outputSharedClusterMap) { outputSpecs.emplace_back(gDataOriginTPC, "CLSHAREDMAP", 0, Lifetime::Timeframe); } + if (mSpecConfig.tpcTriggerHandling) { + outputSpecs.emplace_back(gDataOriginTPC, "TRIGGERWORDS", 0, Lifetime::Timeframe); + } if (mSpecConfig.outputQA) { outputSpecs.emplace_back(gDataOriginTPC, "TRACKINGQA", 0, Lifetime::Timeframe); } diff --git a/GPU/Workflow/src/gpu-reco-workflow.cxx b/GPU/Workflow/src/gpu-reco-workflow.cxx index d73408e984862..fb8ff66683e70 100644 --- a/GPU/Workflow/src/gpu-reco-workflow.cxx +++ b/GPU/Workflow/src/gpu-reco-workflow.cxx @@ -50,7 +50,7 @@ void customize(std::vector& workflowOptions) std::vector options{ {"input-type", VariantType::String, "digits", {"digitizer, digits, zsraw, zsonthefly, clustersnative, compressed-clusters-root, compressed-clusters-ctf, trd-tracklets"}}, - {"output-type", VariantType::String, "tracks", {"clustersnative, tracks, compressed-clusters-ctf, qa, no-shared-cluster-map, send-clusters-per-sector, trd-tracks, error-qa"}}, + {"output-type", VariantType::String, "tracks", {"clustersnative, tracks, compressed-clusters-ctf, qa, no-shared-cluster-map, send-clusters-per-sector, trd-tracks, error-qa, tpc-triggers"}}, {"require-ctp-lumi", VariantType::Bool, false, {"require CTP lumi for TPC correction scaling"}}, {"disable-root-input", VariantType::Bool, true, {"disable root-files input reader"}}, {"disable-mc", VariantType::Bool, false, {"disable sending of MC information"}}, @@ -100,7 +100,8 @@ enum struct ioType { Digits, NoSharedMap, SendClustersPerSector, ITSClusters, - ITSTracks }; + ITSTracks, + TPCTriggers }; static const std::unordered_map InputMap{ {"digits", ioType::Digits}, @@ -121,7 +122,8 @@ static const std::unordered_map OutputMap{ {"no-shared-cluster-map", ioType::NoSharedMap}, {"send-clusters-per-sector", ioType::SendClustersPerSector}, {"trd-tracks", ioType::TRDTracks}, - {"its-tracks", ioType::ITSTracks}}; + {"its-tracks", ioType::ITSTracks}, + {"tpc-triggers", ioType::TPCTriggers}}; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { @@ -169,6 +171,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) cfg.askDISTSTF = !cfgc.options().get("ignore-dist-stf"); cfg.readTRDtracklets = isEnabled(inputTypes, ioType::TRDTracklets); cfg.runTRDTracking = isEnabled(outputTypes, ioType::TRDTracks); + cfg.tpcTriggerHandling = isEnabled(outputTypes, ioType::TPCTriggers); Inputs ggInputs; auto ggRequest = std::make_shared(false, true, false, true, true, o2::base::GRPGeomRequest::Aligned, ggInputs, true); diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 9bc2e738a50f9..72be2394217c6 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -175,6 +175,7 @@ workflow_has_parameter CALIB && [[ $CALIB_TPC_VDRIFTTGL == 1 ]] && SEND_ITSTPC_D PVERTEXING_CONFIG_KEY+="${ITSMFT_STROBES};" has_processing_step ENTROPY_ENCODER && has_detector_ctf TPC && GPU_OUTPUT+=",compressed-clusters-ctf" +[[ ${TPC_ENABLE_TRIGGER_HANDLING:-} == 1 ]] && GPU_OUTPUT+=",tpc-triggers" if [[ $SYNCMODE == 1 ]] && workflow_has_parameter QC && has_detector_qc TPC; then GPU_OUTPUT+=",qa,error-qa" From 351f8c54687bd2ffd6390fd692f00b2405b769c9 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 18 Sep 2023 16:51:24 +0200 Subject: [PATCH 064/324] GPU: Do not reupload unmodified calib objects to GPU --- GPU/GPUTracking/Global/GPUChainTracking.cxx | 29 +++++++++++++-------- GPU/GPUTracking/Global/GPUChainTracking.h | 2 +- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index dbb95870d9275..f271afca78967 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -402,53 +402,53 @@ int GPUChainTracking::Init() return 0; } -void GPUChainTracking::UpdateGPUCalibObjects(int stream) +void GPUChainTracking::UpdateGPUCalibObjects(int stream, const GPUCalibObjectsConst* ptrMask) { - if (processors()->calibObjects.fastTransform) { + if (processors()->calibObjects.fastTransform && (ptrMask == nullptr || ptrMask->fastTransform)) { memcpy((void*)mFlatObjectsShadow.mCalibObjects.fastTransform, (const void*)processors()->calibObjects.fastTransform, sizeof(*processors()->calibObjects.fastTransform)); memcpy((void*)mFlatObjectsShadow.mTpcTransformBuffer, (const void*)processors()->calibObjects.fastTransform->getFlatBufferPtr(), processors()->calibObjects.fastTransform->getFlatBufferSize()); mFlatObjectsShadow.mCalibObjects.fastTransform->clearInternalBufferPtr(); mFlatObjectsShadow.mCalibObjects.fastTransform->setActualBufferAddress(mFlatObjectsShadow.mTpcTransformBuffer); mFlatObjectsShadow.mCalibObjects.fastTransform->setFutureBufferAddress(mFlatObjectsDevice.mTpcTransformBuffer); } - if (processors()->calibObjects.fastTransformRef) { + if (processors()->calibObjects.fastTransformRef && (ptrMask == nullptr || ptrMask->fastTransformRef)) { memcpy((void*)mFlatObjectsShadow.mCalibObjects.fastTransformRef, (const void*)processors()->calibObjects.fastTransformRef, sizeof(*processors()->calibObjects.fastTransformRef)); memcpy((void*)mFlatObjectsShadow.mTpcTransformRefBuffer, (const void*)processors()->calibObjects.fastTransformRef->getFlatBufferPtr(), processors()->calibObjects.fastTransformRef->getFlatBufferSize()); mFlatObjectsShadow.mCalibObjects.fastTransformRef->clearInternalBufferPtr(); mFlatObjectsShadow.mCalibObjects.fastTransformRef->setActualBufferAddress(mFlatObjectsShadow.mTpcTransformRefBuffer); mFlatObjectsShadow.mCalibObjects.fastTransformRef->setFutureBufferAddress(mFlatObjectsDevice.mTpcTransformRefBuffer); } - if (processors()->calibObjects.fastTransformHelper) { + if (processors()->calibObjects.fastTransformHelper && (ptrMask == nullptr || ptrMask->fastTransformHelper)) { memcpy((void*)mFlatObjectsShadow.mCalibObjects.fastTransformHelper, (const void*)processors()->calibObjects.fastTransformHelper, sizeof(*processors()->calibObjects.fastTransformHelper)); mFlatObjectsShadow.mCalibObjects.fastTransformHelper->setCorrMap(mFlatObjectsShadow.mCalibObjects.fastTransform); mFlatObjectsShadow.mCalibObjects.fastTransformHelper->setCorrMapRef(mFlatObjectsShadow.mCalibObjects.fastTransformRef); } #ifdef GPUCA_HAVE_O2HEADERS - if (processors()->calibObjects.dEdxCalibContainer) { + if (processors()->calibObjects.dEdxCalibContainer && (ptrMask == nullptr || ptrMask->dEdxCalibContainer)) { memcpy((void*)mFlatObjectsShadow.mCalibObjects.dEdxCalibContainer, (const void*)processors()->calibObjects.dEdxCalibContainer, sizeof(*processors()->calibObjects.dEdxCalibContainer)); memcpy((void*)mFlatObjectsShadow.mdEdxSplinesBuffer, (const void*)processors()->calibObjects.dEdxCalibContainer->getFlatBufferPtr(), processors()->calibObjects.dEdxCalibContainer->getFlatBufferSize()); mFlatObjectsShadow.mCalibObjects.dEdxCalibContainer->clearInternalBufferPtr(); mFlatObjectsShadow.mCalibObjects.dEdxCalibContainer->setActualBufferAddress(mFlatObjectsShadow.mdEdxSplinesBuffer); mFlatObjectsShadow.mCalibObjects.dEdxCalibContainer->setFutureBufferAddress(mFlatObjectsDevice.mdEdxSplinesBuffer); } - if (processors()->calibObjects.matLUT) { + if (processors()->calibObjects.matLUT && (ptrMask == nullptr || ptrMask->matLUT)) { memcpy((void*)mFlatObjectsShadow.mCalibObjects.matLUT, (const void*)processors()->calibObjects.matLUT, sizeof(*processors()->calibObjects.matLUT)); memcpy((void*)mFlatObjectsShadow.mMatLUTBuffer, (const void*)processors()->calibObjects.matLUT->getFlatBufferPtr(), processors()->calibObjects.matLUT->getFlatBufferSize()); mFlatObjectsShadow.mCalibObjects.matLUT->clearInternalBufferPtr(); mFlatObjectsShadow.mCalibObjects.matLUT->setActualBufferAddress(mFlatObjectsShadow.mMatLUTBuffer); mFlatObjectsShadow.mCalibObjects.matLUT->setFutureBufferAddress(mFlatObjectsDevice.mMatLUTBuffer); } - if (processors()->calibObjects.trdGeometry) { + if (processors()->calibObjects.trdGeometry && (ptrMask == nullptr || ptrMask->trdGeometry)) { memcpy((void*)mFlatObjectsShadow.mCalibObjects.trdGeometry, (const void*)processors()->calibObjects.trdGeometry, sizeof(*processors()->calibObjects.trdGeometry)); mFlatObjectsShadow.mCalibObjects.trdGeometry->clearInternalBufferPtr(); } - if (processors()->calibObjects.tpcPadGain) { + if (processors()->calibObjects.tpcPadGain && (ptrMask == nullptr || ptrMask->tpcPadGain)) { memcpy((void*)mFlatObjectsShadow.mCalibObjects.tpcPadGain, (const void*)processors()->calibObjects.tpcPadGain, sizeof(*processors()->calibObjects.tpcPadGain)); } - if (processors()->calibObjects.tpcZSLinkMapping) { + if (processors()->calibObjects.tpcZSLinkMapping && (ptrMask == nullptr || ptrMask->tpcZSLinkMapping)) { memcpy((void*)mFlatObjectsShadow.mCalibObjects.tpcZSLinkMapping, (const void*)processors()->calibObjects.tpcZSLinkMapping, sizeof(*processors()->calibObjects.tpcZSLinkMapping)); } - if (processors()->calibObjects.o2Propagator) { + if (processors()->calibObjects.o2Propagator && (ptrMask == nullptr || ptrMask->o2Propagator)) { memcpy((void*)mFlatObjectsShadow.mCalibObjects.o2Propagator, (const void*)processors()->calibObjects.o2Propagator, sizeof(*processors()->calibObjects.o2Propagator)); mFlatObjectsShadow.mCalibObjects.o2Propagator->setGPUField(&processorsDevice()->param.polynomialField); mFlatObjectsShadow.mCalibObjects.o2Propagator->setBz(param().polynomialField.GetNominalBz()); @@ -618,8 +618,15 @@ void GPUChainTracking::DoQueuedCalibUpdates(int stream) } } if (mRec->IsGPU()) { + std::array oldFlatPtrs, oldFlatPtrsDevice; + memcpy(oldFlatPtrs.data(), (void*)&mFlatObjectsShadow, oldFlatPtrs.size()); + memcpy(oldFlatPtrsDevice.data(), (void*)&mFlatObjectsDevice, oldFlatPtrsDevice.size()); mRec->ResetRegisteredMemoryPointers(mFlatObjectsShadow.mMemoryResFlat); - UpdateGPUCalibObjects(stream); + bool ptrsChanged = memcmp(oldFlatPtrs.data(), (void*)&mFlatObjectsShadow, oldFlatPtrs.size()) || memcmp(oldFlatPtrsDevice.data(), (void*)&mFlatObjectsDevice, oldFlatPtrsDevice.size()); + if (ptrsChanged) { + GPUInfo("Updating all calib objects since pointers changed"); + } + UpdateGPUCalibObjects(stream, ptrsChanged ? nullptr : &mNewCalibObjects); } if (mNewCalibValues->newSolenoidField || mNewCalibValues->newContinuousMaxTimeBin) { GPUSettingsGRP grp = mRec->GetGRPSettings(); diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index 3bf3fbaa2f371..cf8c9f04c1bb1 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -207,7 +207,7 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega short mMemoryResFlat = -1; void* SetPointersFlatObjects(void* mem); }; - void UpdateGPUCalibObjects(int stream); + void UpdateGPUCalibObjects(int stream, const GPUCalibObjectsConst* ptrMask = nullptr); void UpdateGPUCalibObjectsPtrs(int stream); struct eventStruct // Must consist only of void* ptr that will hold the GPU event ptrs! From 664a1874836c893998a3f943e6ab91f355adcaad Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 18 Sep 2023 23:03:20 +0200 Subject: [PATCH 065/324] GPU: Cleanup: Move ITS and TPC specific code out of GPUWorkFlowSpec.cxx to separate files --- GPU/Workflow/CMakeLists.txt | 2 + GPU/Workflow/src/GPUWorkflowITS.cxx | 403 +++++++++++++++++++ GPU/Workflow/src/GPUWorkflowSpec.cxx | 580 +-------------------------- GPU/Workflow/src/GPUWorkflowTPC.cxx | 377 +++++++++++++++++ 4 files changed, 783 insertions(+), 579 deletions(-) create mode 100644 GPU/Workflow/src/GPUWorkflowITS.cxx create mode 100644 GPU/Workflow/src/GPUWorkflowTPC.cxx diff --git a/GPU/Workflow/CMakeLists.txt b/GPU/Workflow/CMakeLists.txt index a0cff072ce5a4..e27b6a52deb93 100644 --- a/GPU/Workflow/CMakeLists.txt +++ b/GPU/Workflow/CMakeLists.txt @@ -11,6 +11,8 @@ o2_add_library(GPUWorkflow SOURCES src/GPUWorkflowSpec.cxx + src/GPUWorkflowTPC.cxx + src/GPUWorkflowITS.cxx TARGETVARNAME targetName PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsTPC diff --git a/GPU/Workflow/src/GPUWorkflowITS.cxx b/GPU/Workflow/src/GPUWorkflowITS.cxx new file mode 100644 index 0000000000000..99ebb67ee0b2d --- /dev/null +++ b/GPU/Workflow/src/GPUWorkflowITS.cxx @@ -0,0 +1,403 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GPUWorkflowITS.cxx +/// @author David Rohr + +#include "GPUWorkflow/GPUWorkflowSpec.h" +#include "Headers/DataHeader.h" +#include "Framework/WorkflowSpec.h" // o2::framework::mergeInputs +#include "Framework/DataRefUtils.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/SerializationMethods.h" +#include "Framework/Logger.h" +#include "Framework/CallbackService.h" +#include "Framework/CCDBParamSpec.h" +#include "DataFormatsTPC/TPCSectorHeader.h" +#include "DataFormatsTPC/ClusterNative.h" +#include "DataFormatsTPC/CompressedClusters.h" +#include "DataFormatsTPC/Helpers.h" +#include "DataFormatsTPC/ZeroSuppression.h" +#include "DataFormatsTPC/RawDataTypes.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include "DataFormatsGlobalTracking/TrackTuneParams.h" +#include "TPCReconstruction/TPCTrackingDigitsPreCheck.h" +#include "TPCReconstruction/TPCFastTransformHelperO2.h" +#include "DataFormatsTPC/Digit.h" +#include "TPCFastTransform.h" +#include "DPLUtils/DPLRawParser.h" +#include "DPLUtils/DPLRawPageSequencer.h" +#include "DetectorsBase/MatLayerCylSet.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "CommonUtils/NameConf.h" +#include "TPCBase/RDHUtils.h" +#include "GPUO2InterfaceConfiguration.h" +#include "GPUO2InterfaceQA.h" +#include "GPUO2Interface.h" +#include "CalibdEdxContainer.h" +#include "GPUNewCalibValues.h" +#include "TPCPadGainCalib.h" +#include "TPCZSLinkMapping.h" +#include "display/GPUDisplayInterface.h" +#include "TPCBase/Sector.h" +#include "TPCBase/Utils.h" +#include "TPCBase/CDBInterface.h" +#include "TPCCalibration/VDriftHelper.h" +#include "CorrectionMapsHelper.h" +#include "TPCCalibration/CorrectionMapsLoader.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "Algorithm/Parser.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsTRD/RecoInputContainer.h" +#include "TRDBase/Geometry.h" +#include "TRDBase/GeometryFlat.h" +#include "ITSBase/GeometryTGeo.h" +#include "CommonUtils/VerbosityConfig.h" +#include "CommonUtils/DebugStreamer.h" +#include +#include // for make_shared +#include +#include +#include +#include +#include +#include +#include +#include +#include "GPUReconstructionConvert.h" +#include "DetectorsRaw/RDHUtils.h" +#include +#include +#include +#include +#include +#include + +#include "ITStracking/TimeFrame.h" +#include "ITStracking/Tracker.h" +#include "ITStracking/TrackerTraits.h" +#include "ITStracking/Vertexer.h" +#include "ITStracking/VertexerTraits.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITSMFT/PhysTrigger.h" +#include "CommonDataFormat/IRFrame.h" +#include "ITSReconstruction/FastMultEst.h" +#include "ITSReconstruction/FastMultEstConfig.h" + +using namespace o2::framework; +using namespace o2::header; +using namespace o2::gpu; +using namespace o2::base; +using namespace o2::dataformats; + +namespace o2::gpu +{ + +int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) +{ + using Vertex = o2::dataformats::Vertex>; + + auto compClusters = pc.inputs().get>("compClusters"); + gsl::span patterns = pc.inputs().get>("patterns"); + gsl::span physTriggers; + std::vector fromTRD; + if (mSpecConfig.itsTriggerType == 2) { // use TRD triggers + o2::InteractionRecord ir{0, pc.services().get().firstTForbit}; + auto trdTriggers = pc.inputs().get>("phystrig"); + for (const auto& trig : trdTriggers) { + if (trig.getBCData() >= ir && trig.getNumberOfTracklets()) { + ir = trig.getBCData(); + fromTRD.emplace_back(o2::itsmft::PhysTrigger{ir, 0}); + } + } + physTriggers = gsl::span(fromTRD.data(), fromTRD.size()); + } else if (mSpecConfig.itsTriggerType == 1) { // use Phys triggers from ITS stream + physTriggers = pc.inputs().get>("phystrig"); + } + + // code further down does assignment to the rofs and the altered object is used for output + // we therefore need a copy of the vector rather than an object created directly on the input data, + // the output vector however is created directly inside the message memory thus avoiding copy by + // snapshot + auto rofsinput = pc.inputs().get>("ROframes"); + auto& rofs = pc.outputs().make>(Output{"ITS", "ITSTrackROF", 0, Lifetime::Timeframe}, rofsinput.begin(), rofsinput.end()); + + auto& irFrames = pc.outputs().make>(Output{"ITS", "IRFRAMES", 0, Lifetime::Timeframe}); + + const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); // RS: this should come from CCDB + int nBCPerTF = alpParams.roFrameLengthInBC; + + LOG(info) << "ITSTracker pulled " << compClusters.size() << " clusters, " << rofs.size() << " RO frames"; + + const dataformats::MCTruthContainer* labels = nullptr; + gsl::span mc2rofs; + if (mSpecConfig.processMC) { + labels = pc.inputs().get*>("itsmclabels").release(); + // get the array as read-only span, a snapshot is send forward + mc2rofs = pc.inputs().get>("ITSMC2ROframes"); + LOG(info) << labels->getIndexedSize() << " MC label objects , in " << mc2rofs.size() << " MC events"; + } + + std::vector tracks; + auto& allClusIdx = pc.outputs().make>(Output{"ITS", "TRACKCLSID", 0, Lifetime::Timeframe}); + std::vector trackLabels; + std::vector verticesLabels; + auto& allTracks = pc.outputs().make>(Output{"ITS", "TRACKS", 0, Lifetime::Timeframe}); + std::vector allTrackLabels; + std::vector allVerticesLabels; + + auto& vertROFvec = pc.outputs().make>(Output{"ITS", "VERTICESROF", 0, Lifetime::Timeframe}); + auto& vertices = pc.outputs().make>(Output{"ITS", "VERTICES", 0, Lifetime::Timeframe}); + + std::uint32_t roFrame = 0; + + bool continuous = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS); + LOG(info) << "ITSTracker RO: continuous=" << continuous; + + if (mSpecConfig.itsOverrBeamEst) { + mITSTimeFrame->setBeamPosition(mMeanVertex->getX(), + mMeanVertex->getY(), + mMeanVertex->getSigmaY2(), + mITSTracker->getParameters()[0].LayerResolution[0], + mITSTracker->getParameters()[0].SystErrorY2[0]); + } + + mITSTracker->setBz(o2::base::Propagator::Instance()->getNominalBz()); + + gsl::span::iterator pattIt = patterns.begin(); + + gsl::span rofspan(rofs); + mITSTimeFrame->loadROFrameData(rofspan, compClusters, pattIt, mITSDict, labels); + pattIt = patterns.begin(); + std::vector savedROF; + auto logger = [&](std::string s) { LOG(info) << s; }; + auto errorLogger = [&](std::string s) { LOG(error) << s; }; + + o2::its::FastMultEst multEst; // mult estimator + std::vector processingMask; + int cutVertexMult{0}, cutRandomMult = int(rofs.size()) - multEst.selectROFs(rofs, compClusters, physTriggers, processingMask); + mITSTimeFrame->setMultiplicityCutMask(processingMask); + float vertexerElapsedTime{0.f}; + if (mITSRunVertexer) { + // Run seeding vertexer + vertexerElapsedTime = mITSVertexer->clustersToVertices(logger); + } else { // cosmics + mITSTimeFrame->resetRofPV(); + } + const auto& multEstConf = o2::its::FastMultEstConfig::Instance(); // parameters for mult estimation and cuts + for (auto iRof{0}; iRof < rofspan.size(); ++iRof) { + std::vector vtxVecLoc; + auto& vtxROF = vertROFvec.emplace_back(rofspan[iRof]); + vtxROF.setFirstEntry(vertices.size()); + if (mITSRunVertexer) { + auto vtxSpan = mITSTimeFrame->getPrimaryVertices(iRof); + vtxROF.setNEntries(vtxSpan.size()); + bool selROF = vtxSpan.size() == 0; + for (auto iV{0}; iV < vtxSpan.size(); ++iV) { + auto& v = vtxSpan[iV]; + if (multEstConf.isVtxMultCutRequested() && !multEstConf.isPassingVtxMultCut(v.getNContributors())) { + continue; // skip vertex of unwanted multiplicity + } + selROF = true; + vertices.push_back(v); + if (mSpecConfig.processMC) { + auto vLabels = mITSTimeFrame->getPrimaryVerticesLabels(iRof)[iV]; + std::copy(vLabels.begin(), vLabels.end(), std::back_inserter(allVerticesLabels)); + } + } + if (processingMask[iRof] && !selROF) { // passed selection in clusters and not in vertex multiplicity + LOG(debug) << fmt::format("ROF {} rejected by the vertex multiplicity selection [{},{}]", + iRof, + multEstConf.cutMultVtxLow, + multEstConf.cutMultVtxHigh); + processingMask[iRof] = selROF; + cutVertexMult++; + } + } else { // cosmics + vtxVecLoc.emplace_back(Vertex()); + vtxVecLoc.back().setNContributors(1); + vtxROF.setNEntries(vtxVecLoc.size()); + for (auto& v : vtxVecLoc) { + vertices.push_back(v); + } + mITSTimeFrame->addPrimaryVertices(vtxVecLoc); + } + } + LOG(info) << fmt::format(" - rejected {}/{} ROFs: random/mult.sel:{} (seed {}), vtx.sel:{}", cutRandomMult + cutVertexMult, rofspan.size(), cutRandomMult, multEst.lastRandomSeed, cutVertexMult); + LOG(info) << fmt::format(" - Vertex seeding total elapsed time: {} ms for {} vertices found in {} ROFs", vertexerElapsedTime, mITSTimeFrame->getPrimaryVerticesNum(), rofspan.size()); + + if (mSpecConfig.itsOverrBeamEst) { + LOG(info) << fmt::format(" - Beam position set to: {}, {} from meanvertex object", mITSTimeFrame->getBeamX(), mITSTimeFrame->getBeamY()); + } else { + LOG(info) << fmt::format(" - Beam position computed for the TF: {}, {}", mITSTimeFrame->getBeamX(), mITSTimeFrame->getBeamY()); + } + if (mITSCosmicsProcessing && compClusters.size() > 1500 * rofspan.size()) { + LOG(error) << "Cosmics processing was requested with an average detector occupancy exceeding 1.e-7, skipping TF processing."; + } else { + + mITSTimeFrame->setMultiplicityCutMask(processingMask); + // Run CA tracker + mITSTracker->clustersToTracks(logger, errorLogger); + if (mITSTimeFrame->hasBogusClusters()) { + LOG(warning) << fmt::format(" - The processed timeframe had {} clusters with wild z coordinates, check the dictionaries", mITSTimeFrame->hasBogusClusters()); + } + + for (unsigned int iROF{0}; iROF < rofs.size(); ++iROF) { + auto& rof{rofs[iROF]}; + tracks = mITSTimeFrame->getTracks(iROF); + trackLabels = mITSTimeFrame->getTracksLabel(iROF); + auto number{tracks.size()}; + auto first{allTracks.size()}; + int offset = -rof.getFirstEntry(); // cluster entry!!! + rof.setFirstEntry(first); + rof.setNEntries(number); + + if (processingMask[iROF]) { + irFrames.emplace_back(rof.getBCData(), rof.getBCData() + nBCPerTF - 1).info = tracks.size(); + } + + std::copy(trackLabels.begin(), trackLabels.end(), std::back_inserter(allTrackLabels)); + // Some conversions that needs to be moved in the tracker internals + for (unsigned int iTrk{0}; iTrk < tracks.size(); ++iTrk) { + auto& trc{tracks[iTrk]}; + trc.setFirstClusterEntry(allClusIdx.size()); // before adding tracks, create final cluster indices + int ncl = trc.getNumberOfClusters(), nclf = 0; + for (int ic = o2::its::TrackITSExt::MaxClusters; ic--;) { // track internally keeps in->out cluster indices, but we want to store the references as out->in!!! + auto clid = trc.getClusterIndex(ic); + if (clid >= 0) { + allClusIdx.push_back(clid); + nclf++; + } + } + assert(ncl == nclf); + allTracks.emplace_back(trc); + } + } + LOGP(info, "ITSTracker pushed {} tracks and {} vertices", allTracks.size(), vertices.size()); + if (mSpecConfig.processMC) { + LOGP(info, "ITSTracker pushed {} track labels", allTrackLabels.size()); + LOGP(info, "ITSTracker pushed {} vertex labels", allVerticesLabels.size()); + + pc.outputs().snapshot(Output{"ITS", "TRACKSMCTR", 0, Lifetime::Timeframe}, allTrackLabels); + pc.outputs().snapshot(Output{"ITS", "VERTICESMCTR", 0, Lifetime::Timeframe}, allVerticesLabels); + pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0, Lifetime::Timeframe}, mc2rofs); + } + } + return 0; +} + +void GPURecoWorkflowSpec::initFunctionITS(InitContext& ic) +{ + std::transform(mITSMode.begin(), mITSMode.end(), mITSMode.begin(), [](unsigned char c) { return std::tolower(c); }); + o2::its::VertexerTraits* vtxTraits = nullptr; + o2::its::TrackerTraits* trkTraits = nullptr; + mTracker->GetITSTraits(trkTraits, vtxTraits, mITSTimeFrame); + mITSVertexer = std::make_unique(vtxTraits); + mITSTracker = std::make_unique(trkTraits); + mITSVertexer->adoptTimeFrame(*mITSTimeFrame); + mITSTracker->adoptTimeFrame(*mITSTimeFrame); + mITSRunVertexer = true; + mITSCosmicsProcessing = false; + std::vector trackParams; + + if (mITSMode == "async") { + trackParams.resize(3); + for (auto& param : trackParams) { + param.ZBins = 64; + param.PhiBins = 32; + } + trackParams[1].TrackletMinPt = 0.2f; + trackParams[1].CellDeltaTanLambdaSigma *= 2.; + trackParams[2].TrackletMinPt = 0.1f; + trackParams[2].CellDeltaTanLambdaSigma *= 4.; + trackParams[2].MinTrackLength = 4; + LOG(info) << "Initializing tracker in async. phase reconstruction with " << trackParams.size() << " passes"; + } else if (mITSMode == "sync") { + trackParams.resize(1); + trackParams[0].ZBins = 64; + trackParams[0].PhiBins = 32; + trackParams[0].MinTrackLength = 4; + LOG(info) << "Initializing tracker in sync. phase reconstruction with " << trackParams.size() << " passes"; + } else if (mITSMode == "cosmics") { + mITSCosmicsProcessing = true; + mITSRunVertexer = false; + trackParams.resize(1); + trackParams[0].MinTrackLength = 4; + trackParams[0].CellDeltaTanLambdaSigma *= 10; + trackParams[0].PhiBins = 4; + trackParams[0].ZBins = 16; + trackParams[0].PVres = 1.e5f; + trackParams[0].MaxChi2ClusterAttachment = 60.; + trackParams[0].MaxChi2NDF = 40.; + trackParams[0].TrackletsPerClusterLimit = 100.; + trackParams[0].CellsPerClusterLimit = 100.; + LOG(info) << "Initializing tracker in reconstruction for cosmics with " << trackParams.size() << " passes"; + } else { + throw std::runtime_error(fmt::format("Unsupported ITS tracking mode {:s} ", mITSMode)); + } + + for (auto& params : trackParams) { + params.CorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrLUT; + } + mITSTracker->setParameters(trackParams); +} + +void GPURecoWorkflowSpec::finaliseCCDBITS(ConcreteDataMatcher& matcher, void* obj) +{ + if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { + LOG(info) << "cluster dictionary updated"; + mITSDict = (const o2::itsmft::TopologyDictionary*)obj; + return; + } + // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level + if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) { + LOG(info) << "Alpide param updated"; + const auto& par = o2::itsmft::DPLAlpideParam::Instance(); + par.printKeyValues(); + return; + } + if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) { + LOGP(info, "mean vertex acquired"); + if (obj) { + mMeanVertex = (const o2::dataformats::MeanVertexObject*)obj; + } + return; + } +} + +bool GPURecoWorkflowSpec::fetchCalibsCCDBITS(ProcessingContext& pc) +{ + static bool initOnceDone = false; + if (!initOnceDone) { // this params need to be queried only once + initOnceDone = true; + pc.inputs().get("itscldict"); // just to trigger the finaliseCCDB + pc.inputs().get*>("itsalppar"); + mITSVertexer->getGlobalConfiguration(); + mITSTracker->getGlobalConfiguration(); + if (mSpecConfig.itsOverrBeamEst) { + pc.inputs().get("meanvtx"); + } + } + return false; +} + +} // namespace o2::gpu diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 12faeb00a65e5..c9a4975969305 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -10,7 +10,7 @@ // or submit itself to any jurisdiction. /// @file GPUWorkflowSpec.cxx -/// @author Matthias Richter +/// @author Matthias Richter, David Rohr /// @since 2018-04-18 /// @brief Processor spec for running TPC CA tracking @@ -90,21 +90,8 @@ #include #include #include - -// Includes needed for ITS tracking - // TODO: Move ITS tracking control code to an extra class, and move these includes there -#include "ITStracking/TimeFrame.h" #include "ITStracking/Tracker.h" -#include "ITStracking/TrackerTraits.h" #include "ITStracking/Vertexer.h" -#include "ITStracking/VertexerTraits.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "ITSMFTBase/DPLAlpideParam.h" -#include "DataFormatsCalibration/MeanVertexObject.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "DataFormatsITSMFT/PhysTrigger.h" -#include "CommonDataFormat/IRFrame.h" -#include "ITSReconstruction/FastMultEst.h" -#include "ITSReconstruction/FastMultEstConfig.h" using namespace o2::framework; using namespace o2::header; @@ -382,7 +369,6 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) bool getWorkflowTPCInput_clusters = false, getWorkflowTPCInput_mc = false, getWorkflowTPCInput_digits = false; bool debugTFDump = false; - // unsigned int totalZSPages = 0; if (mSpecConfig.processMC) { getWorkflowTPCInput_mc = true; } @@ -914,199 +900,6 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) LOG(info) << "GPU Reoncstruction time for this TF " << mTimer->CpuTime() - cput << " s (cpu), " << mTimer->RealTime() - realt << " s (wall)"; } -int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) -{ - using Vertex = o2::dataformats::Vertex>; - - auto compClusters = pc.inputs().get>("compClusters"); - gsl::span patterns = pc.inputs().get>("patterns"); - gsl::span physTriggers; - std::vector fromTRD; - if (mSpecConfig.itsTriggerType == 2) { // use TRD triggers - o2::InteractionRecord ir{0, pc.services().get().firstTForbit}; - auto trdTriggers = pc.inputs().get>("phystrig"); - for (const auto& trig : trdTriggers) { - if (trig.getBCData() >= ir && trig.getNumberOfTracklets()) { - ir = trig.getBCData(); - fromTRD.emplace_back(o2::itsmft::PhysTrigger{ir, 0}); - } - } - physTriggers = gsl::span(fromTRD.data(), fromTRD.size()); - } else if (mSpecConfig.itsTriggerType == 1) { // use Phys triggers from ITS stream - physTriggers = pc.inputs().get>("phystrig"); - } - - // code further down does assignment to the rofs and the altered object is used for output - // we therefore need a copy of the vector rather than an object created directly on the input data, - // the output vector however is created directly inside the message memory thus avoiding copy by - // snapshot - auto rofsinput = pc.inputs().get>("ROframes"); - auto& rofs = pc.outputs().make>(Output{"ITS", "ITSTrackROF", 0, Lifetime::Timeframe}, rofsinput.begin(), rofsinput.end()); - - auto& irFrames = pc.outputs().make>(Output{"ITS", "IRFRAMES", 0, Lifetime::Timeframe}); - - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); // RS: this should come from CCDB - int nBCPerTF = alpParams.roFrameLengthInBC; - - LOG(info) << "ITSTracker pulled " << compClusters.size() << " clusters, " << rofs.size() << " RO frames"; - - const dataformats::MCTruthContainer* labels = nullptr; - gsl::span mc2rofs; - if (mSpecConfig.processMC) { - labels = pc.inputs().get*>("itsmclabels").release(); - // get the array as read-only span, a snapshot is send forward - mc2rofs = pc.inputs().get>("ITSMC2ROframes"); - LOG(info) << labels->getIndexedSize() << " MC label objects , in " << mc2rofs.size() << " MC events"; - } - - std::vector tracks; - auto& allClusIdx = pc.outputs().make>(Output{"ITS", "TRACKCLSID", 0, Lifetime::Timeframe}); - std::vector trackLabels; - std::vector verticesLabels; - auto& allTracks = pc.outputs().make>(Output{"ITS", "TRACKS", 0, Lifetime::Timeframe}); - std::vector allTrackLabels; - std::vector allVerticesLabels; - - auto& vertROFvec = pc.outputs().make>(Output{"ITS", "VERTICESROF", 0, Lifetime::Timeframe}); - auto& vertices = pc.outputs().make>(Output{"ITS", "VERTICES", 0, Lifetime::Timeframe}); - - std::uint32_t roFrame = 0; - - bool continuous = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS); - LOG(info) << "ITSTracker RO: continuous=" << continuous; - - if (mSpecConfig.itsOverrBeamEst) { - mITSTimeFrame->setBeamPosition(mMeanVertex->getX(), - mMeanVertex->getY(), - mMeanVertex->getSigmaY2(), - mITSTracker->getParameters()[0].LayerResolution[0], - mITSTracker->getParameters()[0].SystErrorY2[0]); - } - - mITSTracker->setBz(o2::base::Propagator::Instance()->getNominalBz()); - - gsl::span::iterator pattIt = patterns.begin(); - - gsl::span rofspan(rofs); - mITSTimeFrame->loadROFrameData(rofspan, compClusters, pattIt, mITSDict, labels); - pattIt = patterns.begin(); - std::vector savedROF; - auto logger = [&](std::string s) { LOG(info) << s; }; - auto errorLogger = [&](std::string s) { LOG(error) << s; }; - - o2::its::FastMultEst multEst; // mult estimator - std::vector processingMask; - int cutVertexMult{0}, cutRandomMult = int(rofs.size()) - multEst.selectROFs(rofs, compClusters, physTriggers, processingMask); - mITSTimeFrame->setMultiplicityCutMask(processingMask); - float vertexerElapsedTime{0.f}; - if (mITSRunVertexer) { - // Run seeding vertexer - vertexerElapsedTime = mITSVertexer->clustersToVertices(logger); - } else { // cosmics - mITSTimeFrame->resetRofPV(); - } - const auto& multEstConf = o2::its::FastMultEstConfig::Instance(); // parameters for mult estimation and cuts - for (auto iRof{0}; iRof < rofspan.size(); ++iRof) { - std::vector vtxVecLoc; - auto& vtxROF = vertROFvec.emplace_back(rofspan[iRof]); - vtxROF.setFirstEntry(vertices.size()); - if (mITSRunVertexer) { - auto vtxSpan = mITSTimeFrame->getPrimaryVertices(iRof); - vtxROF.setNEntries(vtxSpan.size()); - bool selROF = vtxSpan.size() == 0; - for (auto iV{0}; iV < vtxSpan.size(); ++iV) { - auto& v = vtxSpan[iV]; - if (multEstConf.isVtxMultCutRequested() && !multEstConf.isPassingVtxMultCut(v.getNContributors())) { - continue; // skip vertex of unwanted multiplicity - } - selROF = true; - vertices.push_back(v); - if (mSpecConfig.processMC) { - auto vLabels = mITSTimeFrame->getPrimaryVerticesLabels(iRof)[iV]; - std::copy(vLabels.begin(), vLabels.end(), std::back_inserter(allVerticesLabels)); - } - } - if (processingMask[iRof] && !selROF) { // passed selection in clusters and not in vertex multiplicity - LOG(debug) << fmt::format("ROF {} rejected by the vertex multiplicity selection [{},{}]", - iRof, - multEstConf.cutMultVtxLow, - multEstConf.cutMultVtxHigh); - processingMask[iRof] = selROF; - cutVertexMult++; - } - } else { // cosmics - vtxVecLoc.emplace_back(Vertex()); - vtxVecLoc.back().setNContributors(1); - vtxROF.setNEntries(vtxVecLoc.size()); - for (auto& v : vtxVecLoc) { - vertices.push_back(v); - } - mITSTimeFrame->addPrimaryVertices(vtxVecLoc); - } - } - LOG(info) << fmt::format(" - rejected {}/{} ROFs: random/mult.sel:{} (seed {}), vtx.sel:{}", cutRandomMult + cutVertexMult, rofspan.size(), cutRandomMult, multEst.lastRandomSeed, cutVertexMult); - LOG(info) << fmt::format(" - Vertex seeding total elapsed time: {} ms for {} vertices found in {} ROFs", vertexerElapsedTime, mITSTimeFrame->getPrimaryVerticesNum(), rofspan.size()); - - if (mSpecConfig.itsOverrBeamEst) { - LOG(info) << fmt::format(" - Beam position set to: {}, {} from meanvertex object", mITSTimeFrame->getBeamX(), mITSTimeFrame->getBeamY()); - } else { - LOG(info) << fmt::format(" - Beam position computed for the TF: {}, {}", mITSTimeFrame->getBeamX(), mITSTimeFrame->getBeamY()); - } - if (mITSCosmicsProcessing && compClusters.size() > 1500 * rofspan.size()) { - LOG(error) << "Cosmics processing was requested with an average detector occupancy exceeding 1.e-7, skipping TF processing."; - } else { - - mITSTimeFrame->setMultiplicityCutMask(processingMask); - // Run CA tracker - mITSTracker->clustersToTracks(logger, errorLogger); - if (mITSTimeFrame->hasBogusClusters()) { - LOG(warning) << fmt::format(" - The processed timeframe had {} clusters with wild z coordinates, check the dictionaries", mITSTimeFrame->hasBogusClusters()); - } - - for (unsigned int iROF{0}; iROF < rofs.size(); ++iROF) { - auto& rof{rofs[iROF]}; - tracks = mITSTimeFrame->getTracks(iROF); - trackLabels = mITSTimeFrame->getTracksLabel(iROF); - auto number{tracks.size()}; - auto first{allTracks.size()}; - int offset = -rof.getFirstEntry(); // cluster entry!!! - rof.setFirstEntry(first); - rof.setNEntries(number); - - if (processingMask[iROF]) { - irFrames.emplace_back(rof.getBCData(), rof.getBCData() + nBCPerTF - 1).info = tracks.size(); - } - - std::copy(trackLabels.begin(), trackLabels.end(), std::back_inserter(allTrackLabels)); - // Some conversions that needs to be moved in the tracker internals - for (unsigned int iTrk{0}; iTrk < tracks.size(); ++iTrk) { - auto& trc{tracks[iTrk]}; - trc.setFirstClusterEntry(allClusIdx.size()); // before adding tracks, create final cluster indices - int ncl = trc.getNumberOfClusters(), nclf = 0; - for (int ic = o2::its::TrackITSExt::MaxClusters; ic--;) { // track internally keeps in->out cluster indices, but we want to store the references as out->in!!! - auto clid = trc.getClusterIndex(ic); - if (clid >= 0) { - allClusIdx.push_back(clid); - nclf++; - } - } - assert(ncl == nclf); - allTracks.emplace_back(trc); - } - } - LOGP(info, "ITSTracker pushed {} tracks and {} vertices", allTracks.size(), vertices.size()); - if (mSpecConfig.processMC) { - LOGP(info, "ITSTracker pushed {} track labels", allTrackLabels.size()); - LOGP(info, "ITSTracker pushed {} vertex labels", allVerticesLabels.size()); - - pc.outputs().snapshot(Output{"ITS", "TRACKSMCTR", 0, Lifetime::Timeframe}, allTrackLabels); - pc.outputs().snapshot(Output{"ITS", "VERTICESMCTR", 0, Lifetime::Timeframe}, allVerticesLabels); - pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0, Lifetime::Timeframe}, mc2rofs); - } - } - return 0; -} - void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc) { GPUCalibObjectsConst newCalibObjects; @@ -1334,377 +1127,6 @@ Outputs GPURecoWorkflowSpec::outputs() return outputSpecs; }; -void GPURecoWorkflowSpec::initFunctionITS(InitContext& ic) -{ - std::transform(mITSMode.begin(), mITSMode.end(), mITSMode.begin(), [](unsigned char c) { return std::tolower(c); }); - o2::its::VertexerTraits* vtxTraits = nullptr; - o2::its::TrackerTraits* trkTraits = nullptr; - mTracker->GetITSTraits(trkTraits, vtxTraits, mITSTimeFrame); - mITSVertexer = std::make_unique(vtxTraits); - mITSTracker = std::make_unique(trkTraits); - mITSVertexer->adoptTimeFrame(*mITSTimeFrame); - mITSTracker->adoptTimeFrame(*mITSTimeFrame); - mITSRunVertexer = true; - mITSCosmicsProcessing = false; - std::vector trackParams; - - if (mITSMode == "async") { - trackParams.resize(3); - for (auto& param : trackParams) { - param.ZBins = 64; - param.PhiBins = 32; - } - trackParams[1].TrackletMinPt = 0.2f; - trackParams[1].CellDeltaTanLambdaSigma *= 2.; - trackParams[2].TrackletMinPt = 0.1f; - trackParams[2].CellDeltaTanLambdaSigma *= 4.; - trackParams[2].MinTrackLength = 4; - LOG(info) << "Initializing tracker in async. phase reconstruction with " << trackParams.size() << " passes"; - } else if (mITSMode == "sync") { - trackParams.resize(1); - trackParams[0].ZBins = 64; - trackParams[0].PhiBins = 32; - trackParams[0].MinTrackLength = 4; - LOG(info) << "Initializing tracker in sync. phase reconstruction with " << trackParams.size() << " passes"; - } else if (mITSMode == "cosmics") { - mITSCosmicsProcessing = true; - mITSRunVertexer = false; - trackParams.resize(1); - trackParams[0].MinTrackLength = 4; - trackParams[0].CellDeltaTanLambdaSigma *= 10; - trackParams[0].PhiBins = 4; - trackParams[0].ZBins = 16; - trackParams[0].PVres = 1.e5f; - trackParams[0].MaxChi2ClusterAttachment = 60.; - trackParams[0].MaxChi2NDF = 40.; - trackParams[0].TrackletsPerClusterLimit = 100.; - trackParams[0].CellsPerClusterLimit = 100.; - LOG(info) << "Initializing tracker in reconstruction for cosmics with " << trackParams.size() << " passes"; - } else { - throw std::runtime_error(fmt::format("Unsupported ITS tracking mode {:s} ", mITSMode)); - } - - for (auto& params : trackParams) { - params.CorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrLUT; - } - mITSTracker->setParameters(trackParams); -} - -void GPURecoWorkflowSpec::initFunctionTPCCalib(InitContext& ic) -{ - mdEdxCalibContainer.reset(new o2::tpc::CalibdEdxContainer()); - mTPCVDriftHelper.reset(new o2::tpc::VDriftHelper()); - mFastTransformHelper.reset(new o2::tpc::CorrectionMapsLoader()); - mFastTransform = std::move(o2::tpc::TPCFastTransformHelperO2::instance()->create(0)); - mFastTransformRef = std::move(o2::tpc::TPCFastTransformHelperO2::instance()->create(0)); - mFastTransformHelper->setCorrMap(mFastTransform.get()); // just to reserve the space - mFastTransformHelper->setCorrMapRef(mFastTransformRef.get()); - mFastTransformHelper->setLumiScaleMode(mSpecConfig.lumiScaleMode); - if (mSpecConfig.outputTracks) { - mFastTransformHelper->init(ic); - } - if (mConfParam->dEdxDisableTopologyPol) { - LOGP(info, "Disabling loading of track topology correction using polynomials from CCDB"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol); - } - - if (mConfParam->dEdxDisableThresholdMap) { - LOGP(info, "Disabling loading of threshold map from CCDB"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalThresholdMap); - } - - if (mConfParam->dEdxDisableGainMap) { - LOGP(info, "Disabling loading of gain map from CCDB"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalGainMap); - } - - if (mConfParam->dEdxDisableResidualGainMap) { - LOGP(info, "Disabling loading of residual gain map from CCDB"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalResidualGainMap); - } - - if (mConfParam->dEdxDisableResidualGain) { - LOGP(info, "Disabling loading of residual gain calibration from CCDB"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTimeGain); - } - - if (mConfParam->dEdxUseFullGainMap) { - LOGP(info, "Using the full gain map for correcting the cluster charge during calculation of the dE/dx"); - mdEdxCalibContainer->setUsageOfFullGainMap(true); - } - - if (mConfParam->gainCalibDisableCCDB) { - LOGP(info, "Disabling loading the TPC pad gain calibration from the CCDB"); - mUpdateGainMapCCDB = false; - } - - // load from file - if (!mConfParam->dEdxPolTopologyCorrFile.empty() || !mConfParam->dEdxCorrFile.empty() || !mConfParam->dEdxSplineTopologyCorrFile.empty()) { - if (!mConfParam->dEdxPolTopologyCorrFile.empty()) { - LOGP(info, "Loading dE/dx polynomial track topology correction from file: {}", mConfParam->dEdxPolTopologyCorrFile); - mdEdxCalibContainer->loadPolTopologyCorrectionFromFile(mConfParam->dEdxPolTopologyCorrFile); - - LOGP(info, "Disabling loading of track topology correction using polynomials from CCDB as it was already loaded from input file"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol); - - if (std::filesystem::exists(mConfParam->thresholdCalibFile)) { - LOG(info) << "Loading tpc zero supression map from file " << mConfParam->thresholdCalibFile; - const auto* thresholdMap = o2::tpc::utils::readCalPads(mConfParam->thresholdCalibFile, "ThresholdMap")[0]; - mdEdxCalibContainer->setZeroSupresssionThreshold(*thresholdMap); - - LOGP(info, "Disabling loading of threshold map from CCDB as it was already loaded from input file"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalThresholdMap); - } else { - if (not mConfParam->thresholdCalibFile.empty()) { - LOG(warn) << "Couldn't find tpc zero supression file " << mConfParam->thresholdCalibFile << ". Not setting any zero supression."; - } - LOG(info) << "Setting default zero supression map"; - mdEdxCalibContainer->setDefaultZeroSupresssionThreshold(); - } - } else if (!mConfParam->dEdxSplineTopologyCorrFile.empty()) { - LOGP(info, "Loading dE/dx spline track topology correction from file: {}", mConfParam->dEdxSplineTopologyCorrFile); - mdEdxCalibContainer->loadSplineTopologyCorrectionFromFile(mConfParam->dEdxSplineTopologyCorrFile); - - LOGP(info, "Disabling loading of track topology correction using polynomials from CCDB as splines were loaded from input file"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol); - } - if (!mConfParam->dEdxCorrFile.empty()) { - LOGP(info, "Loading dEdx correction from file: {}", mConfParam->dEdxCorrFile); - mdEdxCalibContainer->loadResidualCorrectionFromFile(mConfParam->dEdxCorrFile); - - LOGP(info, "Disabling loading of residual gain calibration from CCDB as it was already loaded from input file"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTimeGain); - } - } - - if (mConfParam->dEdxPolTopologyCorrFile.empty() && mConfParam->dEdxSplineTopologyCorrFile.empty()) { - // setting default topology correction to allocate enough memory - LOG(info) << "Setting default dE/dx polynomial track topology correction to allocate enough memory"; - mdEdxCalibContainer->setDefaultPolTopologyCorrection(); - } - - GPUO2InterfaceConfiguration& config = *mConfig.get(); - mConfig->configCalib.dEdxCalibContainer = mdEdxCalibContainer.get(); - - if (std::filesystem::exists(mConfParam->gainCalibFile)) { - LOG(info) << "Loading tpc gain correction from file " << mConfParam->gainCalibFile; - const auto* gainMap = o2::tpc::utils::readCalPads(mConfParam->gainCalibFile, "GainMap")[0]; - mTPCPadGainCalib = GPUO2Interface::getPadGainCalib(*gainMap); - - LOGP(info, "Disabling loading the TPC gain correction map from the CCDB as it was already loaded from input file"); - mUpdateGainMapCCDB = false; - } else { - if (not mConfParam->gainCalibFile.empty()) { - LOG(warn) << "Couldn't find tpc gain correction file " << mConfParam->gainCalibFile << ". Not applying any gain correction."; - } - mTPCPadGainCalib = GPUO2Interface::getPadGainCalibDefault(); - mTPCPadGainCalib->getGainCorrection(30, 5, 5); - } - mConfig->configCalib.tpcPadGain = mTPCPadGainCalib.get(); - - mTPCZSLinkMapping.reset(new TPCZSLinkMapping{tpc::Mapper::instance()}); - mConfig->configCalib.tpcZSLinkMapping = mTPCZSLinkMapping.get(); -} - -void GPURecoWorkflowSpec::finaliseCCDBITS(ConcreteDataMatcher& matcher, void* obj) -{ - if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { - LOG(info) << "cluster dictionary updated"; - mITSDict = (const o2::itsmft::TopologyDictionary*)obj; - return; - } - // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level - if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) { - LOG(info) << "Alpide param updated"; - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - return; - } - if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) { - LOGP(info, "mean vertex acquired"); - if (obj) { - mMeanVertex = (const o2::dataformats::MeanVertexObject*)obj; - } - return; - } -} - -void GPURecoWorkflowSpec::finaliseCCDBTPC(ConcreteDataMatcher& matcher, void* obj) -{ - const o2::tpc::CalibdEdxContainer* dEdxCalibContainer = mdEdxCalibContainer.get(); - - auto copyCalibsToBuffer = [this, dEdxCalibContainer]() { - if (!(mdEdxCalibContainerBufferNew)) { - mdEdxCalibContainerBufferNew = std::make_unique(); - mdEdxCalibContainerBufferNew->cloneFromObject(*dEdxCalibContainer, nullptr); - } - }; - - if (matcher == ConcreteDataMatcher(gDataOriginTPC, "PADGAINFULL", 0)) { - LOGP(info, "Updating gain map from CCDB"); - const auto* gainMap = static_cast*>(obj); - - if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalGainMap) && mSpecConfig.outputTracks) { - copyCalibsToBuffer(); - const float minGain = 0; - const float maxGain = 2; - mdEdxCalibContainerBufferNew.get()->setGainMap(*gainMap, minGain, maxGain); - } - - if (mUpdateGainMapCCDB && mSpecConfig.caClusterer) { - mTPCPadGainCalibBufferNew = GPUO2Interface::getPadGainCalib(*gainMap); - } - - } else if (matcher == ConcreteDataMatcher(gDataOriginTPC, "PADGAINRESIDUAL", 0)) { - LOGP(info, "Updating residual gain map from CCDB"); - copyCalibsToBuffer(); - const auto* gainMapResidual = static_cast>*>(obj); - const float minResidualGain = 0.7f; - const float maxResidualGain = 1.3f; - mdEdxCalibContainerBufferNew.get()->setGainMapResidual(gainMapResidual->at("GainMap"), minResidualGain, maxResidualGain); - } else if (matcher == ConcreteDataMatcher(gDataOriginTPC, "PADTHRESHOLD", 0)) { - LOGP(info, "Updating threshold map from CCDB"); - copyCalibsToBuffer(); - const auto* thresholdMap = static_cast>*>(obj); - mdEdxCalibContainerBufferNew.get()->setZeroSupresssionThreshold(thresholdMap->at("ThresholdMap")); - } else if (matcher == ConcreteDataMatcher(gDataOriginTPC, "TOPOLOGYGAIN", 0) && !(dEdxCalibContainer->isTopologyCorrectionSplinesSet())) { - LOGP(info, "Updating Q topology correction from CCDB"); - copyCalibsToBuffer(); - const auto* topologyCorr = static_cast(obj); - o2::tpc::CalibdEdxTrackTopologyPol calibTrackTopology; - calibTrackTopology.setFromContainer(*topologyCorr); - mdEdxCalibContainerBufferNew->setPolTopologyCorrection(calibTrackTopology); - } else if (matcher == ConcreteDataMatcher(gDataOriginTPC, "TIMEGAIN", 0)) { - LOGP(info, "Updating residual gain correction from CCDB"); - copyCalibsToBuffer(); - const auto* residualCorr = static_cast(obj); - mdEdxCalibContainerBufferNew->setResidualCorrection(*residualCorr); - } else if (mTPCVDriftHelper->accountCCDBInputs(matcher, obj)) { - } else if (mFastTransformHelper->accountCCDBInputs(matcher, obj)) { - } -} - -bool GPURecoWorkflowSpec::fetchCalibsCCDBITS(ProcessingContext& pc) -{ - static bool initOnceDone = false; - if (!initOnceDone) { // this params need to be queried only once - initOnceDone = true; - pc.inputs().get("itscldict"); // just to trigger the finaliseCCDB - pc.inputs().get*>("itsalppar"); - mITSVertexer->getGlobalConfiguration(); - mITSTracker->getGlobalConfiguration(); - if (mSpecConfig.itsOverrBeamEst) { - pc.inputs().get("meanvtx"); - } - } - return false; -} - -template -bool GPURecoWorkflowSpec::fetchCalibsCCDBTPC(ProcessingContext& pc, T& newCalibObjects) -{ - // update calibrations for clustering and tracking - mMustUpdateFastTransform = false; - if ((mSpecConfig.outputTracks || mSpecConfig.caClusterer) && !mConfParam->disableCalibUpdates) { - const o2::tpc::CalibdEdxContainer* dEdxCalibContainer = mdEdxCalibContainer.get(); - - // this calibration is defined for clustering and tracking - if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalGainMap) || mUpdateGainMapCCDB) { - pc.inputs().get*>("tpcgain"); - } - - // these calibrations are only defined for the tracking - if (mSpecConfig.outputTracks) { - // update the calibration objects in case they changed in the CCDB - if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalThresholdMap)) { - pc.inputs().get>*>("tpcthreshold"); - } - - if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalResidualGainMap)) { - pc.inputs().get>*>("tpcgainresidual"); - } - - if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol)) { - pc.inputs().get("tpctopologygain"); - } - - if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalTimeGain)) { - pc.inputs().get("tpctimegain"); - } - - if (mSpecConfig.outputTracks) { - mTPCVDriftHelper->extractCCDBInputs(pc); - mFastTransformHelper->extractCCDBInputs(pc); - } - if (mTPCVDriftHelper->isUpdated() || mFastTransformHelper->isUpdated()) { - const auto& vd = mTPCVDriftHelper->getVDriftObject(); - LOGP(info, "Updating{}TPC fast transform map and/or VDrift factor of {} wrt reference {} and TDrift offset {} wrt reference {} from source {}", - mFastTransformHelper->isUpdated() ? " new " : " old ", - vd.corrFact, vd.refVDrift, vd.timeOffsetCorr, vd.refTimeOffset, mTPCVDriftHelper->getSourceName()); - - if (mTPCVDriftHelper->isUpdated() || mFastTransformHelper->isUpdatedMap()) { - mFastTransformNew.reset(new TPCFastTransform); - mFastTransformNew->cloneFromObject(*mFastTransformHelper->getCorrMap(), nullptr); - o2::tpc::TPCFastTransformHelperO2::instance()->updateCalibration(*mFastTransformNew, 0, vd.corrFact, vd.refVDrift, vd.getTimeOffset()); - newCalibObjects.fastTransform = mFastTransformNew.get(); - } - if (mTPCVDriftHelper->isUpdated() || mFastTransformHelper->isUpdatedMapRef()) { - mFastTransformRefNew.reset(new TPCFastTransform); - mFastTransformRefNew->cloneFromObject(*mFastTransformHelper->getCorrMapRef(), nullptr); - o2::tpc::TPCFastTransformHelperO2::instance()->updateCalibration(*mFastTransformRefNew, 0, vd.corrFact, vd.refVDrift, vd.getTimeOffset()); - newCalibObjects.fastTransformRef = mFastTransformRefNew.get(); - } - if (mFastTransformNew || mFastTransformRefNew || mFastTransformHelper->isUpdatedLumi()) { - mFastTransformHelperNew.reset(new o2::tpc::CorrectionMapsLoader); - mFastTransformHelperNew->setInstLumi(mFastTransformHelper->getInstLumi(), false); - mFastTransformHelperNew->setMeanLumi(mFastTransformHelper->getMeanLumi(), false); - mFastTransformHelperNew->setUseCTPLumi(mFastTransformHelper->getUseCTPLumi()); - mFastTransformHelperNew->setMeanLumiOverride(mFastTransformHelper->getMeanLumiOverride()); - mFastTransformHelperNew->setInstLumiOverride(mFastTransformHelper->getInstLumiOverride()); - mFastTransformHelperNew->setLumiScaleMode(mFastTransformHelper->getLumiScaleMode()); - mFastTransformHelperNew->setCorrMap(mFastTransformNew ? mFastTransformNew.get() : mFastTransform.get()); - mFastTransformHelperNew->setCorrMapRef(mFastTransformRefNew ? mFastTransformRefNew.get() : mFastTransformRef.get()); - mFastTransformHelperNew->acknowledgeUpdate(); - newCalibObjects.fastTransformHelper = mFastTransformHelperNew.get(); - } - mMustUpdateFastTransform = true; - mTPCVDriftHelper->acknowledgeUpdate(); - mFastTransformHelper->acknowledgeUpdate(); - } - } - - if (mdEdxCalibContainerBufferNew) { - newCalibObjects.dEdxCalibContainer = mdEdxCalibContainerBufferNew.get(); - } - - if (mTPCPadGainCalibBufferNew) { - newCalibObjects.tpcPadGain = mTPCPadGainCalibBufferNew.get(); - } - - return mdEdxCalibContainerBufferNew || mTPCPadGainCalibBufferNew || mMustUpdateFastTransform; - } - return false; -} - -void GPURecoWorkflowSpec::cleanOldCalibsTPCPtrs() -{ - if (mdEdxCalibContainerBufferNew) { - mdEdxCalibContainer = std::move(mdEdxCalibContainerBufferNew); - } - if (mTPCPadGainCalibBufferNew) { - mTPCPadGainCalib = std::move(mTPCPadGainCalibBufferNew); - } - if (mFastTransformNew) { - mFastTransform = std::move(mFastTransformNew); - } - if (mFastTransformRefNew) { - mFastTransformRef = std::move(mFastTransformRefNew); - } - if (mFastTransformHelperNew) { - mFastTransformHelper = std::move(mFastTransformHelperNew); - } -} - void GPURecoWorkflowSpec::deinitialize() { mQA.reset(nullptr); diff --git a/GPU/Workflow/src/GPUWorkflowTPC.cxx b/GPU/Workflow/src/GPUWorkflowTPC.cxx new file mode 100644 index 0000000000000..b0a18c153733a --- /dev/null +++ b/GPU/Workflow/src/GPUWorkflowTPC.cxx @@ -0,0 +1,377 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GPUWorkflowTPC.cxx +/// @author David Rohr + +#include "GPUWorkflow/GPUWorkflowSpec.h" +#include "Headers/DataHeader.h" +#include "Framework/WorkflowSpec.h" // o2::framework::mergeInputs +#include "Framework/DataRefUtils.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/SerializationMethods.h" +#include "Framework/Logger.h" +#include "Framework/CallbackService.h" +#include "Framework/CCDBParamSpec.h" +#include "DataFormatsTPC/TPCSectorHeader.h" +#include "DataFormatsTPC/ClusterNative.h" +#include "DataFormatsTPC/CompressedClusters.h" +#include "DataFormatsTPC/Helpers.h" +#include "DataFormatsTPC/ZeroSuppression.h" +#include "DataFormatsTPC/RawDataTypes.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include "DataFormatsGlobalTracking/TrackTuneParams.h" +#include "TPCReconstruction/TPCTrackingDigitsPreCheck.h" +#include "TPCReconstruction/TPCFastTransformHelperO2.h" +#include "DataFormatsTPC/Digit.h" +#include "TPCFastTransform.h" +#include "DPLUtils/DPLRawParser.h" +#include "DPLUtils/DPLRawPageSequencer.h" +#include "DetectorsBase/MatLayerCylSet.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "CommonUtils/NameConf.h" +#include "TPCBase/RDHUtils.h" +#include "GPUO2InterfaceConfiguration.h" +#include "GPUO2InterfaceQA.h" +#include "GPUO2Interface.h" +#include "CalibdEdxContainer.h" +#include "GPUNewCalibValues.h" +#include "TPCPadGainCalib.h" +#include "TPCZSLinkMapping.h" +#include "display/GPUDisplayInterface.h" +#include "TPCBase/Sector.h" +#include "TPCBase/Utils.h" +#include "TPCBase/CDBInterface.h" +#include "TPCCalibration/VDriftHelper.h" +#include "CorrectionMapsHelper.h" +#include "TPCCalibration/CorrectionMapsLoader.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "Algorithm/Parser.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsTRD/RecoInputContainer.h" +#include "TRDBase/Geometry.h" +#include "TRDBase/GeometryFlat.h" +#include "ITSBase/GeometryTGeo.h" +#include "CommonUtils/VerbosityConfig.h" +#include "CommonUtils/DebugStreamer.h" +#include +#include // for make_shared +#include +#include +#include +#include +#include +#include +#include +#include +#include "GPUReconstructionConvert.h" +#include "DetectorsRaw/RDHUtils.h" +#include +#include +#include +#include +#include +#include + +using namespace o2::framework; +using namespace o2::header; +using namespace o2::gpu; +using namespace o2::base; +using namespace o2::dataformats; + +namespace o2::gpu +{ + +void GPURecoWorkflowSpec::initFunctionTPCCalib(InitContext& ic) +{ + mdEdxCalibContainer.reset(new o2::tpc::CalibdEdxContainer()); + mTPCVDriftHelper.reset(new o2::tpc::VDriftHelper()); + mFastTransformHelper.reset(new o2::tpc::CorrectionMapsLoader()); + mFastTransform = std::move(o2::tpc::TPCFastTransformHelperO2::instance()->create(0)); + mFastTransformRef = std::move(o2::tpc::TPCFastTransformHelperO2::instance()->create(0)); + mFastTransformHelper->setCorrMap(mFastTransform.get()); // just to reserve the space + mFastTransformHelper->setCorrMapRef(mFastTransformRef.get()); + mFastTransformHelper->setLumiScaleMode(mSpecConfig.lumiScaleMode); + if (mSpecConfig.outputTracks) { + mFastTransformHelper->init(ic); + } + if (mConfParam->dEdxDisableTopologyPol) { + LOGP(info, "Disabling loading of track topology correction using polynomials from CCDB"); + mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol); + } + + if (mConfParam->dEdxDisableThresholdMap) { + LOGP(info, "Disabling loading of threshold map from CCDB"); + mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalThresholdMap); + } + + if (mConfParam->dEdxDisableGainMap) { + LOGP(info, "Disabling loading of gain map from CCDB"); + mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalGainMap); + } + + if (mConfParam->dEdxDisableResidualGainMap) { + LOGP(info, "Disabling loading of residual gain map from CCDB"); + mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalResidualGainMap); + } + + if (mConfParam->dEdxDisableResidualGain) { + LOGP(info, "Disabling loading of residual gain calibration from CCDB"); + mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTimeGain); + } + + if (mConfParam->dEdxUseFullGainMap) { + LOGP(info, "Using the full gain map for correcting the cluster charge during calculation of the dE/dx"); + mdEdxCalibContainer->setUsageOfFullGainMap(true); + } + + if (mConfParam->gainCalibDisableCCDB) { + LOGP(info, "Disabling loading the TPC pad gain calibration from the CCDB"); + mUpdateGainMapCCDB = false; + } + + // load from file + if (!mConfParam->dEdxPolTopologyCorrFile.empty() || !mConfParam->dEdxCorrFile.empty() || !mConfParam->dEdxSplineTopologyCorrFile.empty()) { + if (!mConfParam->dEdxPolTopologyCorrFile.empty()) { + LOGP(info, "Loading dE/dx polynomial track topology correction from file: {}", mConfParam->dEdxPolTopologyCorrFile); + mdEdxCalibContainer->loadPolTopologyCorrectionFromFile(mConfParam->dEdxPolTopologyCorrFile); + + LOGP(info, "Disabling loading of track topology correction using polynomials from CCDB as it was already loaded from input file"); + mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol); + + if (std::filesystem::exists(mConfParam->thresholdCalibFile)) { + LOG(info) << "Loading tpc zero supression map from file " << mConfParam->thresholdCalibFile; + const auto* thresholdMap = o2::tpc::utils::readCalPads(mConfParam->thresholdCalibFile, "ThresholdMap")[0]; + mdEdxCalibContainer->setZeroSupresssionThreshold(*thresholdMap); + + LOGP(info, "Disabling loading of threshold map from CCDB as it was already loaded from input file"); + mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalThresholdMap); + } else { + if (not mConfParam->thresholdCalibFile.empty()) { + LOG(warn) << "Couldn't find tpc zero supression file " << mConfParam->thresholdCalibFile << ". Not setting any zero supression."; + } + LOG(info) << "Setting default zero supression map"; + mdEdxCalibContainer->setDefaultZeroSupresssionThreshold(); + } + } else if (!mConfParam->dEdxSplineTopologyCorrFile.empty()) { + LOGP(info, "Loading dE/dx spline track topology correction from file: {}", mConfParam->dEdxSplineTopologyCorrFile); + mdEdxCalibContainer->loadSplineTopologyCorrectionFromFile(mConfParam->dEdxSplineTopologyCorrFile); + + LOGP(info, "Disabling loading of track topology correction using polynomials from CCDB as splines were loaded from input file"); + mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol); + } + if (!mConfParam->dEdxCorrFile.empty()) { + LOGP(info, "Loading dEdx correction from file: {}", mConfParam->dEdxCorrFile); + mdEdxCalibContainer->loadResidualCorrectionFromFile(mConfParam->dEdxCorrFile); + + LOGP(info, "Disabling loading of residual gain calibration from CCDB as it was already loaded from input file"); + mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTimeGain); + } + } + + if (mConfParam->dEdxPolTopologyCorrFile.empty() && mConfParam->dEdxSplineTopologyCorrFile.empty()) { + // setting default topology correction to allocate enough memory + LOG(info) << "Setting default dE/dx polynomial track topology correction to allocate enough memory"; + mdEdxCalibContainer->setDefaultPolTopologyCorrection(); + } + + GPUO2InterfaceConfiguration& config = *mConfig.get(); + mConfig->configCalib.dEdxCalibContainer = mdEdxCalibContainer.get(); + + if (std::filesystem::exists(mConfParam->gainCalibFile)) { + LOG(info) << "Loading tpc gain correction from file " << mConfParam->gainCalibFile; + const auto* gainMap = o2::tpc::utils::readCalPads(mConfParam->gainCalibFile, "GainMap")[0]; + mTPCPadGainCalib = GPUO2Interface::getPadGainCalib(*gainMap); + + LOGP(info, "Disabling loading the TPC gain correction map from the CCDB as it was already loaded from input file"); + mUpdateGainMapCCDB = false; + } else { + if (not mConfParam->gainCalibFile.empty()) { + LOG(warn) << "Couldn't find tpc gain correction file " << mConfParam->gainCalibFile << ". Not applying any gain correction."; + } + mTPCPadGainCalib = GPUO2Interface::getPadGainCalibDefault(); + mTPCPadGainCalib->getGainCorrection(30, 5, 5); + } + mConfig->configCalib.tpcPadGain = mTPCPadGainCalib.get(); + + mTPCZSLinkMapping.reset(new TPCZSLinkMapping{tpc::Mapper::instance()}); + mConfig->configCalib.tpcZSLinkMapping = mTPCZSLinkMapping.get(); +} + +void GPURecoWorkflowSpec::finaliseCCDBTPC(ConcreteDataMatcher& matcher, void* obj) +{ + const o2::tpc::CalibdEdxContainer* dEdxCalibContainer = mdEdxCalibContainer.get(); + + auto copyCalibsToBuffer = [this, dEdxCalibContainer]() { + if (!(mdEdxCalibContainerBufferNew)) { + mdEdxCalibContainerBufferNew = std::make_unique(); + mdEdxCalibContainerBufferNew->cloneFromObject(*dEdxCalibContainer, nullptr); + } + }; + + if (matcher == ConcreteDataMatcher(gDataOriginTPC, "PADGAINFULL", 0)) { + LOGP(info, "Updating gain map from CCDB"); + const auto* gainMap = static_cast*>(obj); + + if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalGainMap) && mSpecConfig.outputTracks) { + copyCalibsToBuffer(); + const float minGain = 0; + const float maxGain = 2; + mdEdxCalibContainerBufferNew.get()->setGainMap(*gainMap, minGain, maxGain); + } + + if (mUpdateGainMapCCDB && mSpecConfig.caClusterer) { + mTPCPadGainCalibBufferNew = GPUO2Interface::getPadGainCalib(*gainMap); + } + + } else if (matcher == ConcreteDataMatcher(gDataOriginTPC, "PADGAINRESIDUAL", 0)) { + LOGP(info, "Updating residual gain map from CCDB"); + copyCalibsToBuffer(); + const auto* gainMapResidual = static_cast>*>(obj); + const float minResidualGain = 0.7f; + const float maxResidualGain = 1.3f; + mdEdxCalibContainerBufferNew.get()->setGainMapResidual(gainMapResidual->at("GainMap"), minResidualGain, maxResidualGain); + } else if (matcher == ConcreteDataMatcher(gDataOriginTPC, "PADTHRESHOLD", 0)) { + LOGP(info, "Updating threshold map from CCDB"); + copyCalibsToBuffer(); + const auto* thresholdMap = static_cast>*>(obj); + mdEdxCalibContainerBufferNew.get()->setZeroSupresssionThreshold(thresholdMap->at("ThresholdMap")); + } else if (matcher == ConcreteDataMatcher(gDataOriginTPC, "TOPOLOGYGAIN", 0) && !(dEdxCalibContainer->isTopologyCorrectionSplinesSet())) { + LOGP(info, "Updating Q topology correction from CCDB"); + copyCalibsToBuffer(); + const auto* topologyCorr = static_cast(obj); + o2::tpc::CalibdEdxTrackTopologyPol calibTrackTopology; + calibTrackTopology.setFromContainer(*topologyCorr); + mdEdxCalibContainerBufferNew->setPolTopologyCorrection(calibTrackTopology); + } else if (matcher == ConcreteDataMatcher(gDataOriginTPC, "TIMEGAIN", 0)) { + LOGP(info, "Updating residual gain correction from CCDB"); + copyCalibsToBuffer(); + const auto* residualCorr = static_cast(obj); + mdEdxCalibContainerBufferNew->setResidualCorrection(*residualCorr); + } else if (mTPCVDriftHelper->accountCCDBInputs(matcher, obj)) { + } else if (mFastTransformHelper->accountCCDBInputs(matcher, obj)) { + } +} + +template <> +bool GPURecoWorkflowSpec::fetchCalibsCCDBTPC(ProcessingContext& pc, GPUCalibObjectsConst& newCalibObjects) +{ + // update calibrations for clustering and tracking + mMustUpdateFastTransform = false; + if ((mSpecConfig.outputTracks || mSpecConfig.caClusterer) && !mConfParam->disableCalibUpdates) { + const o2::tpc::CalibdEdxContainer* dEdxCalibContainer = mdEdxCalibContainer.get(); + + // this calibration is defined for clustering and tracking + if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalGainMap) || mUpdateGainMapCCDB) { + pc.inputs().get*>("tpcgain"); + } + + // these calibrations are only defined for the tracking + if (mSpecConfig.outputTracks) { + // update the calibration objects in case they changed in the CCDB + if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalThresholdMap)) { + pc.inputs().get>*>("tpcthreshold"); + } + + if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalResidualGainMap)) { + pc.inputs().get>*>("tpcgainresidual"); + } + + if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol)) { + pc.inputs().get("tpctopologygain"); + } + + if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalTimeGain)) { + pc.inputs().get("tpctimegain"); + } + + if (mSpecConfig.outputTracks) { + mTPCVDriftHelper->extractCCDBInputs(pc); + mFastTransformHelper->extractCCDBInputs(pc); + } + if (mTPCVDriftHelper->isUpdated() || mFastTransformHelper->isUpdated()) { + const auto& vd = mTPCVDriftHelper->getVDriftObject(); + LOGP(info, "Updating{}TPC fast transform map and/or VDrift factor of {} wrt reference {} and TDrift offset {} wrt reference {} from source {}", + mFastTransformHelper->isUpdated() ? " new " : " old ", + vd.corrFact, vd.refVDrift, vd.timeOffsetCorr, vd.refTimeOffset, mTPCVDriftHelper->getSourceName()); + + if (mTPCVDriftHelper->isUpdated() || mFastTransformHelper->isUpdatedMap()) { + mFastTransformNew.reset(new TPCFastTransform); + mFastTransformNew->cloneFromObject(*mFastTransformHelper->getCorrMap(), nullptr); + o2::tpc::TPCFastTransformHelperO2::instance()->updateCalibration(*mFastTransformNew, 0, vd.corrFact, vd.refVDrift, vd.getTimeOffset()); + newCalibObjects.fastTransform = mFastTransformNew.get(); + } + if (mTPCVDriftHelper->isUpdated() || mFastTransformHelper->isUpdatedMapRef()) { + mFastTransformRefNew.reset(new TPCFastTransform); + mFastTransformRefNew->cloneFromObject(*mFastTransformHelper->getCorrMapRef(), nullptr); + o2::tpc::TPCFastTransformHelperO2::instance()->updateCalibration(*mFastTransformRefNew, 0, vd.corrFact, vd.refVDrift, vd.getTimeOffset()); + newCalibObjects.fastTransformRef = mFastTransformRefNew.get(); + } + if (mFastTransformNew || mFastTransformRefNew || mFastTransformHelper->isUpdatedLumi()) { + mFastTransformHelperNew.reset(new o2::tpc::CorrectionMapsLoader); + mFastTransformHelperNew->setInstLumi(mFastTransformHelper->getInstLumi(), false); + mFastTransformHelperNew->setMeanLumi(mFastTransformHelper->getMeanLumi(), false); + mFastTransformHelperNew->setUseCTPLumi(mFastTransformHelper->getUseCTPLumi()); + mFastTransformHelperNew->setMeanLumiOverride(mFastTransformHelper->getMeanLumiOverride()); + mFastTransformHelperNew->setInstLumiOverride(mFastTransformHelper->getInstLumiOverride()); + mFastTransformHelperNew->setLumiScaleMode(mFastTransformHelper->getLumiScaleMode()); + mFastTransformHelperNew->setCorrMap(mFastTransformNew ? mFastTransformNew.get() : mFastTransform.get()); + mFastTransformHelperNew->setCorrMapRef(mFastTransformRefNew ? mFastTransformRefNew.get() : mFastTransformRef.get()); + mFastTransformHelperNew->acknowledgeUpdate(); + newCalibObjects.fastTransformHelper = mFastTransformHelperNew.get(); + } + mMustUpdateFastTransform = true; + mTPCVDriftHelper->acknowledgeUpdate(); + mFastTransformHelper->acknowledgeUpdate(); + } + } + + if (mdEdxCalibContainerBufferNew) { + newCalibObjects.dEdxCalibContainer = mdEdxCalibContainerBufferNew.get(); + } + + if (mTPCPadGainCalibBufferNew) { + newCalibObjects.tpcPadGain = mTPCPadGainCalibBufferNew.get(); + } + + return mdEdxCalibContainerBufferNew || mTPCPadGainCalibBufferNew || mMustUpdateFastTransform; + } + return false; +} + +void GPURecoWorkflowSpec::cleanOldCalibsTPCPtrs() +{ + if (mdEdxCalibContainerBufferNew) { + mdEdxCalibContainer = std::move(mdEdxCalibContainerBufferNew); + } + if (mTPCPadGainCalibBufferNew) { + mTPCPadGainCalib = std::move(mTPCPadGainCalibBufferNew); + } + if (mFastTransformNew) { + mFastTransform = std::move(mFastTransformNew); + } + if (mFastTransformRefNew) { + mFastTransformRef = std::move(mFastTransformRefNew); + } + if (mFastTransformHelperNew) { + mFastTransformHelper = std::move(mFastTransformHelperNew); + } +} + +} // namespace o2::gpu From 74652e9308f3224665941bd65f77315e58140873 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 18 Sep 2023 23:40:23 +0200 Subject: [PATCH 066/324] GPU Workflow: Move some functionality from run function into dedicated functions --- .../include/GPUWorkflow/GPUWorkflowSpec.h | 6 + GPU/Workflow/src/GPUWorkflowSpec.cxx | 116 ++++++++---------- GPU/Workflow/src/GPUWorkflowTPC.cxx | 29 +++++ 3 files changed, 86 insertions(+), 65 deletions(-) diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index 9711356c62aeb..00fa295698ec1 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -77,6 +77,7 @@ struct TPCPadGainCalib; struct TPCZSLinkMapping; struct GPUSettingsO2; class GPUO2InterfaceQA; +struct GPUTrackingInOutPointers; class GPURecoWorkflowSpec : public o2::framework::Task { @@ -139,6 +140,11 @@ class GPURecoWorkflowSpec : public o2::framework::Task void doCalibUpdates(o2::framework::ProcessingContext& pc); + void doTrackTuneTPC(GPUTrackingInOutPointers& ptrs, char* buffout); + + template + void processInputs(o2::framework::ProcessingContext&, A&, B&, C&, D&, E&, F&, G&, bool&, H&, I&, J&, K&); + int runITSTracking(o2::framework::ProcessingContext& pc); CompletionPolicyData* mPolicyData; diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index c9a4975969305..a1bcf05cf63c8 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -337,48 +337,12 @@ void GPURecoWorkflowSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& match } } -void GPURecoWorkflowSpec::run(ProcessingContext& pc) +template +void GPURecoWorkflowSpec::processInputs(ProcessingContext& pc, A& tpcZSmetaPointers, B& tpcZSmetaPointers2, C& tpcZSmetaSizes, D& tpcZSmetaSizes2, E& inputZS, F& tpcZS, G& tpcZSonTheFlySizes, bool& debugTFDump, H& compClustersDummy, I& compClustersFlatDummy, J& pCompClustersFlat, K& tmpEmptyCompClusters) { constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR; constexpr static size_t NEndpoints = o2::gpu::GPUTrackingInOutZS::NENDPOINTS; - auto cput = mTimer->CpuTime(); - auto realt = mTimer->RealTime(); - mTimer->Start(false); - mNTFs++; - - GRPGeomHelper::instance().checkUpdates(pc); - if (GRPGeomHelper::instance().getGRPECS()->isDetReadOut(o2::detectors::DetID::TPC) && mConfParam->tpcTriggeredMode ^ !GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::TPC)) { - LOG(fatal) << "configKeyValue tpcTriggeredMode does not match GRP isDetContinuousReadOut(TPC) setting"; - } - - std::vector> inputs; - - const o2::tpc::CompressedClustersFlat* pCompClustersFlat = nullptr; - size_t compClustersFlatDummyMemory[(sizeof(o2::tpc::CompressedClustersFlat) + sizeof(size_t) - 1) / sizeof(size_t)]; - o2::tpc::CompressedClustersFlat& compClustersFlatDummy = reinterpret_cast(compClustersFlatDummyMemory); - o2::tpc::CompressedClusters compClustersDummy; - o2::gpu::GPUTrackingInOutZS tpcZS; - std::vector tpcZSmetaPointers[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; - std::vector tpcZSmetaSizes[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; - const void** tpcZSmetaPointers2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; - const unsigned int* tpcZSmetaSizes2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; - std::array tpcZSonTheFlySizes; - gsl::span inputZS; - - bool getWorkflowTPCInput_clusters = false, getWorkflowTPCInput_mc = false, getWorkflowTPCInput_digits = false; - bool debugTFDump = false; - - if (mSpecConfig.processMC) { - getWorkflowTPCInput_mc = true; - } - if (!mSpecConfig.decompressTPC && !mSpecConfig.caClusterer) { - getWorkflowTPCInput_clusters = true; - } - if (!mSpecConfig.decompressTPC && mSpecConfig.caClusterer && ((!mSpecConfig.zsOnTheFly || mSpecConfig.processMC) && !mSpecConfig.zsDecoder)) { - getWorkflowTPCInput_digits = true; - } - if (mSpecConfig.zsOnTheFly || mSpecConfig.zsDecoder) { for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { @@ -424,7 +388,6 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) } } } - std::unique_ptr tmpEmptyCompClusters; if (mSpecConfig.zsDecoder) { std::vector filter = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}}; auto isSameRdh = [](const char* left, const char* right) -> bool { @@ -496,8 +459,53 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) LOGF(info, "running tracking for sector(s) 0x%09x", mTPCSectorMask); } } +} + +void GPURecoWorkflowSpec::run(ProcessingContext& pc) +{ + constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR; + constexpr static size_t NEndpoints = o2::gpu::GPUTrackingInOutZS::NENDPOINTS; + + auto cput = mTimer->CpuTime(); + auto realt = mTimer->RealTime(); + mTimer->Start(false); + mNTFs++; + + GRPGeomHelper::instance().checkUpdates(pc); + if (GRPGeomHelper::instance().getGRPECS()->isDetReadOut(o2::detectors::DetID::TPC) && mConfParam->tpcTriggeredMode ^ !GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::TPC)) { + LOG(fatal) << "configKeyValue tpcTriggeredMode does not match GRP isDetContinuousReadOut(TPC) setting"; + } + + std::vector> inputs; - const auto& inputsClustersDigits = o2::tpc::getWorkflowTPCInput(pc, mVerbosity, getWorkflowTPCInput_mc, getWorkflowTPCInput_clusters, mTPCSectorMask, getWorkflowTPCInput_digits); + const o2::tpc::CompressedClustersFlat* pCompClustersFlat = nullptr; + size_t compClustersFlatDummyMemory[(sizeof(o2::tpc::CompressedClustersFlat) + sizeof(size_t) - 1) / sizeof(size_t)]; + o2::tpc::CompressedClustersFlat& compClustersFlatDummy = reinterpret_cast(compClustersFlatDummyMemory); + o2::tpc::CompressedClusters compClustersDummy; + o2::gpu::GPUTrackingInOutZS tpcZS; + std::vector tpcZSmetaPointers[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + std::vector tpcZSmetaSizes[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + const void** tpcZSmetaPointers2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + const unsigned int* tpcZSmetaSizes2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + std::array tpcZSonTheFlySizes; + gsl::span inputZS; + std::unique_ptr tmpEmptyCompClusters; + + bool getWorkflowTPCInput_clusters = false, getWorkflowTPCInput_mc = false, getWorkflowTPCInput_digits = false; + bool debugTFDump = false; + + if (mSpecConfig.processMC) { + getWorkflowTPCInput_mc = true; + } + if (!mSpecConfig.decompressTPC && !mSpecConfig.caClusterer) { + getWorkflowTPCInput_clusters = true; + } + if (!mSpecConfig.decompressTPC && mSpecConfig.caClusterer && ((!mSpecConfig.zsOnTheFly || mSpecConfig.processMC) && !mSpecConfig.zsDecoder)) { + getWorkflowTPCInput_digits = true; + } + + processInputs(pc, tpcZSmetaPointers, tpcZSmetaPointers2, tpcZSmetaSizes, tpcZSmetaSizes2, inputZS, tpcZS, tpcZSonTheFlySizes, debugTFDump, compClustersDummy, compClustersFlatDummy, pCompClustersFlat, tmpEmptyCompClusters); // Process non-digit / non-cluster inputs + const auto& inputsClustersDigits = o2::tpc::getWorkflowTPCInput(pc, mVerbosity, getWorkflowTPCInput_mc, getWorkflowTPCInput_clusters, mTPCSectorMask, getWorkflowTPCInput_digits); // Process digit and cluster inputs GPUTrackingInOutPointers ptrs; o2::globaltracking::RecoContainer inputTracksTRD; @@ -796,32 +804,10 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) downSizeBufferToSpan(outputRegions.tpcTracksO2Labels, spanOutputTracksMCTruth); // if requested, tune TPC tracks - using TrackTunePar = o2::globaltracking::TrackTuneParams; - const auto& trackTune = TrackTunePar::Instance(); - if (ptrs.nOutputTracksTPCO2 && trackTune.sourceLevelTPC && - (trackTune.useTPCInnerCorr || trackTune.useTPCOuterCorr || - trackTune.tpcCovInnerType != TrackTunePar::AddCovType::Disable || trackTune.tpcCovOuterType != TrackTunePar::AddCovType::Disable)) { - auto buffout = outputBuffers[outputRegions.getIndex(outputRegions.tpcTracksO2)].first->get().data(); - if (((const void*)ptrs.outputTracksTPCO2) != ((const void*)buffout)) { - throw std::runtime_error("Buffer does not match span"); - } - o2::tpc::TrackTPC* tpcTracks = reinterpret_cast(buffout); - for (unsigned int itr = 0; itr < ptrs.nOutputTracksTPCO2; itr++) { - auto& trc = tpcTracks[itr]; - if (trackTune.useTPCInnerCorr) { - trc.updateParams(trackTune.tpcParInner); - } - if (trackTune.tpcCovInnerType != TrackTunePar::AddCovType::Disable) { - trc.updateCov(trackTune.tpcCovInner, trackTune.tpcCovInnerType == TrackTunePar::AddCovType::WithCorrelations); - } - if (trackTune.useTPCOuterCorr) { - trc.getParamOut().updateParams(trackTune.tpcParOuter); - } - if (trackTune.tpcCovOuterType != TrackTunePar::AddCovType::Disable) { - trc.getParamOut().updateCov(trackTune.tpcCovOuter, trackTune.tpcCovOuterType == TrackTunePar::AddCovType::WithCorrelations); - } - } + if (ptrs.nOutputTracksTPCO2) { + doTrackTuneTPC(ptrs, outputBuffers[outputRegions.getIndex(outputRegions.tpcTracksO2)].first->get().data()); } + if (mClusterOutputIds.size() > 0 && (void*)ptrs.clustersNative->clustersLinear != (void*)(outputBuffers[outputRegions.getIndex(outputRegions.clustersNative)].second + sizeof(o2::tpc::ClusterCountIndex))) { throw std::runtime_error("cluster native output ptrs out of sync"); // sanity check } diff --git a/GPU/Workflow/src/GPUWorkflowTPC.cxx b/GPU/Workflow/src/GPUWorkflowTPC.cxx index b0a18c153733a..578d35a72258a 100644 --- a/GPU/Workflow/src/GPUWorkflowTPC.cxx +++ b/GPU/Workflow/src/GPUWorkflowTPC.cxx @@ -374,4 +374,33 @@ void GPURecoWorkflowSpec::cleanOldCalibsTPCPtrs() } } +void GPURecoWorkflowSpec::doTrackTuneTPC(GPUTrackingInOutPointers& ptrs, char* buffout) +{ + using TrackTunePar = o2::globaltracking::TrackTuneParams; + const auto& trackTune = TrackTunePar::Instance(); + if (ptrs.nOutputTracksTPCO2 && trackTune.sourceLevelTPC && + (trackTune.useTPCInnerCorr || trackTune.useTPCOuterCorr || + trackTune.tpcCovInnerType != TrackTunePar::AddCovType::Disable || trackTune.tpcCovOuterType != TrackTunePar::AddCovType::Disable)) { + if (((const void*)ptrs.outputTracksTPCO2) != ((const void*)buffout)) { + throw std::runtime_error("Buffer does not match span"); + } + o2::tpc::TrackTPC* tpcTracks = reinterpret_cast(buffout); + for (unsigned int itr = 0; itr < ptrs.nOutputTracksTPCO2; itr++) { + auto& trc = tpcTracks[itr]; + if (trackTune.useTPCInnerCorr) { + trc.updateParams(trackTune.tpcParInner); + } + if (trackTune.tpcCovInnerType != TrackTunePar::AddCovType::Disable) { + trc.updateCov(trackTune.tpcCovInner, trackTune.tpcCovInnerType == TrackTunePar::AddCovType::WithCorrelations); + } + if (trackTune.useTPCOuterCorr) { + trc.getParamOut().updateParams(trackTune.tpcParOuter); + } + if (trackTune.tpcCovOuterType != TrackTunePar::AddCovType::Disable) { + trc.getParamOut().updateCov(trackTune.tpcCovOuter, trackTune.tpcCovOuterType == TrackTunePar::AddCovType::WithCorrelations); + } + } + } +} + } // namespace o2::gpu From 4830e6767d685fb7aa35ed8fcc46469d2fb438f1 Mon Sep 17 00:00:00 2001 From: Arvind Khuntia Date: Tue, 5 Sep 2023 16:04:18 +0200 Subject: [PATCH 067/324] [FDD] TCM trgeer signals added to Simulation --- .../FIT/FDD/simulation/src/Digitizer.cxx | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/Detectors/FIT/FDD/simulation/src/Digitizer.cxx b/Detectors/FIT/FDD/simulation/src/Digitizer.cxx index c8be105263fdc..6551c31ed02a6 100644 --- a/Detectors/FIT/FDD/simulation/src/Digitizer.cxx +++ b/Detectors/FIT/FDD/simulation/src/Digitizer.cxx @@ -192,25 +192,51 @@ void Digitizer::storeBC(const BCCache& bc, o2::dataformats::MCTruthContainer& labels) { // LOG(info) << "Storing BC " << bc; - int first = digitsCh.size(), nStored = 0; + float totalChargeA = 0, totalChargeC = 0; + int n_hit_A = 0, n_hit_C = 0, total_time_A = 0, total_time_C = 0; + bool nChCside = 8; for (int ic = 0; ic < Nchannels; ic++) { float chargeADC = integrateCharge(bc.pulse[ic]); + int cfdTime = int(simulateTimeCFD(bc.pulse[ic])); + if (chargeADC != 0) { + if (ic < nChCside) { + totalChargeC += chargeADC; + total_time_C += cfdTime; + n_hit_C++; + } else { + totalChargeA += chargeADC; + total_time_A += cfdTime; + n_hit_A++; + } uint8_t channelBits = parameters.defaultFEEbits; if (std::rand() % 2) { ChannelData::setFlag(ChannelData::kNumberADC, channelBits); } - digitsCh.emplace_back(ic, int(simulateTimeCFD(bc.pulse[ic])), int(chargeADC), channelBits); + digitsCh.emplace_back(ic, cfdTime, int(chargeADC), channelBits); nStored++; } } - // bc.print(); - + //SET TRIGGERS + Bool_t is_A, is_C, isVertex, is_Central, is_SemiCentral = 0; + is_A = n_hit_A > 0; + is_C = n_hit_C > 0; + uint32_t amplA = is_A ? totalChargeA * 0.125 : -5000; // sum amplitude A side / 8 (hardware) + uint32_t amplC = is_C ? totalChargeC * 0.125 : -5000; // sum amplitude C side / 8 (hardware) + int timeA = is_A ? total_time_A / n_hit_A : -5000; // average time A side + int timeC = is_C ? total_time_C / n_hit_C : -5000; // average time C side + isVertex = is_A && is_C; + + bool isLaser = false; + bool isOutputsAreBlocked = false; + bool isDataValid = true; + mTriggers.setTriggers(is_A, is_C, isVertex, is_Central, is_SemiCentral, int8_t(n_hit_A), int8_t(n_hit_C), + amplA, amplC, timeA, timeC, isLaser, isOutputsAreBlocked, isDataValid); if (nStored != 0) { int nBC = digitsBC.size(); digitsBC.emplace_back(first, nStored, bc, mTriggers); - digitsTrig.emplace_back(bc, 0, 0, 0, 0, 0); + digitsTrig.emplace_back(bc, is_A, is_C, isVertex, is_Central, is_SemiCentral); for (const auto& lbl : bc.labels) { labels.addElement(nBC, lbl); From 5e2d747fcfaf9ba8e04e662eaed49384538aefbe Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Tue, 5 Sep 2023 14:08:58 +0000 Subject: [PATCH 068/324] Please consider the following formatting changes --- Detectors/FIT/FDD/simulation/src/Digitizer.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/FIT/FDD/simulation/src/Digitizer.cxx b/Detectors/FIT/FDD/simulation/src/Digitizer.cxx index 6551c31ed02a6..adb056792d8e4 100644 --- a/Detectors/FIT/FDD/simulation/src/Digitizer.cxx +++ b/Detectors/FIT/FDD/simulation/src/Digitizer.cxx @@ -218,7 +218,7 @@ void Digitizer::storeBC(const BCCache& bc, nStored++; } } - //SET TRIGGERS + // SET TRIGGERS Bool_t is_A, is_C, isVertex, is_Central, is_SemiCentral = 0; is_A = n_hit_A > 0; is_C = n_hit_C > 0; From a6d615bd131532a4123e22a775bae7772e9626a4 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 19 Sep 2023 16:10:49 +0200 Subject: [PATCH 069/324] Fix missing cassert include Previously implicit inclusion dropped in new XCode. --- Common/Utils/include/CommonUtils/ConfigurableParam.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Common/Utils/include/CommonUtils/ConfigurableParam.h b/Common/Utils/include/CommonUtils/ConfigurableParam.h index 2d1984f4d9ef3..08356dc462de8 100644 --- a/Common/Utils/include/CommonUtils/ConfigurableParam.h +++ b/Common/Utils/include/CommonUtils/ConfigurableParam.h @@ -15,6 +15,7 @@ #define COMMON_SIMCONFIG_INCLUDE_SIMCONFIG_CONFIGURABLEPARAM_H_ #include +#include #include #include #include From ceda7372f136bbfe89dcbc2e62e805c89b255af5 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 20 Sep 2023 08:43:50 +0200 Subject: [PATCH 070/324] DPL: make sure ccdb-run-dependent is treated as bool (#11917) --- .../Core/src/DataDescriptorQueryBuilder.cxx | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/Framework/Core/src/DataDescriptorQueryBuilder.cxx b/Framework/Core/src/DataDescriptorQueryBuilder.cxx index cb4ad54b23b95..f79698ea2a08d 100644 --- a/Framework/Core/src/DataDescriptorQueryBuilder.cxx +++ b/Framework/Core/src/DataDescriptorQueryBuilder.cxx @@ -316,19 +316,43 @@ std::vector DataDescriptorQueryBuilder::parse(char const* config) if (*currentKey == "lifetime" && currentValue == "condition") { currentLifetime = Lifetime::Condition; } - attributes.push_back(ConfigParamSpec{*currentKey, VariantType::String, *currentValue, {}}); + if (*currentKey == "ccdb-run-dependent" && (currentValue != "false" && currentValue != "0")) { + attributes.push_back(ConfigParamSpec{*currentKey, VariantType::Bool, true, {}}); + } else if (*currentKey == "ccdb-run-dependent" && (currentValue == "false" || currentValue == "0")) { + attributes.push_back(ConfigParamSpec{*currentKey, VariantType::Bool, false, {}}); + } else if (*currentKey == "ccdb-run-dependent") { + error("ccdb-run-dependent can only be true or false"); + } else { + attributes.push_back(ConfigParamSpec{*currentKey, VariantType::String, *currentValue, {}}); + } } else if (*next == ';') { assignLastStringMatch("value", 1000, currentValue, IN_END_ATTRIBUTES); if (*currentKey == "lifetime" && currentValue == "condition") { currentLifetime = Lifetime::Condition; } - attributes.push_back(ConfigParamSpec{*currentKey, VariantType::String, *currentValue, {}}); + if (*currentKey == "ccdb-run-dependent" && (currentValue != "false" && currentValue != "0")) { + attributes.push_back(ConfigParamSpec{*currentKey, VariantType::Bool, true, {}}); + } else if (*currentKey == "ccdb-run-dependent" && (currentValue == "false" || currentValue == "0")) { + attributes.push_back(ConfigParamSpec{*currentKey, VariantType::Bool, false, {}}); + } else if (*currentKey == "ccdb-run-dependent") { + error("ccdb-run-dependent can only be true or false"); + } else { + attributes.push_back(ConfigParamSpec{*currentKey, VariantType::String, *currentValue, {}}); + } } else if (*next == '\0') { assignLastStringMatch("value", 1000, currentValue, IN_END_ATTRIBUTES); if (*currentKey == "lifetime" && currentValue == "condition") { currentLifetime = Lifetime::Condition; } - attributes.push_back(ConfigParamSpec{*currentKey, VariantType::String, *currentValue, {}}); + if (*currentKey == "ccdb-run-dependent" && (currentValue != "false" && currentValue != "0")) { + attributes.push_back(ConfigParamSpec{*currentKey, VariantType::Bool, true, {}}); + } else if (*currentKey == "ccdb-run-dependent" && (currentValue == "false" || currentValue == "0")) { + attributes.push_back(ConfigParamSpec{*currentKey, VariantType::Bool, false, {}}); + } else if (*currentKey == "ccdb-run-dependent") { + error("ccdb-run-dependent can only be true or false"); + } else { + attributes.push_back(ConfigParamSpec{*currentKey, VariantType::String, *currentValue, {}}); + } } else { error("missing value for string value"); } From 971ab9b5012e50c4e405019388845519e4bb49a9 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 20 Sep 2023 08:44:38 +0200 Subject: [PATCH 071/324] Avoid ambiguity in function name (#11914) Apple clang version 15.0.0 (clang-1500.0.40.1) complains about inject being ambiguous, and indeed it's not clear to me how this could have worked in the first place. Reworked to split the implementation in two, and select the injectBool version only for the case in which there is a single header. --- DataFormats/Headers/include/Headers/Stack.h | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/DataFormats/Headers/include/Headers/Stack.h b/DataFormats/Headers/include/Headers/Stack.h index 184733e35c339..259a445f18cf8 100644 --- a/DataFormats/Headers/include/Headers/Stack.h +++ b/DataFormats/Headers/include/Headers/Stack.h @@ -16,6 +16,7 @@ namespace o2 { + namespace header { //__________________________________________________________________________________________________ @@ -103,7 +104,11 @@ struct Stack { bufferSize{calculateSize(std::forward(headers)...)}, buffer{static_cast(allocator.resource()->allocate(bufferSize, alignof(std::max_align_t))), freeobj{allocator.resource()}} { - inject(buffer.get(), std::forward(headers)...); + if constexpr (sizeof...(headers) > 1) { + injectAll(buffer.get(), std::forward(headers)...); + } else if (sizeof...(headers) == 1) { + injectBool(buffer.get(), std::forward(headers)..., false); + } } //______________________________________________________________________________________________ @@ -144,7 +149,7 @@ struct Stack { //______________________________________________________________________________________________ template - static std::byte* inject(std::byte* here, T&& h, bool more = false) noexcept + static std::byte* injectBool(std::byte* here, T&& h, bool more) noexcept { using headerType = typename std::remove_cv::type>::type; if (here == nullptr) { @@ -189,11 +194,15 @@ struct Stack { //______________________________________________________________________________________________ template - static std::byte* inject(std::byte* here, T&& h, Args&&... args) noexcept + static std::byte* injectAll(std::byte* here, T&& h, Args&&... args) noexcept { bool more = hasNonEmptyArg(args...); - auto alsohere = inject(here, h, more); - return inject(alsohere, args...); + auto alsohere = injectBool(here, h, more); + if constexpr (sizeof...(args) > 1) { + return injectAll(alsohere, args...); + } else { + return injectBool(alsohere, args..., false); + } } //______________________________________________________________________________________________ From b8c1b2682ba6d2d891fdb20612feef8ffb56713b Mon Sep 17 00:00:00 2001 From: Piotr Konopka Date: Wed, 20 Sep 2023 08:58:36 +0200 Subject: [PATCH 072/324] DPL: Use ALIEN_PROD_ID to know we run on Grid (#11921) --- Framework/Core/src/DefaultsHelpers.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Core/src/DefaultsHelpers.cxx b/Framework/Core/src/DefaultsHelpers.cxx index 443eaed2ffae7..88956b93a855d 100644 --- a/Framework/Core/src/DefaultsHelpers.cxx +++ b/Framework/Core/src/DefaultsHelpers.cxx @@ -55,7 +55,7 @@ static DeploymentMode getDeploymentMode_internal() throw std::runtime_error("Invalid deployment mode"); } } - return getenv("DDS_SESSION_ID") != nullptr ? DeploymentMode::OnlineDDS : (getenv("OCC_CONTROL_PORT") != nullptr ? DeploymentMode::OnlineECS : (getenv("ALIEN_JOB_ID") != nullptr ? DeploymentMode::Grid : (getenv("ALICE_O2_FST") ? DeploymentMode::FST : (DeploymentMode::Local)))); + return getenv("DDS_SESSION_ID") != nullptr ? DeploymentMode::OnlineDDS : (getenv("OCC_CONTROL_PORT") != nullptr ? DeploymentMode::OnlineECS : (getenv("ALIEN_PROC_ID") != nullptr ? DeploymentMode::Grid : (getenv("ALICE_O2_FST") ? DeploymentMode::FST : (DeploymentMode::Local)))); } DeploymentMode DefaultsHelpers::deploymentMode() From 9f23cffc2f5e1b46d5fbc39ff9c41adfb66e0296 Mon Sep 17 00:00:00 2001 From: wiechula Date: Wed, 13 Sep 2023 11:03:45 +0200 Subject: [PATCH 073/324] Add configKeyValues to laser track calibration --- Detectors/TPC/workflow/src/tpc-calib-laser-tracks.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Detectors/TPC/workflow/src/tpc-calib-laser-tracks.cxx b/Detectors/TPC/workflow/src/tpc-calib-laser-tracks.cxx index b69308e2bd109..68481f86cbc5d 100644 --- a/Detectors/TPC/workflow/src/tpc-calib-laser-tracks.cxx +++ b/Detectors/TPC/workflow/src/tpc-calib-laser-tracks.cxx @@ -13,6 +13,7 @@ #include "TPCWorkflow/CalibLaserTracksSpec.h" #include "Framework/CompletionPolicy.h" #include "Framework/CompletionPolicyHelpers.h" +#include "CommonUtils/ConfigurableParam.h" using namespace o2::framework; @@ -22,6 +23,8 @@ void customize(std::vector& workflowOptions) std::vector options{ {"input-spec", VariantType::String, "input:TPC/TRACKS", {"selection string input specs"}}, {"use-filtered-tracks", VariantType::Bool, false, {"use prefiltered laser tracks as input"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, }; std::swap(workflowOptions, options); @@ -33,6 +36,10 @@ void customize(std::vector& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& config) { + // set up configuration + o2::conf::ConfigurableParam::updateFromFile(config.options().get("configFile")); + o2::conf::ConfigurableParam::updateFromString(config.options().get("configKeyValues")); + WorkflowSpec specs; std::string inputSpec = config.options().get("input-spec"); if (config.options().get("use-filtered-tracks")) { From ba4ad4baa17c12929209a50c9a1aa15e90e03d8c Mon Sep 17 00:00:00 2001 From: wiechula Date: Tue, 19 Sep 2023 16:06:32 +0200 Subject: [PATCH 074/324] Add trigger word including orbit information --- .../TPC/include/DataFormatsTPC/ZeroSuppression.h | 9 +++++++++ DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h index f89e790e36a87..85ee355dde9c5 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h @@ -19,6 +19,7 @@ #include // for size_t #endif #include "GPUCommonDef.h" +#include "GPUCommonRtypes.h" namespace o2 { @@ -103,6 +104,14 @@ struct TriggerWordDLBZS { bool isValid(int entry = 0) const { return triggerEntries[entry] & 0x8000; } }; +/// Trigger info including the orbit +struct TriggerInfoDLBZS { + TriggerWordDLBZS triggerWord{}; ///< trigger Word information + uint32_t orbit{}; ///< orbit of the trigger word + + ClassDefNV(TriggerInfoDLBZS, 1); +}; + } // namespace tpc } // namespace o2 #endif diff --git a/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h b/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h index 023892f01b92a..4f513317ced63 100644 --- a/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h +++ b/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h @@ -70,5 +70,7 @@ #pragma link C++ class o2::tpc::dcs::DataPointVector < o2::tpc::dcs::HV::StackState> + ; #pragma link C++ class o2::tpc::dcs::Gas + ; #pragma link C++ class o2::tpc::PIDResponse + ; +#pragma link C++ class o2::tpc::TriggerInfoDLBZS + ; +#pragma link C++ class std::vector < o2::tpc::TriggerInfoDLBZS> + ; #endif From 36cee8c615761b9df41c34835180f9883b00d492 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 20 Sep 2023 11:33:32 +0200 Subject: [PATCH 075/324] GPU TPC: Send TPC trigger words with orbit information --- GPU/GPUTracking/DataTypes/GPUTriggerOutputs.h | 21 +++++++++++++------ .../Global/GPUChainTrackingClusterizer.cxx | 9 +++++--- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/GPU/GPUTracking/DataTypes/GPUTriggerOutputs.h b/GPU/GPUTracking/DataTypes/GPUTriggerOutputs.h index 41427e331cab2..0a3208f8e67a7 100644 --- a/GPU/GPUTracking/DataTypes/GPUTriggerOutputs.h +++ b/GPU/GPUTracking/DataTypes/GPUTriggerOutputs.h @@ -30,19 +30,28 @@ namespace gpu struct GPUTriggerOutputs { #ifdef GPUCA_HAVE_O2HEADERS struct hasher { - size_t operator()(const std::array& key) const + size_t operator()(const o2::tpc::TriggerInfoDLBZS& key) const { - std::hash std_hasher; + std::array tmp; + memcpy((void*)tmp.data(), (const void*)&key, sizeof(key)); + std::hash std_hasher; size_t result = 0; - for (size_t i = 0; i < key.size(); ++i) { - result ^= std_hasher(key[i]); + for (size_t i = 0; i < tmp.size(); ++i) { + result ^= std_hasher(tmp[i]); } return result; } }; - std::unordered_set, hasher> triggers; - static_assert(o2::tpc::TPCZSHDRV2::TRIGGER_WORD_SIZE % sizeof(unsigned long) == 0); + struct equal { + bool operator()(const o2::tpc::TriggerInfoDLBZS& lhs, const o2::tpc::TriggerInfoDLBZS& rhs) const + { + return memcmp((const void*)&lhs, (const void*)&rhs, sizeof(lhs)) == 0; + } + }; + + std::unordered_set triggers; + static_assert(sizeof(o2::tpc::TriggerInfoDLBZS) % sizeof(unsigned int) == 0); #endif }; diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index e522cbd52a5f2..e3feafa55b9cb 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -233,9 +233,12 @@ std::pair GPUChainTracking::TPCClusterizerDecodeZSCo const TPCZSHDRV2* const hdr2 = (const TPCZSHDRV2*)hdr; if (hdr2->flags & TPCZSHDRV2::ZSFlags::TriggerWordPresent) { const char* triggerWord = (const char*)hdr - TPCZSHDRV2::TRIGGER_WORD_SIZE; - std::array tmp; - memcpy((void*)tmp.data(), triggerWord, TPCZSHDRV2::TRIGGER_WORD_SIZE); - mTriggerBuffer->triggers.emplace(tmp); + o2::tpc::TriggerInfoDLBZS tmp; + memcpy((void*)&tmp.triggerWord, triggerWord, TPCZSHDRV2::TRIGGER_WORD_SIZE); + tmp.orbit = o2::raw::RDHUtils::getHeartBeatOrbit(*rdh); + if (tmp.triggerWord.isValid(0)) { + mTriggerBuffer->triggers.emplace(tmp); + } } } nDigits += hdr->nADCsamples; From a77717b6ffb461cceed954104ad531fa7efe9573 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 20 Sep 2023 14:07:03 +0200 Subject: [PATCH 076/324] GPU TPC: Always send TPC TRIGGERWORD in gpu-reconstruction, sending empty dummy word when processing data that has no triggers --- GPU/GPUTracking/Definitions/GPUSettingsList.h | 2 +- .../Global/GPUChainTrackingClusterizer.cxx | 34 +++++++++---------- GPU/Workflow/src/GPUWorkflowSpec.cxx | 3 ++ prodtests/full-system-test/dpl-workflow.sh | 3 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index d718cf1cacc8d..590eab609b579 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -178,7 +178,7 @@ EndConfig() BeginSubConfig(GPUSettingsProcessingParam, param, configStandalone.proc, "PARAM", 0, "Processing settings", proc_param) AddOptionArray(tpcErrorParamY, float, 4, (0.06, 0.24, 0.12, 0.1), "", 0, "TPC Cluster Y Error Parameterization") AddOptionArray(tpcErrorParamZ, float, 4, (0.06, 0.24, 0.15, 0.1), "", 0, "TPC Cluster Z Error Parameterization") -AddOption(tpcTriggerHandling, bool, false, "", 0, "Enable TPC trigger handling") +AddOption(tpcTriggerHandling, bool, true, "", 0, "Enable TPC trigger handling") AddHelp("help", 'h') EndConfig() diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index e3feafa55b9cb..2e64d91b62e05 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -200,13 +200,11 @@ std::pair GPUChainTracking::TPCClusterizerDecodeZSCo if (mCFContext->zsVersion == -1) { mCFContext->zsVersion = hdr->version; if (GetProcessingSettings().param.tpcTriggerHandling && mCFContext->zsVersion < ZSVersion::ZSVersionDenseLinkBased) { - GPUError("Trigger handling only possible with TPC Dense Link Based data, received version %d", mCFContext->zsVersion); - if (GetProcessingSettings().ignoreNonFatalGPUErrors) { - mCFContext->abandonTimeframe = true; - return {0, 0}; - } else { - GPUFatal("Cannot process with invalid TPC ZS data, exiting"); + static bool errorShown = false; + if (errorShown == false) { + GPUAlarm("Trigger handling only possible with TPC Dense Link Based data, received version %d, disabling", mCFContext->zsVersion); } + errorShown = true; } } else if (mCFContext->zsVersion != (int)hdr->version) { GPUError("Received TPC ZS 8kb page of mixed versions, expected %d, received %d (linkid %d, feeCRU %d, feeEndpoint %d, feelinkid %d)", mCFContext->zsVersion, (int)hdr->version, (int)o2::raw::RDHUtils::getLinkID(*rdh), (int)rdh_utils::getCRU(*rdh), (int)rdh_utils::getEndPoint(*rdh), (int)rdh_utils::getLink(*rdh)); @@ -478,12 +476,12 @@ int GPUChainTracking::RunTPCClusterizer_prepare(bool restorePointers) mCFContext->tpcMaxTimeBin = maxAllowedTimebin; const CfFragment fragmentMax{(tpccf::TPCTime)mCFContext->tpcMaxTimeBin + 1, maxFragmentLen}; mCFContext->prepare(mIOPtrs.tpcZS, fragmentMax); + if (GetProcessingSettings().param.tpcTriggerHandling) { + mTriggerBuffer->triggers.clear(); + } if (mIOPtrs.tpcZS) { unsigned int nDigitsFragmentMax[NSLICES]; mCFContext->zsVersion = -1; - if (GetProcessingSettings().param.tpcTriggerHandling) { - mTriggerBuffer->triggers.clear(); - } for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { if (mIOPtrs.tpcZS->slice[iSlice].count[0]) { const void* rdh = mIOPtrs.tpcZS->slice[iSlice].zsPtr[0][0]; @@ -509,15 +507,6 @@ int GPUChainTracking::RunTPCClusterizer_prepare(bool restorePointers) processors()->tpcClusterer[iSlice].mPmemory->counters.nDigits = x.first; mRec->MemoryScalers()->nTPCdigits += x.first; } - if (GetProcessingSettings().param.tpcTriggerHandling) { - GPUOutputControl* triggerOutput = mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTriggerWords)]; - if (triggerOutput && triggerOutput->allocator) { - GPUInfo("Storing %lu trigger words", mTriggerBuffer->triggers.size()); - auto* outputBuffer = (decltype(mTriggerBuffer->triggers)::value_type*)triggerOutput->allocator(mTriggerBuffer->triggers.size() * sizeof(decltype(mTriggerBuffer->triggers)::value_type)); - std::copy(mTriggerBuffer->triggers.begin(), mTriggerBuffer->triggers.end(), outputBuffer); - } - mTriggerBuffer->triggers.clear(); - } for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { unsigned int nDigitsBase = nDigitsFragmentMax[iSlice]; unsigned int threshold = 40000000; @@ -541,6 +530,15 @@ int GPUChainTracking::RunTPCClusterizer_prepare(bool restorePointers) processors()->tpcClusterer[iSlice].SetNMaxDigits(nDigits, mCFContext->nPagesFragmentMax, nDigits, 0); } } + if (GetProcessingSettings().param.tpcTriggerHandling) { + GPUOutputControl* triggerOutput = mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTriggerWords)]; + if (triggerOutput && triggerOutput->allocator) { + GPUInfo("Storing %lu trigger words", mTriggerBuffer->triggers.size()); + auto* outputBuffer = (decltype(mTriggerBuffer->triggers)::value_type*)triggerOutput->allocator(mTriggerBuffer->triggers.size() * sizeof(decltype(mTriggerBuffer->triggers)::value_type)); + std::copy(mTriggerBuffer->triggers.begin(), mTriggerBuffer->triggers.end(), outputBuffer); + } + mTriggerBuffer->triggers.clear(); + } if (mIOPtrs.tpcZS) { GPUInfo("Event has %u 8kb TPC ZS pages (version %d), %lld digits", mCFContext->nPagesTotal, mCFContext->zsVersion, (long long int)mRec->MemoryScalers()->nTPCdigits); } else { diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index a1bcf05cf63c8..e7f46b3fb1bbd 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -882,6 +882,9 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) pc.outputs().snapshot({gDataOriginGPU, "ERRORQA", 0, Lifetime::Timeframe}, mErrorQA); mErrorQA.clear(); // FIXME: This is a race condition once we run multi-threaded! } + if (mSpecConfig.tpcTriggerHandling && !(mSpecConfig.zsOnTheFly || mSpecConfig.zsDecoder)) { + pc.outputs().make>(Output{gDataOriginTPC, "TRIGGERWORDS", 0, Lifetime::Timeframe}, 0u); + } mTimer->Stop(); LOG(info) << "GPU Reoncstruction time for this TF " << mTimer->CpuTime() - cput << " s (cpu), " << mTimer->RealTime() - realt << " s (wall)"; } diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 72be2394217c6..53438f749ed63 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -68,7 +68,7 @@ fi # --------------------------------------------------------------------------------------------------------------------- # Set some individual workflow arguments depending on configuration GPU_INPUT=zsraw -GPU_OUTPUT=tracks,clusters +GPU_OUTPUT=tracks,clusters,tpc-triggers GPU_CONFIG= GPU_CONFIG_KEY= TOF_CONFIG= @@ -175,7 +175,6 @@ workflow_has_parameter CALIB && [[ $CALIB_TPC_VDRIFTTGL == 1 ]] && SEND_ITSTPC_D PVERTEXING_CONFIG_KEY+="${ITSMFT_STROBES};" has_processing_step ENTROPY_ENCODER && has_detector_ctf TPC && GPU_OUTPUT+=",compressed-clusters-ctf" -[[ ${TPC_ENABLE_TRIGGER_HANDLING:-} == 1 ]] && GPU_OUTPUT+=",tpc-triggers" if [[ $SYNCMODE == 1 ]] && workflow_has_parameter QC && has_detector_qc TPC; then GPU_OUTPUT+=",qa,error-qa" From 94930f41e865f1f5e7b79741dc934e51ef348f95 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 20 Sep 2023 16:08:36 +0200 Subject: [PATCH 077/324] GPU TPC: always enable triggerHandling in tpc-reco workflow and in gpu-reco workflow if caclusterer is active --- Detectors/TPC/workflow/src/RecoWorkflow.cxx | 2 +- GPU/Workflow/src/gpu-reco-workflow.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/TPC/workflow/src/RecoWorkflow.cxx b/Detectors/TPC/workflow/src/RecoWorkflow.cxx index d409ffbf6e593..a529808978c9b 100644 --- a/Detectors/TPC/workflow/src/RecoWorkflow.cxx +++ b/Detectors/TPC/workflow/src/RecoWorkflow.cxx @@ -446,7 +446,7 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto cfg.processMC = propagateMC; cfg.sendClustersPerSector = isEnabled(OutputType::SendClustersPerSector); cfg.askDISTSTF = askDISTSTF; - cfg.tpcTriggerHandling = isEnabled(OutputType::TPCTriggers); + cfg.tpcTriggerHandling = isEnabled(OutputType::TPCTriggers) || cfg.caClusterer; Inputs ggInputs; auto ggRequest = std::make_shared(false, true, false, true, true, o2::base::GRPGeomRequest::Aligned, ggInputs, true); diff --git a/GPU/Workflow/src/gpu-reco-workflow.cxx b/GPU/Workflow/src/gpu-reco-workflow.cxx index fb8ff66683e70..9d0c481c2916d 100644 --- a/GPU/Workflow/src/gpu-reco-workflow.cxx +++ b/GPU/Workflow/src/gpu-reco-workflow.cxx @@ -171,7 +171,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) cfg.askDISTSTF = !cfgc.options().get("ignore-dist-stf"); cfg.readTRDtracklets = isEnabled(inputTypes, ioType::TRDTracklets); cfg.runTRDTracking = isEnabled(outputTypes, ioType::TRDTracks); - cfg.tpcTriggerHandling = isEnabled(outputTypes, ioType::TPCTriggers); + cfg.tpcTriggerHandling = isEnabled(outputTypes, ioType::TPCTriggers) || cfg.caClusterer; Inputs ggInputs; auto ggRequest = std::make_shared(false, true, false, true, true, o2::base::GRPGeomRequest::Aligned, ggInputs, true); From 4a8cbc37fb455ffc16e25ad765d9e3cb419ebc12 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 28 Aug 2020 17:37:01 +0200 Subject: [PATCH 078/324] GPU: Use double-pipeline within DPL --- GPU/GPUTracking/Interface/GPUO2Interface.cxx | 153 ++++++++++-------- GPU/GPUTracking/Interface/GPUO2Interface.h | 33 ++-- .../include/GPUWorkflow/GPUWorkflowSpec.h | 4 +- GPU/Workflow/src/GPUWorkflowSpec.cxx | 63 ++++---- 4 files changed, 147 insertions(+), 106 deletions(-) diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index 62d84bc2d9058..1258189737651 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -26,6 +26,9 @@ #include "CalibdEdxContainer.h" #include #include +#include +#include +#include using namespace o2::gpu; @@ -37,59 +40,81 @@ GPUO2Interface::~GPUO2Interface() { Deinitialize(); } int GPUO2Interface::Initialize(const GPUO2InterfaceConfiguration& config) { - if (mInitialized) { + if (mNContexts) { return (1); } mConfig.reset(new GPUO2InterfaceConfiguration(config)); - mContinuous = mConfig->configGRP.continuousMaxTimeBin != 0; - mRec.reset(GPUReconstruction::CreateInstance(mConfig->configDeviceBackend)); - if (mRec == nullptr) { - GPUError("Error obtaining instance of GPUReconstruction"); - return 1; - } - mChain = mRec->AddChain(mConfig->configInterface.maxTPCHits, mConfig->configInterface.maxTRDTracklets); - mChain->mConfigDisplay = &mConfig->configDisplay; - mChain->mConfigQA = &mConfig->configQA; + mNContexts = mConfig->configProcessing.doublePipeline ? 2 : 1; + mCtx.reset(new GPUO2Interface::processingContext[mNContexts]); if (mConfig->configWorkflow.inputs.isSet(GPUDataTypes::InOutType::TPCRaw)) { mConfig->configGRP.needsClusterer = 1; } if (mConfig->configWorkflow.inputs.isSet(GPUDataTypes::InOutType::TPCCompressedClusters)) { mConfig->configGRP.doCompClusterDecode = 1; } - mRec->SetSettings(&mConfig->configGRP, &mConfig->configReconstruction, &mConfig->configProcessing, &mConfig->configWorkflow); - mChain->SetCalibObjects(mConfig->configCalib); - - if (mConfig->configWorkflow.steps.isSet(GPUDataTypes::RecoStep::ITSTracking)) { - mChainITS = mRec->AddChain(); - } + for (unsigned int i = 0; i < mNContexts; i++) { + if (i) { + mConfig->configDeviceBackend.master = mCtx[0].mRec.get(); + } + mCtx[i].mRec.reset(GPUReconstruction::CreateInstance(mConfig->configDeviceBackend)); + mConfig->configDeviceBackend.master = nullptr; + if (mCtx[i].mRec == nullptr) { + GPUError("Error obtaining instance of GPUReconstruction"); + mNContexts = 0; + mCtx.reset(nullptr); + return 1; + } + mCtx[i].mChain = mCtx[i].mRec->AddChain(mConfig->configInterface.maxTPCHits, mConfig->configInterface.maxTRDTracklets); + mCtx[i].mChain->mConfigDisplay = &mConfig->configDisplay; + mCtx[i].mChain->mConfigQA = &mConfig->configQA; + mCtx[i].mRec->SetSettings(&mConfig->configGRP, &mConfig->configReconstruction, &mConfig->configProcessing, &mConfig->configWorkflow); + mCtx[i].mChain->SetCalibObjects(mConfig->configCalib); + + if (i == 0 && mConfig->configWorkflow.steps.isSet(GPUDataTypes::RecoStep::ITSTracking)) { + mChainITS = mCtx[i].mRec->AddChain(); + } - mOutputRegions.reset(new GPUTrackingOutputs); - if (mConfig->configInterface.outputToExternalBuffers) { - for (unsigned int i = 0; i < mOutputRegions->count(); i++) { - mChain->SetSubOutputControl(i, &mOutputRegions->asArray()[i]); + mCtx[i].mOutputRegions.reset(new GPUTrackingOutputs); + if (mConfig->configInterface.outputToExternalBuffers) { + for (unsigned int j = 0; j < mCtx[i].mOutputRegions->count(); j++) { + mCtx[i].mChain->SetSubOutputControl(j, &mCtx[i].mOutputRegions->asArray()[j]); + } + GPUOutputControl dummy; + dummy.set([](size_t size) -> void* {throw std::runtime_error("invalid output memory request, no common output buffer set"); return nullptr; }); + mCtx[i].mRec->SetOutputControl(dummy); } - GPUOutputControl dummy; - dummy.set([](size_t size) -> void* {throw std::runtime_error("invalid output memory request, no common output buffer set"); return nullptr; }); - mRec->SetOutputControl(dummy); - } - if (mRec->Init()) { - return (1); + if (i == 0 && mCtx[i].mRec->Init()) { + mNContexts = 0; + mCtx.reset(nullptr); + return (1); + } + if (!mCtx[i].mRec->IsGPU() && mCtx[i].mRec->GetProcessingSettings().memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_INDIVIDUAL) { + mCtx[i].mRec->MemoryScalers()->factor *= 2; + } } - if (!mRec->IsGPU() && mRec->GetProcessingSettings().memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_INDIVIDUAL) { - mRec->MemoryScalers()->factor *= 2; + if (mConfig->configProcessing.doublePipeline) { + mPipelineThread.reset(new std::thread([this]() { mCtx[0].mRec->RunPipelineWorker(); })); } - mInitialized = true; return (0); } void GPUO2Interface::Deinitialize() { - if (mInitialized) { - mRec->Finalize(); - mRec.reset(); + if (mNContexts) { + if (mConfig->configProcessing.doublePipeline) { + mCtx[0].mRec->TerminatePipelineWorker(); + mPipelineThread->join(); + } + for (unsigned int i = 0; i < mNContexts; i++) { + mCtx[i].mRec->Finalize(); + } + mCtx[0].mRec->Exit(); + for (int i = mNContexts - 1; i >= 0; i--) { + mCtx[i].mRec.reset(); + } } - mInitialized = false; + mNContexts = 0; } void GPUO2Interface::DumpEvent(int nEvent, GPUTrackingInOutPointers* data) @@ -97,17 +122,17 @@ void GPUO2Interface::DumpEvent(int nEvent, GPUTrackingInOutPointers* data) if (mConfig->configProcessing.doublePipeline) { throw std::runtime_error("Cannot dump events in double pipeline mode"); } - mChain->ClearIOPointers(); - mChain->mIOPtrs = *data; + mCtx[0].mChain->ClearIOPointers(); + mCtx[0].mChain->mIOPtrs = *data; char fname[1024]; snprintf(fname, 1024, "event.%d.dump", nEvent); - mChain->DumpData(fname); + mCtx[0].mChain->DumpData(fname); if (nEvent == 0) { #ifdef GPUCA_BUILD_QA if (mConfig->configProcessing.runMC) { - mChain->ForceInitQA(); + mCtx[0].mChain->ForceInitQA(); snprintf(fname, 1024, "mc.%d.dump", nEvent); - mChain->GetQA()->DumpO2MCData(fname); + mCtx[0].mChain->GetQA()->DumpO2MCData(fname); } #endif } @@ -118,61 +143,55 @@ void GPUO2Interface::DumpSettings() if (mConfig->configProcessing.doublePipeline) { throw std::runtime_error("Cannot dump events in double pipeline mode"); } - mChain->DoQueuedCalibUpdates(-1); - mRec->DumpSettings(); + mCtx[0].mChain->DoQueuedCalibUpdates(-1); + mCtx[0].mRec->DumpSettings(); } -int GPUO2Interface::RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs) +int GPUO2Interface::RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs, unsigned int iThread) { - if (!mInitialized) { + if (mNContexts <= iThread) { return (1); } - mChain->mIOPtrs = *data; + mCtx[iThread].mChain->mIOPtrs = *data; if (mConfig->configInterface.outputToExternalBuffers) { - for (unsigned int i = 0; i < mOutputRegions->count(); i++) { + for (unsigned int i = 0; i < mCtx[iThread].mOutputRegions->count(); i++) { if (outputs->asArray()[i].allocator) { - mOutputRegions->asArray()[i].set(outputs->asArray()[i].allocator); + mCtx[iThread].mOutputRegions->asArray()[i].set(outputs->asArray()[i].allocator); } else if (outputs->asArray()[i].ptrBase) { - mOutputRegions->asArray()[i].set(outputs->asArray()[i].ptrBase, outputs->asArray()[i].size); + mCtx[iThread].mOutputRegions->asArray()[i].set(outputs->asArray()[i].ptrBase, outputs->asArray()[i].size); } else { - mOutputRegions->asArray()[i].reset(); + mCtx[iThread].mOutputRegions->asArray()[i].reset(); } } } - int retVal = mRec->RunChains(); + int retVal = mCtx[iThread].mRec->RunChains(); if (retVal == 2) { retVal = 0; // 2 signals end of event display, ignore } - if (mConfig->configQA.shipToQC && mChain->QARanForTF()) { - outputs->qa.hist1 = &mChain->GetQA()->getHistograms1D(); - outputs->qa.hist2 = &mChain->GetQA()->getHistograms2D(); - outputs->qa.hist3 = &mChain->GetQA()->getHistograms1Dd(); - outputs->qa.hist4 = &mChain->GetQA()->getGraphs(); + if (mConfig->configQA.shipToQC && mCtx[iThread].mChain->QARanForTF()) { + outputs->qa.hist1 = &mCtx[iThread].mChain->GetQA()->getHistograms1D(); + outputs->qa.hist2 = &mCtx[iThread].mChain->GetQA()->getHistograms2D(); + outputs->qa.hist3 = &mCtx[iThread].mChain->GetQA()->getHistograms1Dd(); + outputs->qa.hist4 = &mCtx[iThread].mChain->GetQA()->getGraphs(); outputs->qa.newQAHistsCreated = true; } - *data = mChain->mIOPtrs; + *data = mCtx[iThread].mChain->mIOPtrs; return retVal; } -void GPUO2Interface::Clear(bool clearOutputs) { mRec->ClearAllocatedMemory(clearOutputs); } - -void GPUO2Interface::GetClusterErrors2(int row, float z, float sinPhi, float DzDs, short clusterState, float& ErrY2, float& ErrZ2) const -{ - mRec->GetParam().GetClusterErrors2(row, z, sinPhi, DzDs, ErrY2, ErrZ2); - mRec->GetParam().UpdateClusterError2ByState(clusterState, ErrY2, ErrZ2); -} +void GPUO2Interface::Clear(bool clearOutputs, unsigned int iThread) { mCtx[iThread].mRec->ClearAllocatedMemory(clearOutputs); } int GPUO2Interface::registerMemoryForGPU(const void* ptr, size_t size) { - return mRec->registerMemoryForGPU(ptr, size); + return mCtx[0].mRec->registerMemoryForGPU(ptr, size); } int GPUO2Interface::unregisterMemoryForGPU(const void* ptr) { - return mRec->unregisterMemoryForGPU(ptr); + return mCtx[0].mRec->unregisterMemoryForGPU(ptr); } std::unique_ptr GPUO2Interface::getPadGainCalibDefault() @@ -190,15 +209,17 @@ std::unique_ptr GPUO2Interface::getCalibdEdxContain return std::make_unique(); } -int GPUO2Interface::UpdateCalibration(const GPUCalibObjectsConst& newCalib, const GPUNewCalibValues& newVals) +int GPUO2Interface::UpdateCalibration(const GPUCalibObjectsConst& newCalib, const GPUNewCalibValues& newVals, unsigned int iThread) { - mChain->SetUpdateCalibObjects(newCalib, newVals); + mCtx[iThread].mChain->SetUpdateCalibObjects(newCalib, newVals); return 0; } void GPUO2Interface::setErrorCodeOutput(std::vector>* v) { - mRec->setErrorCodeOutput(v); + for (unsigned int i = 0; i < mNContexts; i++) { + mCtx[i].mRec->setErrorCodeOutput(v); + } } void GPUO2Interface::GetITSTraits(o2::its::TrackerTraits*& trackerTraits, o2::its::VertexerTraits*& vertexerTraits, o2::its::TimeFrame*& timeFrame) diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.h b/GPU/GPUTracking/Interface/GPUO2Interface.h index 8a4e10033641d..f4794f3b34d22 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.h +++ b/GPU/GPUTracking/Interface/GPUO2Interface.h @@ -31,6 +31,12 @@ #include #include "GPUCommonDef.h" #include "GPUDataTypes.h" + +namespace std +{ +class thread; +} // namespace std + namespace o2::tpc { struct ClusterNativeAccess; @@ -66,18 +72,15 @@ class GPUO2Interface int Initialize(const GPUO2InterfaceConfiguration& config); void Deinitialize(); - int RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs = nullptr); - void Clear(bool clearOutputs); + int RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs = nullptr, unsigned int iThread = 0); + void Clear(bool clearOutputs, unsigned int iThread = 0); void DumpEvent(int nEvent, GPUTrackingInOutPointers* data); void DumpSettings(); void GetITSTraits(o2::its::TrackerTraits*& trackerTraits, o2::its::VertexerTraits*& vertexerTraits, o2::its::TimeFrame*& timeFrame); // Updates all calibration objects that are != nullptr in newCalib - int UpdateCalibration(const GPUCalibObjectsConst& newCalib, const GPUNewCalibValues& newVals); - - bool GetParamContinuous() { return (mContinuous); } - void GetClusterErrors2(int row, float z, float sinPhi, float DzDs, short clusterState, float& ErrY2, float& ErrZ2) const; + int UpdateCalibration(const GPUCalibObjectsConst& newCalib, const GPUNewCalibValues& newVals, unsigned int iThread = 0); static std::unique_ptr getPadGainCalibDefault(); static std::unique_ptr getPadGainCalib(const o2::tpc::CalDet& in); @@ -90,18 +93,24 @@ class GPUO2Interface const GPUO2InterfaceConfiguration& getConfig() const { return *mConfig; } + struct processingContext { + std::unique_ptr mRec; + GPUChainTracking* mChain = nullptr; + std::unique_ptr mOutputRegions; + }; + private: GPUO2Interface(const GPUO2Interface&); GPUO2Interface& operator=(const GPUO2Interface&); - bool mInitialized = false; bool mContinuous = false; - std::unique_ptr mRec; //! - GPUChainTracking* mChain = nullptr; //! - GPUChainITS* mChainITS = nullptr; //! - std::unique_ptr mConfig; //! - std::unique_ptr mOutputRegions; //! + unsigned int mNContexts = 0; + std::unique_ptr mCtx; + + std::unique_ptr mConfig; + GPUChainITS* mChainITS = nullptr; + std::unique_ptr mPipelineThread; }; } // namespace o2::gpu diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index 00fa295698ec1..b0893db6a9431 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -27,6 +27,7 @@ #include #include #include +#include class TStopwatch; namespace o2 @@ -138,7 +139,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task /// storing the new calib objects by overwritting the old calibs void cleanOldCalibsTPCPtrs(); - void doCalibUpdates(o2::framework::ProcessingContext& pc); + void doCalibUpdates(o2::framework::ProcessingContext& pc, unsigned int threadIndex); void doTrackTuneTPC(GPUTrackingInOutPointers& ptrs, char* buffout); @@ -175,6 +176,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task std::vector mTPCSectors; std::unique_ptr mITSTracker; std::unique_ptr mITSVertexer; + std::mutex mMutexDecodeInput; o2::its::TimeFrame* mITSTimeFrame = nullptr; const o2::itsmft::TopologyDictionary* mITSDict = nullptr; const o2::dataformats::MeanVertexObject* mMeanVertex; diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index e7f46b3fb1bbd..4bf0b3ca6f58c 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -72,8 +72,21 @@ #include "ITSBase/GeometryTGeo.h" #include "CommonUtils/VerbosityConfig.h" #include "CommonUtils/DebugStreamer.h" +#include "GPUReconstructionConvert.h" +#include "DetectorsRaw/RDHUtils.h" +#include "ITStracking/Tracker.h" +#include "ITStracking/Vertexer.h" +// #include "Framework/ThreadPool.h" + +#include +#include +#include +#include +#include +#include + #include -#include // for make_shared +#include #include #include #include @@ -82,16 +95,6 @@ #include #include #include -#include "GPUReconstructionConvert.h" -#include "DetectorsRaw/RDHUtils.h" -#include -#include -#include -#include -#include -#include -#include "ITStracking/Tracker.h" -#include "ITStracking/Vertexer.h" using namespace o2::framework; using namespace o2::header; @@ -224,6 +227,9 @@ void GPURecoWorkflowSpec::init(InitContext& ic) << "Instead, link the corresponding file as /TPC/Calib/CorrectionMap/snapshot.root and use it via\n" << "--condition-remap file://=TPC/Calib/CorrectionMap option"; } + if (config.configProcessing.doublePipeline && ic.services().get().poolSize != 2) { + throw std::runtime_error("double pipeline requires exactly 2 threads"); + } // initialize TPC calib objects initFunctionTPCCalib(ic); @@ -471,11 +477,6 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) mTimer->Start(false); mNTFs++; - GRPGeomHelper::instance().checkUpdates(pc); - if (GRPGeomHelper::instance().getGRPECS()->isDetReadOut(o2::detectors::DetID::TPC) && mConfParam->tpcTriggeredMode ^ !GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::TPC)) { - LOG(fatal) << "configKeyValue tpcTriggeredMode does not match GRP isDetContinuousReadOut(TPC) setting"; - } - std::vector> inputs; const o2::tpc::CompressedClustersFlat* pCompClustersFlat = nullptr; @@ -504,6 +505,15 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) getWorkflowTPCInput_digits = true; } + auto lockDecodeInput = std::make_unique>(mMutexDecodeInput); + // int threadIndex = pc.services().get().threadIndex; + int threadIndex = 0; + + GRPGeomHelper::instance().checkUpdates(pc); + if (GRPGeomHelper::instance().getGRPECS()->isDetReadOut(o2::detectors::DetID::TPC) && mConfParam->tpcTriggeredMode ^ !GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::TPC)) { + LOG(fatal) << "configKeyValue tpcTriggeredMode does not match GRP isDetContinuousReadOut(TPC) setting"; + } + processInputs(pc, tpcZSmetaPointers, tpcZSmetaPointers2, tpcZSmetaSizes, tpcZSmetaSizes2, inputZS, tpcZS, tpcZSonTheFlySizes, debugTFDump, compClustersDummy, compClustersFlatDummy, pCompClustersFlat, tmpEmptyCompClusters); // Process non-digit / non-cluster inputs const auto& inputsClustersDigits = o2::tpc::getWorkflowTPCInput(pc, mVerbosity, getWorkflowTPCInput_mc, getWorkflowTPCInput_clusters, mTPCSectorMask, getWorkflowTPCInput_digits); // Process digit and cluster inputs GPUTrackingInOutPointers ptrs; @@ -686,7 +696,9 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) const auto& holdData = o2::tpc::TPCTrackingDigitsPreCheck::runPrecheck(&ptrs, mConfig.get()); - doCalibUpdates(pc); + doCalibUpdates(pc, threadIndex); + + lockDecodeInput.reset(); if (mConfParam->dump) { if (mNTFs == 1) { @@ -702,7 +714,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) int retVal = 0; if (mConfParam->dump < 2) { - retVal = mTracker->RunTracking(&ptrs, &outputRegions); + retVal = mTracker->RunTracking(&ptrs, &outputRegions, threadIndex); if (retVal != 0) { debugTFDump = true; } @@ -712,13 +724,10 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) } } - // flushing debug output to file - o2::utils::DebugStreamer::instance()->flush(); - - // setting TPC calibration objects - cleanOldCalibsTPCPtrs(); - - mTracker->Clear(false); + o2::utils::DebugStreamer::instance()->flush(); // flushing debug output to file + cleanOldCalibsTPCPtrs(); // setting TPC calibration objects + // if (!mTrackingCAO2Interface->getConfig().configInterface.outputToExternalBuffers) // TODO: Why was this needed for double-pipeline? + mTracker->Clear(false, threadIndex); // clean non-output memory used by GPU Reconstruction if (debugTFDump && mNDebugDumps < mConfParam->dumpBadTFs) { mNDebugDumps++; @@ -889,7 +898,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) LOG(info) << "GPU Reoncstruction time for this TF " << mTimer->CpuTime() - cput << " s (cpu), " << mTimer->RealTime() - realt << " s (wall)"; } -void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc) +void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc, unsigned int threadIndex) { GPUCalibObjectsConst newCalibObjects; GPUNewCalibValues newCalibValues; @@ -947,7 +956,7 @@ void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc) } if (needCalibUpdate) { LOG(info) << "Updating GPUReconstruction calibration objects"; - mTracker->UpdateCalibration(newCalibObjects, newCalibValues); + mTracker->UpdateCalibration(newCalibObjects, newCalibValues, threadIndex); } } From 4d5aea81fa2bff63835779bc3a8c9392550240e3 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Tue, 19 Sep 2023 16:26:36 +0200 Subject: [PATCH 079/324] GPU Workflow: Workaround for multi-threaded pipeline step 1: alternate between pipeline contexts --- GPU/GPUTracking/Interface/GPUO2Interface.cxx | 25 +++++++++++++++---- GPU/GPUTracking/Interface/GPUO2Interface.h | 18 ++++--------- .../include/GPUWorkflow/GPUWorkflowSpec.h | 3 ++- GPU/Workflow/src/GPUWorkflowSpec.cxx | 18 ++++++++----- 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index 1258189737651..684bf658a73e6 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -34,7 +34,20 @@ using namespace o2::gpu; #include "DataFormatsTPC/ClusterNative.h" -GPUO2Interface::GPUO2Interface() = default; +namespace o2::gpu +{ +struct GPUO2Interface_processingContext { + std::unique_ptr mRec; + GPUChainTracking* mChain = nullptr; + std::unique_ptr mOutputRegions; +}; + +struct GPUO2Interface_Internals { + std::unique_ptr pipelineThread; +}; +} // namespace o2::gpu + +GPUO2Interface::GPUO2Interface() : mInternals(new GPUO2Interface_Internals){}; GPUO2Interface::~GPUO2Interface() { Deinitialize(); } @@ -45,7 +58,7 @@ int GPUO2Interface::Initialize(const GPUO2InterfaceConfiguration& config) } mConfig.reset(new GPUO2InterfaceConfiguration(config)); mNContexts = mConfig->configProcessing.doublePipeline ? 2 : 1; - mCtx.reset(new GPUO2Interface::processingContext[mNContexts]); + mCtx.reset(new GPUO2Interface_processingContext[mNContexts]); if (mConfig->configWorkflow.inputs.isSet(GPUDataTypes::InOutType::TPCRaw)) { mConfig->configGRP.needsClusterer = 1; } @@ -94,7 +107,7 @@ int GPUO2Interface::Initialize(const GPUO2InterfaceConfiguration& config) } } if (mConfig->configProcessing.doublePipeline) { - mPipelineThread.reset(new std::thread([this]() { mCtx[0].mRec->RunPipelineWorker(); })); + mInternals->pipelineThread.reset(new std::thread([this]() { mCtx[0].mRec->RunPipelineWorker(); })); } return (0); } @@ -104,7 +117,7 @@ void GPUO2Interface::Deinitialize() if (mNContexts) { if (mConfig->configProcessing.doublePipeline) { mCtx[0].mRec->TerminatePipelineWorker(); - mPipelineThread->join(); + mInternals->pipelineThread->join(); } for (unsigned int i = 0; i < mNContexts; i++) { mCtx[i].mRec->Finalize(); @@ -211,7 +224,9 @@ std::unique_ptr GPUO2Interface::getCalibdEdxContain int GPUO2Interface::UpdateCalibration(const GPUCalibObjectsConst& newCalib, const GPUNewCalibValues& newVals, unsigned int iThread) { - mCtx[iThread].mChain->SetUpdateCalibObjects(newCalib, newVals); + for (unsigned int i = 0; i < mNContexts; i++) { + mCtx[i].mChain->SetUpdateCalibObjects(newCalib, newVals); + } return 0; } diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.h b/GPU/GPUTracking/Interface/GPUO2Interface.h index f4794f3b34d22..fe3c6d4c11586 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.h +++ b/GPU/GPUTracking/Interface/GPUO2Interface.h @@ -32,11 +32,6 @@ #include "GPUCommonDef.h" #include "GPUDataTypes.h" -namespace std -{ -class thread; -} // namespace std - namespace o2::tpc { struct ClusterNativeAccess; @@ -63,6 +58,9 @@ struct GPUTrackingOutputs; struct GPUConstantMem; struct GPUNewCalibValues; +struct GPUO2Interface_processingContext; +struct GPUO2Interface_Internals; + class GPUO2Interface { public: @@ -93,12 +91,6 @@ class GPUO2Interface const GPUO2InterfaceConfiguration& getConfig() const { return *mConfig; } - struct processingContext { - std::unique_ptr mRec; - GPUChainTracking* mChain = nullptr; - std::unique_ptr mOutputRegions; - }; - private: GPUO2Interface(const GPUO2Interface&); GPUO2Interface& operator=(const GPUO2Interface&); @@ -106,11 +98,11 @@ class GPUO2Interface bool mContinuous = false; unsigned int mNContexts = 0; - std::unique_ptr mCtx; + std::unique_ptr mCtx; std::unique_ptr mConfig; GPUChainITS* mChainITS = nullptr; - std::unique_ptr mPipelineThread; + std::unique_ptr mInternals; }; } // namespace o2::gpu diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index b0893db6a9431..347dc82eb9f06 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -139,7 +139,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task /// storing the new calib objects by overwritting the old calibs void cleanOldCalibsTPCPtrs(); - void doCalibUpdates(o2::framework::ProcessingContext& pc, unsigned int threadIndex); + void doCalibUpdates(o2::framework::ProcessingContext& pc); void doTrackTuneTPC(GPUTrackingInOutPointers& ptrs, char* buffout); @@ -184,6 +184,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task int mVerbosity = 0; unsigned int mNTFs = 0; unsigned int mNDebugDumps = 0; + unsigned int mNextThreadIndex = 0; bool mUpdateGainMapCCDB = true; std::unique_ptr mTFSettings; Config mSpecConfig; diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 4bf0b3ca6f58c..35a5ba77dacd1 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -227,8 +227,11 @@ void GPURecoWorkflowSpec::init(InitContext& ic) << "Instead, link the corresponding file as /TPC/Calib/CorrectionMap/snapshot.root and use it via\n" << "--condition-remap file://=TPC/Calib/CorrectionMap option"; } - if (config.configProcessing.doublePipeline && ic.services().get().poolSize != 2) { + /* if (config.configProcessing.doublePipeline && ic.services().get().poolSize != 2) { throw std::runtime_error("double pipeline requires exactly 2 threads"); + } */ + if (config.configProcessing.doublePipeline && (mSpecConfig.readTRDtracklets || mSpecConfig.runITSTracking || !(mSpecConfig.zsOnTheFly || mSpecConfig.zsDecoder))) { + LOG(fatal) << "GPU two-threaded pipeline works only with TPC-only processing, and with ZS input"; } // initialize TPC calib objects @@ -506,8 +509,11 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) } auto lockDecodeInput = std::make_unique>(mMutexDecodeInput); - // int threadIndex = pc.services().get().threadIndex; - int threadIndex = 0; + // unsigned int threadIndex = pc.services().get().threadIndex; + unsigned int threadIndex = mNextThreadIndex; + if (mConfig->configProcessing.doublePipeline) { + mNextThreadIndex = (mNextThreadIndex + 1) % 2; + } GRPGeomHelper::instance().checkUpdates(pc); if (GRPGeomHelper::instance().getGRPECS()->isDetReadOut(o2::detectors::DetID::TPC) && mConfParam->tpcTriggeredMode ^ !GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::TPC)) { @@ -696,7 +702,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) const auto& holdData = o2::tpc::TPCTrackingDigitsPreCheck::runPrecheck(&ptrs, mConfig.get()); - doCalibUpdates(pc, threadIndex); + doCalibUpdates(pc); lockDecodeInput.reset(); @@ -898,7 +904,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) LOG(info) << "GPU Reoncstruction time for this TF " << mTimer->CpuTime() - cput << " s (cpu), " << mTimer->RealTime() - realt << " s (wall)"; } -void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc, unsigned int threadIndex) +void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc) { GPUCalibObjectsConst newCalibObjects; GPUNewCalibValues newCalibValues; @@ -956,7 +962,7 @@ void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc, u } if (needCalibUpdate) { LOG(info) << "Updating GPUReconstruction calibration objects"; - mTracker->UpdateCalibration(newCalibObjects, newCalibValues, threadIndex); + mTracker->UpdateCalibration(newCalibObjects, newCalibValues); } } From 5c1f7f3f27587d97058f23d619b3922bf367f978 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 21 Sep 2023 09:07:20 +0200 Subject: [PATCH 080/324] DPL: inject missing data (#11925) --- .../Framework/ExternalFairMQDeviceProxy.h | 4 +- .../Core/src/ExternalFairMQDeviceProxy.cxx | 135 ++++++++++++++++-- Framework/Utils/src/raw-proxy.cxx | 7 +- 3 files changed, 129 insertions(+), 17 deletions(-) diff --git a/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h b/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h index 916d1738bf5d0..b69b388150b4f 100644 --- a/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h +++ b/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h @@ -105,7 +105,9 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* label, const char* defaultChannelConfig, InjectorFunction converter, uint64_t minSHM = 0, - bool sendTFcounter = false); + bool sendTFcounter = false, + bool doInjectMissingData = false + ); DataProcessorSpec specifyFairMQDeviceOutputProxy(char const* label, Inputs const& inputSpecs, diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 941cd8873d438..3a3d1162b2a4a 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -214,6 +214,118 @@ InjectorFunction o2DataModelAdaptor(OutputSpec const& spec, uint64_t startTime, }; } +auto getFinalIndex(DataHeader const& dh, size_t msgidx) -> size_t +{ + size_t finalBlockIndex = 0; + if (dh.splitPayloadParts > 0 && dh.splitPayloadParts == dh.splitPayloadIndex) { + // this is indicating a sequence of payloads following the header + // FIXME: we will probably also set the DataHeader version + // Current position + number of parts + 1 (for the header) + finalBlockIndex = msgidx + dh.splitPayloadParts + 1; + } else { + // We can consider the next splitPayloadParts as one block of messages pairs + // because we are guaranteed they are all the same. + // If splitPayloadParts = 0, we assume that means there is only one (header, payload) + // pair. + finalBlockIndex = msgidx + (dh.splitPayloadParts > 0 ? dh.splitPayloadParts : 1) * 2; + } + assert(finalBlockIndex >= msgidx + 2); + return finalBlockIndex; +}; + +void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::vector const& routes) +{ + // Check for missing data. + static std::vector present; + present.clear(); + present.resize(routes.size(), false); + static std::vector unmatchedDescriptions; + unmatchedDescriptions.clear(); + bool allFound = true; + DataProcessingHeader const* dph = nullptr; + for (int msgidx = 0; msgidx < parts.Size(); msgidx += 2) { + const auto dh = o2::header::get(parts.At(msgidx)->GetData()); + auto const sih = o2::header::get(parts.At(msgidx)->GetData()); + if (sih != nullptr) { + continue; + } + for (size_t pi = 0; pi < present.size(); ++pi) { + if (present[pi]) { + continue; + } + auto& spec = routes[pi].matcher; + if (parts.At(msgidx).get() == nullptr) { + LOG(error) << "unexpected nullptr found. Skipping message pair."; + continue; + } + // Copy the DataProcessingHeader from the first message. + if (dph == nullptr) { + dph = o2::header::get(parts.At(msgidx)->GetData()); + } + if (!dh) { + LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataHeader missing"; + if (msgidx > 0) { + --msgidx; + } + continue; + } + OutputSpec query{dh->dataOrigin, dh->dataDescription, dh->subSpecification}; + if (DataSpecUtils::match(spec, query)) { + present[pi] = true; + break; + } + } + // Skip the rest of the block of messages. We subtract 2 because above + // we increment by 2. + msgidx = getFinalIndex(*dh, msgidx) - 2; + if (allFound) { + break; + } + } + for (size_t pi = 0; pi < present.size(); ++pi) { + if (!present[pi]) { + unmatchedDescriptions.push_back(pi); + } + } + + if (unmatchedDescriptions.size() > 0) { + LOGP(info, "Found {}/{} data specs", present.size() - unmatchedDescriptions.size(), present.size()); + std::string missing = ""; + for (auto mi : unmatchedDescriptions) { + if (dph == nullptr) { + // This can happen for non DPL messages in input, + // like it happens for some tests. + LOG(debug) << "DataProcessingHeader not found. Skipping message pair."; + continue; + } + auto& spec = routes[mi].matcher; + missing += "\n " + DataSpecUtils::describe(spec); + // If we have a ConcreteDataMatcher, we can create a message with the correct header. + // If we have a ConcreteDataTypeMatcher, we use 0xdeadbeef as subSpecification. + ConcreteDataTypeMatcher concrete = DataSpecUtils::asConcreteDataTypeMatcher(spec); + auto subSpec = DataSpecUtils::getOptionalSubSpec(spec); + if (subSpec == std::nullopt) { + *subSpec = 0xdeadbeef; + } + o2::header::DataHeader dh; + dh.dataOrigin = concrete.origin; + dh.dataDescription = concrete.description; + dh.subSpecification = *subSpec; + dh.payloadSize = 0; + dh.payloadSerializationMethod = header::gSerializationMethodNone; + + auto& channelName = routes[mi].channel; + auto& channelInfo = device.GetChannel(channelName); + auto channelAlloc = o2::pmr::getTransportAllocator(channelInfo.Transport()); + auto headerMessage = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, *dph}); + parts.AddPart(std::move(headerMessage)); + // add empty payload message + parts.AddPart(device.NewMessageFor(channelName, 0, 0)); + } + LOGP(error, "Missing data specs: {}", missing); + } +} + InjectorFunction dplModelAdaptor(std::vector const& filterSpecs, DPLModelAdapterConfig config) { bool throwOnUnmatchedInputs = config.throwOnUnmatchedInputs; @@ -317,18 +429,7 @@ InjectorFunction dplModelAdaptor(std::vector const& filterSpecs, DPL break; } } - if (dh->splitPayloadParts > 0 && dh->splitPayloadParts == dh->splitPayloadIndex) { - // this is indicating a sequence of payloads following the header - // FIXME: we will probably also set the DataHeader version - finalBlockIndex = msgidx + dh->splitPayloadParts + 1; - } else { - // We can consider the next splitPayloadParts as one block of messages pairs - // because we are guaranteed they are all the same. - // If splitPayloadParts = 0, we assume that means there is only one (header, payload) - // pair. - finalBlockIndex = msgidx + (dh->splitPayloadParts > 0 ? dh->splitPayloadParts : 1) * 2; - } - assert(finalBlockIndex >= msgidx + 2); + finalBlockIndex = getFinalIndex(*dh, msgidx); if (finalBlockIndex > parts.Size()) { // TODO error handling // LOGP(error, "DataHeader::splitPayloadParts invalid"); @@ -429,7 +530,8 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, char const* defaultChannelConfig, InjectorFunction converter, uint64_t minSHM, - bool sendTFcounter) + bool sendTFcounter, + bool doInjectMissingData) { DataProcessorSpec spec; spec.name = strdup(name); @@ -441,7 +543,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, // The Init method will register a new "Out of band" channel and // attach an OnData to it which is responsible for converting incoming // messages into DPL messages. - spec.algorithm = AlgorithmSpec{[converter, minSHM, deviceName = spec.name, sendTFcounter](InitContext& ctx) { + spec.algorithm = AlgorithmSpec{[converter, minSHM, deviceName = spec.name, sendTFcounter, doInjectMissingData](InitContext& ctx) { auto* device = ctx.services().get().device(); // make a copy of the output routes and pass to the lambda by move auto outputRoutes = ctx.services().get().spec().outputs; @@ -565,7 +667,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, return count; }; - auto dataHandler = [device, converter, + auto dataHandler = [device, converter, doInjectMissingData, outputRoutes = std::move(outputRoutes), control = &ctx.services().get(), deviceState = &ctx.services().get(), @@ -595,6 +697,9 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, } // For reference, the oldest possible timeframe passed as newTimesliceId here comes from LifetimeHelpers::enumDrivenCreation() bool shouldstop = false; + if (doInjectMissingData) { + injectMissingData(*device, inputs, outputRoutes); + } converter(timingInfo, *device, inputs, channelRetriever, timesliceIndex->getOldestPossibleOutput().timeslice.value, shouldstop); // If we have enough EoS messages, we can stop the device diff --git a/Framework/Utils/src/raw-proxy.cxx b/Framework/Utils/src/raw-proxy.cxx index d518863bb66fe..f85323ba0d321 100644 --- a/Framework/Utils/src/raw-proxy.cxx +++ b/Framework/Utils/src/raw-proxy.cxx @@ -31,6 +31,10 @@ void customize(std::vector& workflowOptions) ConfigParamSpec{ "dataspec", VariantType::String, "A:FLP/RAWDATA;B:FLP/DISTSUBTIMEFRAME/0", {"selection string for the data to be proxied"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "inject-missing-data", VariantType::Bool, false, {"inject missing data according to dataspec if not found in the input"}}); + workflowOptions.push_back( ConfigParamSpec{ "throwOnUnmatched", VariantType::Bool, false, {"throw if unmatched input data is found"}}); @@ -46,6 +50,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) { std::string processorName = config.options().get("proxy-name"); std::string outputconfig = config.options().get("dataspec"); + bool injectMissingData = config.options().get("inject-missing-data"); bool throwOnUnmatched = config.options().get("throwOnUnmatched"); uint64_t minSHM = std::stoul(config.options().get("timeframes-shm-limit")); std::vector matchers = select(outputconfig.c_str()); @@ -60,7 +65,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) processorName.c_str(), std::move(readoutProxyOutput), "type=pair,method=connect,address=ipc:///tmp/readout-pipe-0,rateLogging=1,transport=shmem", - dplModelAdaptor(filterSpecs, throwOnUnmatched), minSHM); + dplModelAdaptor(filterSpecs, throwOnUnmatched), minSHM, false, injectMissingData); WorkflowSpec workflow; workflow.emplace_back(readoutProxy); From 2b5eb934c7acf194d6541a5228c5f26084029551 Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Thu, 21 Sep 2023 09:37:14 +0200 Subject: [PATCH 081/324] Fix TRD pile-up information (#11924) * Fix TRD pile-up and PH information - pile-up setting was OK, but getters were broken - after TRD digits were sorted by default the neighbouring check was broken - due to shared digits PH values could be counted multiple times and incomplete - fix ClassDef version of CalT0 class * Fix digit comparison independently of sorting order --- .../TRD/include/DataFormatsTRD/CalT0.h | 2 +- DataFormats/Detectors/TRD/src/Tracklet64.cxx | 2 +- Detectors/TRD/calibration/src/PulseHeight.cxx | 43 +++++++++++++------ .../DataTypes/GPUTRDInterfaceO2Track.h | 7 +-- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalT0.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalT0.h index 038c2a5684d5f..69fc23646c912 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalT0.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/CalT0.h @@ -63,7 +63,7 @@ class CalT0 std::array mT0{}; ///< calibrated T0 per TRD chamber float mT0av{-1}; ///< average T0 obtained from fitting the PH data from all chambers combined - ClassDefNV(CalT0, 1); + ClassDefNV(CalT0, 2); }; } // namespace trd diff --git a/DataFormats/Detectors/TRD/src/Tracklet64.cxx b/DataFormats/Detectors/TRD/src/Tracklet64.cxx index af4c8e2b9d9d2..9245165709979 100644 --- a/DataFormats/Detectors/TRD/src/Tracklet64.cxx +++ b/DataFormats/Detectors/TRD/src/Tracklet64.cxx @@ -22,7 +22,7 @@ namespace trd void Tracklet64::print() const { LOGF(info, "%02i_%i_%i, ROB(%i), MCM(%i), row(%i), col(%i), position(%i), slope(%i), pid(%i), q0(%i), q1(%i), q2(%i). Format(%i)", - HelperMethods::getSector(getDetector()), HelperMethods::getStack(getDetector()), HelperMethods::getLayer(getDetector()), getROB(), getMCM(), getPadRow(), getColumn(), getPosition(), getSlope(), getPID(), getQ0(), getQ1(), getQ2(), getFormat()); + HelperMethods::getSector(getDetector()), HelperMethods::getStack(getDetector()), HelperMethods::getLayer(getDetector()), getROB(), getMCM(), getPadRow(), getPadCol(), getPosition(), getSlope(), getPID(), getQ0(), getQ1(), getQ2(), getFormat()); } #ifndef GPUCA_GPUCODE_DEVICE diff --git a/Detectors/TRD/calibration/src/PulseHeight.cxx b/Detectors/TRD/calibration/src/PulseHeight.cxx index 851637a88a901..13dee1ab9cfee 100644 --- a/Detectors/TRD/calibration/src/PulseHeight.cxx +++ b/Detectors/TRD/calibration/src/PulseHeight.cxx @@ -92,16 +92,19 @@ void PulseHeight::process() const auto& trigTrack = (*trackTriggers)[iTrigTrack]; if (trigTrack.getBCData().differenceInBC(trig.getBCData()) > 0) { // aborting, since track trigger is later than digit trigger"; + LOGP(debug, "Aborting, track trigger is too late"); break; } if (trigTrack.getBCData() != trig.getBCData()) { // skipping, since track trigger earlier than digit trigger"; + LOGP(debug, "Skipping, track trigger is too late"); ++lastTrkTrig[iTrackType]; continue; } if ((*tracks)[trigTrack.getFirstTrack()].hasPileUpInfo() && (*tracks)[trigTrack.getFirstTrack()].getPileUpTimeShiftMUS() < mParams.pileupCut) { // rejecting triggers which are close to other collisions (avoid pile-up) ++lastTrkTrig[iTrackType]; + LOGP(debug, "Rececting trigger due to pileup of {}", (*tracks)[trigTrack.getFirstTrack()].getPileUpTimeShiftMUS()); break; } for (int iTrk = trigTrack.getFirstTrack(); iTrk < trigTrack.getFirstTrack() + trigTrack.getNumberOfTracks(); iTrk++) { @@ -125,8 +128,13 @@ void PulseHeight::process() void PulseHeight::findDigitsForTracklet(const Tracklet64& trklt, const TriggerRecord& trig, int type) { auto trkltDet = trklt.getDetector(); - for (int iDigit = trig.getFirstDigit() + 1; iDigit < trig.getFirstDigit() + trig.getNumberOfDigits() - 1; ++iDigit) { + int iDigitFirst = trig.getFirstDigit(); + int iDigitLast = trig.getFirstDigit() + trig.getNumberOfDigits(); + for (int iDigit = iDigitFirst + 1; iDigit < iDigitLast - 1; ++iDigit) { const auto& digit = (*mDigits)[iDigit]; + if (digit.isSharedDigit()) { + continue; // avoid double-counting of the same digit + } if (digit.getDetector() != trkltDet || digit.getPadRow() != trklt.getPadRow() || digit.getPadCol() != trklt.getPadCol()) { // for now we loose charge information from padrow-crossing tracklets (~15% of all tracklets) continue; @@ -134,38 +142,47 @@ void PulseHeight::findDigitsForTracklet(const Tracklet64& trklt, const TriggerRe int nNeighbours = 0; bool left = false; bool right = false; - const auto& digitLeft = (*mDigits)[iDigit - 1]; - const auto& digitRight = (*mDigits)[iDigit + 1]; + const auto* digitLeft = &(*mDigits)[iDigit + 1]; + const auto* digitRight = &(*mDigits)[iDigit - 1]; + // due to shared digits the neighbouring element might still be in the same pad column + if (digitLeft->getPadCol() == digit.getPadCol() && iDigit < iDigitLast - 2) { + digitLeft = &(*mDigits)[iDigit + 2]; + } + if (digitRight->getPadCol() == digit.getPadCol() && iDigit > iDigitFirst + 2) { + digitRight = &(*mDigits)[iDigit - 2]; + } LOG(debug) << "Central digit: " << digit; - LOG(debug) << "Left digit: " << digitLeft; - LOG(debug) << "Right digit: " << digitRight; - if (digitLeft.isNeighbour(digit) && digitLeft.getChannel() < digit.getChannel()) { + LOG(debug) << "Left digit: " << *digitLeft; + LOG(debug) << "Right digit: " << *digitRight; + int direction = 0; + if (digitLeft->isNeighbour(digit)) { ++nNeighbours; left = true; + direction = digit.getPadCol() - digitLeft->getPadCol(); } - if (digitRight.isNeighbour(digit) && digitRight.getChannel() > digit.getChannel()) { + if (digitRight->isNeighbour(digit) && digit.getPadCol() - digitRight->getPadCol() != direction) { ++nNeighbours; right = true; } if (nNeighbours > 0) { int digitTrackletDistance = 0; auto adcSumMax = digit.getADCsum(); - if (left && digitLeft.getADCsum() > adcSumMax) { - adcSumMax = digitLeft.getADCsum(); + if (left && digitLeft->getADCsum() > adcSumMax) { + adcSumMax = digitLeft->getADCsum(); digitTrackletDistance = 1; } - if (right && digitRight.getADCsum() > adcSumMax) { - adcSumMax = digitRight.getADCsum(); + if (right && digitRight->getADCsum() > adcSumMax) { + adcSumMax = digitRight->getADCsum(); digitTrackletDistance = -1; } mDistances.push_back(digitTrackletDistance); for (int iTb = 0; iTb < TIMEBINS; ++iTb) { uint16_t phVal = digit.getADC()[iTb]; if (left) { - phVal += digitLeft.getADC()[iTb]; + phVal += digitLeft->getADC()[iTb]; } if (right) { - phVal += digitRight.getADC()[iTb]; + phVal += digitRight->getADC()[iTb]; } mPHValues.emplace_back(phVal, trkltDet, iTb, nNeighbours, type); } diff --git a/GPU/GPUTracking/DataTypes/GPUTRDInterfaceO2Track.h b/GPU/GPUTracking/DataTypes/GPUTRDInterfaceO2Track.h index fb1190b7b6216..19cad3649fa42 100644 --- a/GPU/GPUTracking/DataTypes/GPUTRDInterfaceO2Track.h +++ b/GPU/GPUTracking/DataTypes/GPUTRDInterfaceO2Track.h @@ -77,10 +77,11 @@ class trackInterface : public o2::track::TrackParCov GPUdi() void setPileUpDistance(unsigned char bwd, unsigned char fwd) { setUserField((((unsigned short)bwd) << 8) | fwd); } GPUdi() bool hasPileUpInfo() const { return getUserField() != 0; } - GPUdi() unsigned char getPileUpDistanceBwd() const { return ((unsigned char)getUserField()) >> 8; } - GPUdi() unsigned char getPileUpDistanceFwd() const { return ((unsigned char)getUserField()) & 255; } + GPUdi() bool hasPileUpInfoBothSides() const { return getPileUpDistanceBwd() > 0 && getPileUpDistanceFwd() > 0; } + GPUdi() unsigned char getPileUpDistanceBwd() const { return getUserField() >> 8; } + GPUdi() unsigned char getPileUpDistanceFwd() const { return getUserField() & 255; } GPUdi() unsigned short getPileUpSpan() const { return ((unsigned short)getPileUpDistanceBwd()) + getPileUpDistanceFwd(); } - GPUdi() float getPileUpMean() const { return 0.5 * ((float)getPileUpDistanceFwd()) - ((float)getPileUpDistanceBwd()); } + GPUdi() float getPileUpMean() const { return hasPileUpInfoBothSides() ? 0.5 * (getPileUpDistanceFwd() + getPileUpDistanceBwd()) : getPileUpDistanceFwd() + getPileUpDistanceBwd(); } GPUdi() float getPileUpTimeShiftMUS() const { return getPileUpMean() * o2::constants::lhc::LHCBunchSpacingMUS; } GPUdi() float getPileUpTimeErrorMUS() const { return getPileUpSpan() * o2::constants::lhc::LHCBunchSpacingMUS / 3.4641016; } From d66f71545e364848891a6bdfed3c878060c5f09e Mon Sep 17 00:00:00 2001 From: wiechula <11199190+wiechula@users.noreply.github.com> Date: Thu, 21 Sep 2023 12:59:39 +0200 Subject: [PATCH 082/324] TPC: Add DCAr histograms to TPC QC Tracks component (#11909) * [WIP] Adds: O2 DCA histograms in tracks task * Fix DCA histogramming part + cleanup * Configuration of Propagator must be done outside the code (e.g. QC framework) * map must use std::string as key, instead of std::string_view * remove unnecessary DCAz * simplify code * remove unnecessary includes --------- Co-authored-by: Bhawani Singh --- .../Base/include/DetectorsBase/Propagator.h | 5 ++- Detectors/TPC/qc/include/TPCQC/Helpers.h | 7 +++- Detectors/TPC/qc/include/TPCQC/Tracks.h | 11 +++--- Detectors/TPC/qc/src/Helpers.cxx | 21 +++++++++- Detectors/TPC/qc/src/Tracks.cxx | 38 +++++++++++++++++-- 5 files changed, 69 insertions(+), 13 deletions(-) diff --git a/Detectors/Base/include/DetectorsBase/Propagator.h b/Detectors/Base/include/DetectorsBase/Propagator.h index 84cc4b5f30732..2227f2156c401 100644 --- a/Detectors/Base/include/DetectorsBase/Propagator.h +++ b/Detectors/Base/include/DetectorsBase/Propagator.h @@ -34,7 +34,7 @@ namespace parameters { class GRPObject; class GRPMagField; -} +} // namespace parameters namespace dataformats { @@ -45,7 +45,7 @@ namespace field { class MagFieldFast; class MagneticField; -} +} // namespace field namespace gpu { @@ -134,6 +134,7 @@ class PropagatorImpl GPUd() void setGPUField(const o2::gpu::GPUTPCGMPolynomialField* field) { mGPUField = field; } GPUd() const o2::gpu::GPUTPCGMPolynomialField* getGPUField() const { return mGPUField; } GPUd() void setBz(value_type bz) { mBz = bz; } + GPUd() bool hasMagFieldSet() const { return mField != nullptr; } GPUd() void estimateLTFast(o2::track::TrackLTIntegral& lt, const o2::track::TrackParametrization& trc) const; diff --git a/Detectors/TPC/qc/include/TPCQC/Helpers.h b/Detectors/TPC/qc/include/TPCQC/Helpers.h index 9469121bf8f19..23eeb8286104e 100644 --- a/Detectors/TPC/qc/include/TPCQC/Helpers.h +++ b/Detectors/TPC/qc/include/TPCQC/Helpers.h @@ -22,6 +22,7 @@ #include "TH2F.h" #include +#include #include "TPCBase/CalDet.h" namespace o2 @@ -58,6 +59,10 @@ void setStyleHistogram(TH1& histo); void setStyleHistogramsInMap(std::unordered_map>>& mapOfvectors); // set nice style of histograms in a map void setStyleHistogramsInMap(std::unordered_map>& mapOfHisto); +// set nice style of histograms in a map of vectors +void setStyleHistogramsInMap(std::unordered_map>>& mapOfvectors); +// set nice style of histograms in a map +void setStyleHistogramsInMap(std::unordered_map>& mapOfHisto); /// Check if at least one pad in refPedestal and pedestal differs by 3*refNoise to see if new ZS calibration data should be uploaded to the FECs. /// @param refPedestal /// @param refNoise @@ -70,4 +75,4 @@ bool newZSCalib(const o2::tpc::CalDet& refPedestal, const o2::tpc::CalDet } // namespace tpc } // namespace o2 -#endif \ No newline at end of file +#endif diff --git a/Detectors/TPC/qc/include/TPCQC/Tracks.h b/Detectors/TPC/qc/include/TPCQC/Tracks.h index 899d0878fa401..509855673ee48 100644 --- a/Detectors/TPC/qc/include/TPCQC/Tracks.h +++ b/Detectors/TPC/qc/include/TPCQC/Tracks.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -27,9 +28,6 @@ #include "TH1F.h" #include "TH2F.h" -// o2 includes -#include "DataFormatsTPC/Defs.h" - namespace o2 { namespace tpc @@ -77,6 +75,7 @@ class Tracks mCutMinnCls = nClusterCut; mCutMindEdxTot = dEdxTot; } + // Just for backward compatibility with crrent QC, temporary, will be removed in the next PR /// get 1D histograms std::vector& getHistograms1D() { return mHist1D; } @@ -93,14 +92,14 @@ class Tracks const std::vector& getHistogramRatios1D() const { return mHistRatio1D; } /// get ratios of 1D histograms - std::unordered_map>& getMapHist() { return mMapHist; } - const std::unordered_map>& getMapHist() const { return mMapHist; } + std::unordered_map>& getMapHist() { return mMapHist; } + const std::unordered_map>& getMapHist() const { return mMapHist; } private: float mCutAbsEta = 1.f; // Eta cut int mCutMinnCls = 60; // minimum N clusters float mCutMindEdxTot = 20.f; // dEdxTot min value - std::unordered_map> mMapHist; + std::unordered_map> mMapHist; std::vector mHist1D{}; ///< Initialize vector of 1D histograms std::vector mHist2D{}; ///< Initialize vector of 2D histograms std::vector mHistRatio1D{}; ///< Initialize vector of ratios of 1D histograms diff --git a/Detectors/TPC/qc/src/Helpers.cxx b/Detectors/TPC/qc/src/Helpers.cxx index 3eb2501edc57e..2abf79f93836a 100644 --- a/Detectors/TPC/qc/src/Helpers.cxx +++ b/Detectors/TPC/qc/src/Helpers.cxx @@ -99,6 +99,25 @@ void helpers::setStyleHistogramsInMap(std::unordered_map>>& mapOfvectors) +{ + for (const auto& keyValue : mapOfvectors) { + for (auto& hist : keyValue.second) { + helpers::setStyleHistogram(*hist); + } + } +} + +//______________________________________________________________________________ +void helpers::setStyleHistogramsInMap(std::unordered_map>& mapOfHisto) +{ + for (const auto& keyValue : mapOfHisto) { + helpers::setStyleHistogram(*(keyValue.second)); + } +} + //______________________________________________________________________________ bool helpers::newZSCalib(const o2::tpc::CalDet& refPedestal, const o2::tpc::CalDet& refNoise, const o2::tpc::CalDet& pedestal) { @@ -119,4 +138,4 @@ bool helpers::newZSCalib(const o2::tpc::CalDet& refPedestal, const o2::tp } return false; -} \ No newline at end of file +} diff --git a/Detectors/TPC/qc/src/Tracks.cxx b/Detectors/TPC/qc/src/Tracks.cxx index 49615c3c786a6..878212c1e0429 100644 --- a/Detectors/TPC/qc/src/Tracks.cxx +++ b/Detectors/TPC/qc/src/Tracks.cxx @@ -16,18 +16,20 @@ // root includes #include "TFile.h" -#include "TMathBase.h" // o2 includes #include "DataFormatsTPC/TrackTPC.h" #include "DataFormatsTPC/dEdxInfo.h" +#include "GPUCommonArray.h" +#include "DetectorsBase/Propagator.h" #include "TPCQC/Tracks.h" #include "TPCQC/Helpers.h" ClassImp(o2::tpc::qc::Tracks); using namespace o2::tpc::qc; - +// DCA histograms +const std::vector types{"A_Pos", "A_Neg", "C_Pos", "C_Neg"}; //______________________________________________________________________________ void Tracks::initializeHistograms() { @@ -78,6 +80,11 @@ void Tracks::initializeHistograms() mMapHist["hPhiAsideRatio"] = std::make_unique("hPhiAsideRatio", "Azimuthal angle, A side, ratio neg./pos. ;phi", 360, 0., 2 * M_PI); mMapHist["hPhiCsideRatio"] = std::make_unique("hPhiCsideRatio", "Azimuthal angle, C side, ratio neg./pos. ;phi", 360, 0., 2 * M_PI); mMapHist["hPtRatio"] = std::make_unique("hPtRatio", "Transverse momentum, ratio neg./pos. ;p_T", logPtBinning.size() - 1, logPtBinning.data()); + + // DCA Histograms + for (const auto type : types) { + mMapHist[fmt::format("hDCAr_{}", type).data()] = std::make_unique(fmt::format("hDCAr_{}", type).data(), fmt::format("DCAr {};phi;DCAr (cm)", type).data(), 360, 0, o2::math_utils::twoPid(), 250, -10., 10.); + } } //______________________________________________________________________________ void Tracks::resetHistograms() @@ -100,7 +107,7 @@ bool Tracks::processTrack(const o2::tpc::TrackTPC& track) const auto hasASideOnly = track.hasASideClustersOnly(); const auto hasCSideOnly = track.hasCSideClustersOnly(); - double absEta = TMath::Abs(eta); + const auto absEta = std::abs(eta); // ===| histogram filling before cuts |=== mMapHist["hNClustersBeforeCuts"]->Fill(nCls); @@ -117,6 +124,31 @@ bool Tracks::processTrack(const o2::tpc::TrackTPC& track) mMapHist["hNClustersAfterCuts"]->Fill(nCls); mMapHist["hEta"]->Fill(eta); + //---| propagate to 0,0,0 |--- + // + // propagator instance must be configured before (LUT, MagField) + auto propagator = o2::base::Propagator::Instance(true); + const int type = (track.getQ2Pt() < 0) + 2 * track.hasCSideClustersOnly(); + auto dcaHist = mMapHist[fmt::format("hDCAr_{}", types[type]).data()].get(); + + if (propagator->getMatLUT() && propagator->hasMagFieldSet()) { + // ---| fill DCA histos |--- + o2::gpu::gpustd::array dca; + const o2::math_utils::Point3D refPoint{0, 0, 0}; + o2::track::TrackPar propTrack(track); + if (propagator->propagateToDCABxByBz(refPoint, propTrack, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dca)) { + const auto phi = o2::math_utils::to02PiGen(track.getPhi()); + dcaHist->Fill(phi, dca[0]); + } + } else { + static bool reported = false; + if (!reported) { + LOGP(error, "o2::base::Propagator not properly initialized, MatLUT ({}) and / or Field ({}) missing, will not fill DCA histograms", (void*)propagator->getMatLUT(), (void*)propagator->hasMagFieldSet()); + reported = true; + } + dcaHist->SetTitle(fmt::format("DCAr {} o2::base::Propagator not properly initialized", types[type]).data()); + } + if (hasASideOnly == 1) { mMapHist["hPhiAside"]->Fill(phi); } else if (hasCSideOnly == 1) { From 53942dc56a18dfcf55f2deef325a8913bb6d2eb0 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 20 Sep 2023 22:40:23 +0200 Subject: [PATCH 083/324] Fix missing include --- Utilities/rANS/include/rANS/serialize.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Utilities/rANS/include/rANS/serialize.h b/Utilities/rANS/include/rANS/serialize.h index 5a46df196fd41..19aefe2607ef2 100644 --- a/Utilities/rANS/include/rANS/serialize.h +++ b/Utilities/rANS/include/rANS/serialize.h @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef RANS_ENABLE_JSON #include From eeea6849a41f8bbe606003cfd997e3cbea02d84c Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 21 Sep 2023 00:58:35 +0200 Subject: [PATCH 084/324] Add TPC trigger info to CTF --- .../TPC/include/DataFormatsTPC/CTF.h | 18 +++-- .../include/DataFormatsTPC/ZeroSuppression.h | 2 + .../Detectors/TPC/src/DataFormatsTPCLinkDef.h | 1 + Detectors/CTF/test/test_ctf_io_tpc.cxx | 51 +++++++++++++- .../include/TPCReconstruction/CTFCoder.h | 67 ++++++++++++++++--- .../TPC/workflow/src/EntropyDecoderSpec.cxx | 5 +- .../TPC/workflow/src/EntropyEncoderSpec.cxx | 43 +++++++++++- 7 files changed, 168 insertions(+), 19 deletions(-) diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CTF.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CTF.h index 1e57c9654932c..1f4f08db9d1b9 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CTF.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CTF.h @@ -27,14 +27,15 @@ namespace tpc struct CTFHeader : public ctf::CTFDictHeader, public CompressedClustersCounters { enum : uint32_t { CombinedColumns = 0x1 }; uint32_t flags = 0; - - ClassDefNV(CTFHeader, 2); + uint32_t firstOrbitTrig = 0; /// orbit of 1st trigger + uint16_t nTriggers = 0; /// number of triggers + ClassDefNV(CTFHeader, 3); }; /// wrapper for the Entropy-encoded clusters of the TF -struct CTF : public o2::ctf::EncodedBlocks { +struct CTF : public o2::ctf::EncodedBlocks { - using container_t = o2::ctf::EncodedBlocks; + using container_t = o2::ctf::EncodedBlocks; static constexpr size_t N = getNBlocks(); static constexpr int NBitsQTot = 16; @@ -66,9 +67,14 @@ struct CTF : public o2::ctf::EncodedBlocks { BLCsigmaPadU, BLCsigmaTimeU, // can be combined with BLCsigmaPadU BLCnTrackClusters, - BLCnSliceRowClusters }; + BLCnSliceRowClusters, + // trigger info + BLCTrigOrbitInc, + BLCTrigBCInc, + BLCTrigType + }; - ClassDefNV(CTF, 2); + ClassDefNV(CTF, 4); }; } // namespace tpc diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h index 85ee355dde9c5..b1df9445bcf42 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h @@ -102,6 +102,8 @@ struct TriggerWordDLBZS { uint16_t getTriggerBC(int entry = 0) const { return triggerEntries[entry] & 0xFFF; } uint16_t getTriggerType(int entry = 0) const { return (triggerEntries[entry] >> 12) & 0x7; } bool isValid(int entry = 0) const { return triggerEntries[entry] & 0x8000; } + + ClassDefNV(TriggerWordDLBZS, 1); }; /// Trigger info including the orbit diff --git a/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h b/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h index 4f513317ced63..5a7ce1b18920b 100644 --- a/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h +++ b/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h @@ -70,6 +70,7 @@ #pragma link C++ class o2::tpc::dcs::DataPointVector < o2::tpc::dcs::HV::StackState> + ; #pragma link C++ class o2::tpc::dcs::Gas + ; #pragma link C++ class o2::tpc::PIDResponse + ; +#pragma link C++ class o2::tpc::TriggerWordDLBZS + ; #pragma link C++ class o2::tpc::TriggerInfoDLBZS + ; #pragma link C++ class std::vector < o2::tpc::TriggerInfoDLBZS> + ; diff --git a/Detectors/CTF/test/test_ctf_io_tpc.cxx b/Detectors/CTF/test/test_ctf_io_tpc.cxx index 210ab0af105bd..cb087e6f2a38f 100644 --- a/Detectors/CTF/test/test_ctf_io_tpc.cxx +++ b/Detectors/CTF/test/test_ctf_io_tpc.cxx @@ -20,6 +20,7 @@ #include #include #include "DataFormatsTPC/CompressedClusters.h" +#include "DataFormatsTPC/ZeroSuppression.h" #include "DataFormatsTPC/CTF.h" #include "CommonUtils/NameConf.h" #include "TPCReconstruction/CTFCoder.h" @@ -37,12 +38,21 @@ inline std::vector CombineColumns(true, false); BOOST_DATA_TEST_CASE(CTFTest, boost_data::make(ANSVersions) ^ boost_data::make(CombineColumns), ansVersion, combineColumns) { + std::vector triggers, triggersR; CompressedClusters c; c.nAttachedClusters = 99; c.nUnattachedClusters = 88; c.nAttachedClustersReduced = 77; c.nTracks = 66; + triggers.emplace_back(); + triggers.back().orbit = 1234; + triggers.back().triggerWord.triggerEntries[0] = (10 & 0xFFF) | ((o2::tpc::TriggerWordDLBZS::TriggerType::PhT & 0x7) << 12) | 0x8000; + triggers.back().triggerWord.triggerEntries[1] = (30 & 0xFFF) | ((o2::tpc::TriggerWordDLBZS::TriggerType::PP & 0x7) << 12) | 0x8000; + triggers.emplace_back(); + triggers.back().orbit = 1236; + triggers.back().triggerWord.triggerEntries[0] = (40 & 0xFFF) | ((o2::tpc::TriggerWordDLBZS::TriggerType::Cal & 0x7) << 12) | 0x8000; + std::vector bVec; CompressedClustersFlat* ccFlat = nullptr; size_t sizeCFlatBody = CTFCoder::alignSize(ccFlat); @@ -96,10 +106,43 @@ BOOST_DATA_TEST_CASE(CTFTest, boost_data::make(ANSVersions) ^ boost_data::make(C sw.Start(); std::vector vecIO; { - CTFCoder coder(o2::ctf::CTFCoderBase::OpType::Decoder); + CTFCoder coder(o2::ctf::CTFCoderBase::OpType::Encoder); coder.setCombineColumns(combineColumns); coder.setANSVersion(ansVersion); - coder.encode(vecIO, c, c); // compress + // prepare trigger info + o2::tpc::detail::TriggerInfo trigComp; + for (const auto& trig : triggers) { + for (int it = 0; it < o2::tpc::TriggerWordDLBZS::MaxTriggerEntries; it++) { + if (trig.triggerWord.isValid(it)) { + trigComp.deltaOrbit.push_back(trig.orbit); + trigComp.deltaBC.push_back(trig.triggerWord.getTriggerBC(it)); + trigComp.triggerType.push_back(trig.triggerWord.getTriggerType(it)); + } else { + break; + } + } + } + // transform trigger info to differential form + uint32_t prevOrbit = -1; + uint16_t prevBC = -1; + if (trigComp.triggerType.size()) { + prevOrbit = trigComp.firstOrbit = trigComp.deltaOrbit[0]; + prevBC = trigComp.deltaBC[0]; + trigComp.deltaOrbit[0] = 0; + for (size_t it = 1; it < trigComp.triggerType.size(); it++) { + if (trigComp.deltaOrbit[it] == prevOrbit) { + auto bc = trigComp.deltaBC[it]; + trigComp.deltaBC[it] -= prevBC; + prevBC = bc; + trigComp.deltaOrbit[it] = 0; + } else { + auto orb = trigComp.deltaOrbit[it]; + trigComp.deltaOrbit[it] -= prevOrbit; + prevOrbit = orb; + } + } + } + coder.encode(vecIO, c, c, trigComp); // compress } sw.Stop(); LOG(info) << "Compressed in " << sw.CpuTime() << " s"; @@ -135,7 +178,7 @@ BOOST_DATA_TEST_CASE(CTFTest, boost_data::make(ANSVersions) ^ boost_data::make(C { CTFCoder coder(o2::ctf::CTFCoderBase::OpType::Decoder); coder.setCombineColumns(true); - coder.decode(ctfImage, vecIn); // decompress + coder.decode(ctfImage, vecIn, triggersR); // decompress } sw.Stop(); LOG(info) << "Decompressed in " << sw.CpuTime() << " s"; @@ -153,4 +196,6 @@ BOOST_DATA_TEST_CASE(CTFTest, boost_data::make(ANSVersions) ^ boost_data::make(C BOOST_CHECK(countOrig->solenoidBz == countDeco->solenoidBz); BOOST_CHECK(countOrig->maxTimeBin == countDeco->maxTimeBin); BOOST_CHECK(memcmp(vecIn.data() + sizeof(o2::tpc::CompressedClustersCounters), bVec.data() + sizeof(o2::tpc::CompressedClustersCounters), bVec.size() - sizeof(o2::tpc::CompressedClustersCounters)) == 0); + BOOST_CHECK(triggers.size() == triggersR.size()); + BOOST_CHECK(memcmp(triggers.data(), triggersR.data(), triggers.size() * sizeof(o2::tpc::TriggerInfoDLBZS)) == 0); } diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h index 6242b50eab449..ab49d0d49d79b 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h @@ -40,6 +40,26 @@ namespace tpc namespace detail { +struct TriggerInfo { + uint32_t firstOrbit = -1; + std::vector deltaOrbit; + std::vector deltaBC; + std::vector triggerType; + void clear() + { + firstOrbit = -1; + deltaOrbit.clear(); + deltaBC.clear(); + triggerType.clear(); + } + void resize(size_t s) + { + deltaOrbit.resize(s); + deltaBC.resize(s); + triggerType.resize(s); + } +}; + template struct combinedType { using type = std::conditional_t<(A + B > 16), uint32_t, std::conditional_t<(A + B > 8), uint16_t, uint8_t>>; @@ -107,10 +127,10 @@ class CTFCoder : public o2::ctf::CTFCoderBase /// entropy-encode compressed clusters to flat buffer template - o2::ctf::CTFIOSize encode(VEC& buff, const CompressedClusters& ccl, const CompressedClusters& cclFiltered, std::vector* rejectHits = nullptr, std::vector* rejectTracks = nullptr, std::vector* rejectTrackHits = nullptr, std::vector* rejectTrackHitsReduced = nullptr); + o2::ctf::CTFIOSize encode(VEC& buff, const CompressedClusters& ccl, const CompressedClusters& cclFiltered, const detail::TriggerInfo& trigComp, std::vector* rejectHits = nullptr, std::vector* rejectTracks = nullptr, std::vector* rejectTrackHits = nullptr, std::vector* rejectTrackHitsReduced = nullptr); - template - o2::ctf::CTFIOSize decode(const CTF::base& ec, VEC& buff); + template + o2::ctf::CTFIOSize decode(const CTF::base& ec, VEC& buff, TRIGVEC& buffTrig); void createCoders(const std::vector& bufVec, o2::ctf::CTFCoderBase::OpType op) final; @@ -161,7 +181,7 @@ void CTFCoder::buildCoder(ctf::CTFCoderBase::OpType coderType, const CTF::contai /// entropy-encode clusters to buffer with CTF template -o2::ctf::CTFIOSize CTFCoder::encode(VEC& buff, const CompressedClusters& ccl, const CompressedClusters& cclFiltered, std::vector* rejectHits, std::vector* rejectTracks, std::vector* rejectTrackHits, std::vector* rejectTrackHitsReduced) +o2::ctf::CTFIOSize CTFCoder::encode(VEC& buff, const CompressedClusters& ccl, const CompressedClusters& cclFiltered, const detail::TriggerInfo& trigComp, std::vector* rejectHits, std::vector* rejectTracks, std::vector* rejectTrackHits, std::vector* rejectTrackHitsReduced) { using MD = o2::ctf::Metadata::OptStore; using namespace detail; @@ -189,7 +209,10 @@ o2::ctf::CTFIOSize CTFCoder::encode(VEC& buff, const CompressedClusters& ccl, co MD::EENCODE_OR_PACK, // sigmaPadU MD::EENCODE_OR_PACK, // sigmaTimeU MD::EENCODE_OR_PACK, // nTrackClusters - MD::EENCODE_OR_PACK // nSliceRowClusters + MD::EENCODE_OR_PACK, // nSliceRowClusters + MD::EENCODE_OR_PACK, // TrigBCInc + MD::EENCODE_OR_PACK, // TrigOrbitInc + MD::EENCODE_OR_PACK // TrigType }; // book output size with some margin @@ -202,7 +225,7 @@ o2::ctf::CTFIOSize CTFCoder::encode(VEC& buff, const CompressedClusters& ccl, co flags |= CTFHeader::CombinedColumns; } ec->setHeader(CTFHeader{o2::detectors::DetID::TPC, 0, 1, 0, // dummy timestamp, version 1.0 - cclFiltered, flags}); + cclFiltered, flags, trigComp.firstOrbit, (uint16_t)trigComp.triggerType.size()}); assignDictVersion(static_cast(ec->getHeader())); ec->setANSHeader(mANSVersion); @@ -286,6 +309,11 @@ o2::ctf::CTFIOSize CTFCoder::encode(VEC& buff, const CompressedClusters& ccl, co encodeTPC(ccl.nTrackClusters, ccl.nTrackClusters + ccl.nTracks, CTF::BLCnTrackClusters, 0, rejectTracks); encodeTPC(ccl.nSliceRowClusters, ccl.nSliceRowClusters + ccl.nSliceRows, CTF::BLCnSliceRowClusters, 0); + + encodeTPC(trigComp.deltaOrbit.begin(), trigComp.deltaOrbit.end(), CTF::BLCTrigOrbitInc, 0); + encodeTPC(trigComp.deltaBC.begin(), trigComp.deltaBC.end(), CTF::BLCTrigBCInc, 0); + encodeTPC(trigComp.triggerType.begin(), trigComp.triggerType.end(), CTF::BLCTrigType, 0); + CTF::get(buff.data())->print(getPrefix(), mVerbosity); finaliseCTFOutput(buff); iosize.rawIn = iosize.ctfIn; @@ -293,8 +321,8 @@ o2::ctf::CTFIOSize CTFCoder::encode(VEC& buff, const CompressedClusters& ccl, co } /// decode entropy-encoded bloks to TPC CompressedClusters into the externally provided vector (e.g. PMR vector from DPL) -template -o2::ctf::CTFIOSize CTFCoder::decode(const CTF::base& ec, VEC& buffVec) +template +o2::ctf::CTFIOSize CTFCoder::decode(const CTF::base& ec, VEC& buffVec, TRIGVEC& buffTrig) { using namespace detail; CompressedClusters cc; @@ -374,6 +402,29 @@ o2::ctf::CTFIOSize CTFCoder::decode(const CTF::base& ec, VEC& buffVec) decodeTPC(cc.nTrackClusters, CTF::BLCnTrackClusters); decodeTPC(cc.nSliceRowClusters, CTF::BLCnSliceRowClusters); + + static TriggerInfo trigInfo; + trigInfo.resize(header.nTriggers); + decodeTPC(trigInfo.deltaOrbit.data(), CTF::BLCTrigOrbitInc); + decodeTPC(trigInfo.deltaBC.data(), CTF::BLCTrigBCInc); + decodeTPC(trigInfo.triggerType.data(), CTF::BLCTrigType); + // convert trigger info to output format + uint32_t prevOrbit = header.firstOrbitTrig; + uint16_t prevBC = 0; + int freeSlot = 0; + for (uint16_t it = 0; it < header.nTriggers; it++) { + if (trigInfo.deltaOrbit[it] || !it) { // start new HBF, deltaBC has absolute BC meaning + freeSlot = 0; + auto& t = buffTrig.emplace_back(); + t.orbit = prevOrbit + trigInfo.deltaOrbit[it]; + t.triggerWord.triggerEntries[freeSlot++] = (trigInfo.deltaBC[it] & 0xFFF) | ((trigInfo.triggerType[it] & 0x7) << 12) | 0x8000; + prevBC = trigInfo.deltaBC[it]; + prevOrbit = t.orbit; + } else { // continue existing HBF + prevBC += trigInfo.deltaBC[it]; + buffTrig.back().triggerWord.triggerEntries[freeSlot++] = (prevBC & 0xFFF) | ((trigInfo.triggerType[it] & 0x7) << 12) | 0x8000; + } + } iosize.rawIn = iosize.ctfIn; return iosize; } diff --git a/Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx b/Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx index e0f27913c9d2b..4ff3573918722 100644 --- a/Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx @@ -17,6 +17,7 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/CCDBParamSpec.h" #include "DataFormatsTPC/CompressedClusters.h" +#include "DataFormatsTPC/ZeroSuppression.h" #include "TPCWorkflow/EntropyDecoderSpec.h" using namespace o2::framework; @@ -48,9 +49,10 @@ void EntropyDecoderSpec::run(ProcessingContext& pc) auto buff = pc.inputs().get>("ctf_TPC"); auto& compclusters = pc.outputs().make>(OutputRef{"output"}); + auto& triggers = pc.outputs().make>(OutputRef{"trigger"}); if (buff.size()) { const auto ctfImage = o2::tpc::CTF::getImage(buff.data()); - iosize = mCTFCoder.decode(ctfImage, compclusters); + iosize = mCTFCoder.decode(ctfImage, compclusters, triggers); } pc.outputs().snapshot({"ctfrep", 0}, iosize); mTimer.Stop(); @@ -75,6 +77,7 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) "tpc-entropy-decoder", inputs, Outputs{OutputSpec{{"output"}, "TPC", "COMPCLUSTERSFLAT", 0, Lifetime::Timeframe}, + OutputSpec{{"trigger"}, "TPC", "TRIGGERWORDS", 0, Lifetime::Timeframe}, OutputSpec{{"ctfrep"}, "TPC", "CTFDECREP", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask(verbosity)}, Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, diff --git a/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx b/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx index 28226752528bf..7e03748da0bc4 100644 --- a/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx @@ -16,6 +16,7 @@ #include "TPCWorkflow/EntropyEncoderSpec.h" #include "DataFormatsTPC/CompressedClusters.h" +#include "DataFormatsTPC/ZeroSuppression.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/CCDBParamSpec.h" #include "Headers/DataHeader.h" @@ -112,6 +113,7 @@ void EntropyEncoderSpec::run(ProcessingContext& pc) mCTFCoder.updateTimeDependentParams(pc, true); CompressedClusters clusters; + static o2::tpc::detail::TriggerInfo trigComp; if (mFromFile) { auto tmp = pc.inputs().get("input"); @@ -128,12 +130,28 @@ void EntropyEncoderSpec::run(ProcessingContext& pc) } clusters = *tmp; } + auto triggers = pc.inputs().get>("trigger"); auto cput = mTimer.CpuTime(); mTimer.Start(false); auto& buffer = pc.outputs().make>(Output{"TPC", "CTFDATA", 0, Lifetime::Timeframe}); std::vector rejectHits, rejectTracks, rejectTrackHits, rejectTrackHitsReduced; CompressedClusters clustersFiltered = clusters; std::vector, std::vector>> tmpBuffer(std::max(mNThreads, 1)); + + // prepare trigger info + trigComp.clear(); + for (const auto& trig : triggers) { + for (int it = 0; it < o2::tpc::TriggerWordDLBZS::MaxTriggerEntries; it++) { + if (trig.triggerWord.isValid(it)) { + trigComp.deltaOrbit.push_back(trig.orbit); + trigComp.deltaBC.push_back(trig.triggerWord.getTriggerBC(it)); + trigComp.triggerType.push_back(trig.triggerWord.getTriggerType(it)); + } else { + break; + } + } + } + if (mSelIR) { if (clusters.nTracks && clusters.solenoidBz != -1e6f && clusters.solenoidBz != mParam->bzkG) { throw std::runtime_error("Configured solenoid Bz does not match value used for track model encoding"); @@ -258,7 +276,29 @@ void EntropyEncoderSpec::run(ProcessingContext& pc) clustersFiltered.timeDiffU = tmpBuffer[0].first.data(); clustersFiltered.padDiffU = tmpBuffer[0].second.data(); } - auto iosize = mCTFCoder.encode(buffer, clusters, clustersFiltered, mSelIR ? &rejectHits : nullptr, mSelIR ? &rejectTracks : nullptr, mSelIR ? &rejectTrackHits : nullptr, mSelIR ? &rejectTrackHitsReduced : nullptr); + + // transform trigger info to differential form + uint32_t prevOrbit = -1; + uint16_t prevBC = -1; + if (trigComp.triggerType.size()) { + prevOrbit = trigComp.firstOrbit = trigComp.deltaOrbit[0]; + prevBC = trigComp.deltaBC[0]; + trigComp.deltaOrbit[0] = 0; + for (size_t it = 1; it < trigComp.triggerType.size(); it++) { + if (trigComp.deltaOrbit[it] == prevOrbit) { + auto bc = trigComp.deltaBC[it]; + trigComp.deltaBC[it] -= prevBC; + prevBC = bc; + trigComp.deltaOrbit[it] = 0; + } else { + auto orb = trigComp.deltaOrbit[it]; + trigComp.deltaOrbit[it] -= prevOrbit; + prevOrbit = orb; + } + } + } + + auto iosize = mCTFCoder.encode(buffer, clusters, clustersFiltered, trigComp, mSelIR ? &rejectHits : nullptr, mSelIR ? &rejectTracks : nullptr, mSelIR ? &rejectTrackHits : nullptr, mSelIR ? &rejectTrackHitsReduced : nullptr); pc.outputs().snapshot({"ctfrep", 0}, iosize); mTimer.Stop(); if (mSelIR) { @@ -278,6 +318,7 @@ DataProcessorSpec getEntropyEncoderSpec(bool inputFromFile, bool selIR) std::vector inputs; header::DataDescription inputType = inputFromFile ? header::DataDescription("COMPCLUSTERS") : header::DataDescription("COMPCLUSTERSFLAT"); inputs.emplace_back("input", "TPC", inputType, 0, Lifetime::Timeframe); + inputs.emplace_back("trigger", "TPC", "TRIGGERWORDS", 0, Lifetime::Timeframe); inputs.emplace_back("ctfdict", "TPC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TPC/Calib/CTFDictionaryTree")); std::shared_ptr ggreq; From b52ba0adf8049dc458a066be8786dca361a9488c Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 21 Sep 2023 00:59:12 +0200 Subject: [PATCH 085/324] Add TPC trigger reader/writer The TPC triggers will be automatically read and written at the same time when native clusters are read or written, although for technical reasons they are stored in separate tree/file via dedicated writer. In case previously produced data set lacking TPC triggers output file needs to be read-out, one should export DPL_DISABLE_TPC_TRIGGER_READER=1 env.var. to not initialize the trigger reader. Triggers are added to the RecoContainer and can be accessed via recoContainer.getTPCTriggers() --- .../DataFormatsGlobalTracking/RecoContainer.h | 4 + .../RecoContainerCreateTracksVariadic.h | 1 + .../GlobalTracking/src/RecoContainer.cxx | 20 +++++ .../helpers/src/InputHelper.cxx | 4 + Detectors/TPC/workflow/CMakeLists.txt | 1 + .../TPCWorkflow/TPCTriggerWriterSpec.h | 27 +++++++ Detectors/TPC/workflow/readers/CMakeLists.txt | 1 + .../TPCReaderWorkflow/TriggerReaderSpec.h | 59 ++++++++++++++ .../readers/src/TriggerReaderSpec.cxx | 78 +++++++++++++++++++ .../TPC/workflow/src/FileReaderWorkflow.cxx | 4 + Detectors/TPC/workflow/src/RecoWorkflow.cxx | 9 +++ .../TPC/workflow/src/TPCTriggerWriterSpec.cxx | 37 +++++++++ 12 files changed, 245 insertions(+) create mode 100644 Detectors/TPC/workflow/include/TPCWorkflow/TPCTriggerWriterSpec.h create mode 100644 Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TriggerReaderSpec.h create mode 100644 Detectors/TPC/workflow/readers/src/TriggerReaderSpec.cxx create mode 100644 Detectors/TPC/workflow/src/TPCTriggerWriterSpec.cxx diff --git a/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h index 36dcf85a528b5..a766b7d72bd9d 100644 --- a/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h +++ b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h @@ -37,6 +37,7 @@ namespace o2::tpc class TrackTPC; using TPCClRefElem = uint32_t; struct ClusterNativeAccess; +struct TriggerInfoDLBZS; namespace internal { struct getWorkflowTPCInput_ret; @@ -224,6 +225,7 @@ struct DataRequest { void requestITSClusters(bool mc); void requestMFTClusters(bool mc); void requestTPCClusters(bool mc); + void requestTPCTriggers(); void requestTOFClusters(bool mc); void requestTRDTracklets(bool mc); void requestMCHClusters(bool mc); @@ -370,6 +372,7 @@ struct RecoContainer { void addITSClusters(o2::framework::ProcessingContext& pc, bool mc); void addMFTClusters(o2::framework::ProcessingContext& pc, bool mc); void addTPCClusters(o2::framework::ProcessingContext& pc, bool mc, bool shmap); + void addTPCTriggers(o2::framework::ProcessingContext& pc); void addTOFClusters(o2::framework::ProcessingContext& pc, bool mc); void addHMPClusters(o2::framework::ProcessingContext& pc, bool mc); void addTRDTracklets(o2::framework::ProcessingContext& pc, bool mc); @@ -535,6 +538,7 @@ struct RecoContainer { auto getTPCTrackMCLabel(GTrackID id) const { return getObject(id, MCLABELS); } const o2::tpc::ClusterNativeAccess& getTPCClusters() const; const o2::dataformats::ConstMCTruthContainerView* getTPCClustersMCLabels() const; + auto getTPCTriggers() const { return getSpan(GTrackID::TPC, MATCHES); } // ITS-TPC const o2::dataformats::TrackTPCITS& getTPCITSTrack(GTrackID gid) const { return getTrack(gid); } diff --git a/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h index 9730f8c7ac506..6c31dec12c7d4 100644 --- a/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h +++ b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h @@ -17,6 +17,7 @@ #include "Framework/InputSpec.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DataFormatsTPC/WorkflowHelper.h" +#include "DataFormatsTPC/ZeroSuppression.h" #include "DataFormatsTRD/RecoInputContainer.h" #include "DataFormatsITSMFT/CompCluster.h" #include "DataFormatsITS/TrackITS.h" diff --git a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx index 18b4815a0856d..257d43089b9b6 100644 --- a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx +++ b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx @@ -250,6 +250,9 @@ void DataRequest::requestMFTClusters(bool mc) void DataRequest::requestTPCClusters(bool mc) { addInput({"clusTPC", ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}, Lifetime::Timeframe}); + if (!getenv("DPL_DISABLE_TPC_TRIGGER_READER") || atoi(getenv("DPL_DISABLE_TPC_TRIGGER_READER")) != 1) { + requestTPCTriggers(); + } if (requestMap.find("trackTPC") != requestMap.end()) { addInput({"clusTPCshmap", "TPC", "CLSHAREDMAP", 0, Lifetime::Timeframe}); } @@ -259,6 +262,12 @@ void DataRequest::requestTPCClusters(bool mc) requestMap["clusTPC"] = mc; } +void DataRequest::requestTPCTriggers() +{ + addInput({"trigTPC", "TPC", "TRIGGERWORDS", 0, Lifetime::Timeframe}); + requestMap["trigTPC"] = false; +} + void DataRequest::requestTOFClusters(bool mc) { addInput({"tofcluster", "TOF", "CLUSTERS", 0, Lifetime::Timeframe}); @@ -672,6 +681,11 @@ void RecoContainer::collectData(ProcessingContext& pc, const DataRequest& reques addTPCClusters(pc, req->second, reqMap.find("trackTPC") != reqMap.end()); } + req = reqMap.find("trigTPC"); + if (req != reqMap.end()) { + addTPCTriggers(pc); + } + req = reqMap.find("clusTOF"); if (req != reqMap.end()) { addTOFClusters(pc, req->second); @@ -1054,6 +1068,12 @@ void RecoContainer::addTPCClusters(ProcessingContext& pc, bool mc, bool shmap) } } +//__________________________________________________________ +void RecoContainer::addTPCTriggers(ProcessingContext& pc) +{ + commonPool[GTrackID::TPC].registerContainer(pc.inputs().get>("trigTPC"), MATCHES); +} + //__________________________________________________________ void RecoContainer::addTRDTracklets(ProcessingContext& pc, bool mc) { diff --git a/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx b/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx index c7067e1e4e0b6..856e20fe3f993 100644 --- a/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx +++ b/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx @@ -18,6 +18,7 @@ #include "MFTWorkflow/TrackReaderSpec.h" #include "TPCReaderWorkflow/TrackReaderSpec.h" #include "TPCReaderWorkflow/ClusterReaderSpec.h" +#include "TPCReaderWorkflow/TriggerReaderSpec.h" #include "TPCWorkflow/ClusterSharingMapSpec.h" #include "HMPIDWorkflow/ClustersReaderSpec.h" #include "HMPIDWorkflow/HMPMatchedReaderSpec.h" @@ -97,6 +98,9 @@ int InputHelper::addInputSpecs(const ConfigContext& configcontext, WorkflowSpec& } if (maskClusters[GID::TPC]) { specs.emplace_back(o2::tpc::getClusterReaderSpec(maskClustersMC[GID::TPC])); + if (!getenv("DPL_DISABLE_TPC_TRIGGER_READER") || atoi(getenv("DPL_DISABLE_TPC_TRIGGER_READER")) != 1) { + specs.emplace_back(o2::tpc::getTPCTriggerReaderSpec()); + } } if (maskTracks[GID::TPC] && maskClusters[GID::TPC]) { specs.emplace_back(o2::tpc::getClusterSharingMapSpec()); diff --git a/Detectors/TPC/workflow/CMakeLists.txt b/Detectors/TPC/workflow/CMakeLists.txt index 4dc4d3345005c..1834649fb2bf6 100644 --- a/Detectors/TPC/workflow/CMakeLists.txt +++ b/Detectors/TPC/workflow/CMakeLists.txt @@ -39,6 +39,7 @@ o2_add_library(TPCWorkflow src/TPCIntegrateClusterReaderSpec.cxx src/TPCIntegrateClusterSpec.cxx src/TPCIntegrateClusterWriterSpec.cxx + src/TPCTriggerWriterSpec.cxx src/TPCMergeIntegrateClusterSpec.cxx TARGETVARNAME targetName PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsTPC diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCTriggerWriterSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCTriggerWriterSpec.h new file mode 100644 index 0000000000000..b7858fe688eb9 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCTriggerWriterSpec.h @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_TPCTRIGGERWRITER_SPEC +#define O2_TPC_TPCTRIGGERWRITER_SPEC + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace tpc +{ + +o2::framework::DataProcessorSpec getTPCTriggerWriterSpec(); + +} // end namespace tpc +} // end namespace o2 + +#endif diff --git a/Detectors/TPC/workflow/readers/CMakeLists.txt b/Detectors/TPC/workflow/readers/CMakeLists.txt index 74eca5dff0139..80e967c287404 100644 --- a/Detectors/TPC/workflow/readers/CMakeLists.txt +++ b/Detectors/TPC/workflow/readers/CMakeLists.txt @@ -13,6 +13,7 @@ o2_add_library(TPCReaderWorkflow SOURCES src/ClusterReaderSpec.cxx src/PublisherSpec.cxx src/TrackReaderSpec.cxx + src/TriggerReaderSpec.cxx TARGETVARNAME targetName PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsTPC diff --git a/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TriggerReaderSpec.h b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TriggerReaderSpec.h new file mode 100644 index 0000000000000..a7f6f467c7d09 --- /dev/null +++ b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TriggerReaderSpec.h @@ -0,0 +1,59 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TriggerReaderSpec.h + +#ifndef O2_TPC_TRIGGERREADER +#define O2_TPC_TRIGGERREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Headers/DataHeader.h" +#include "DataFormatsTPC/ZeroSuppression.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tpc +{ +///< DPL device to read and send the TPC tracks (+MC) info + +class TriggerReader : public Task +{ + public: + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + void connectTree(const std::string& filename); + + std::vector* mTrig = nullptr; + + std::unique_ptr mFile; + std::unique_ptr mTree; + + std::string mInputFileName = "tpctriggers.root"; + std::string mTriggerTreeName = "triggers"; + std::string mTriggerBranchName = "Triggers"; +}; + +/// create a processor spec +/// read TPC track data from a root file +framework::DataProcessorSpec getTPCTriggerReaderSpec(); + +} // namespace tpc +} // namespace o2 + +#endif /* O2_TPC_TRIGGERREADER */ diff --git a/Detectors/TPC/workflow/readers/src/TriggerReaderSpec.cxx b/Detectors/TPC/workflow/readers/src/TriggerReaderSpec.cxx new file mode 100644 index 0000000000000..2c363f4f7ed93 --- /dev/null +++ b/Detectors/TPC/workflow/readers/src/TriggerReaderSpec.cxx @@ -0,0 +1,78 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TriggerReaderSpec.cxx + +#include +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "TPCReaderWorkflow/TriggerReaderSpec.h" +#include "CommonUtils/NameConf.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tpc +{ + +void TriggerReader::init(InitContext& ic) +{ + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get("input-dir")), + ic.options().get("infile")); + connectTree(mInputFileName); +} + +void TriggerReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + mTree->GetEntry(ent); + + pc.outputs().snapshot(Output{"TPC", "TRIGGERWORDS", 0, Lifetime::Timeframe}, *mTrig); + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(QuitRequest::Me); + } +} + +void TriggerReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + if (!(mFile && !mFile->IsZombie())) { + throw std::runtime_error("Error opening tree file"); + } + mTree.reset((TTree*)mFile->Get(mTriggerTreeName.c_str())); + if (!mTree) { + throw std::runtime_error("Error opening tree"); + } + + mTree->SetBranchAddress(mTriggerBranchName.c_str(), &mTrig); + LOG(info) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getTPCTriggerReaderSpec() +{ + std::vector outputSpec; + outputSpec.emplace_back("TPC", "TRIGGERWORDS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "tpc-trigger-reader", + Inputs{}, + outputSpec, + AlgorithmSpec{adaptFromTask()}, + Options{ + {"infile", VariantType::String, "tpctriggers.root", {"Name of the input triggers file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace tpc +} // namespace o2 diff --git a/Detectors/TPC/workflow/src/FileReaderWorkflow.cxx b/Detectors/TPC/workflow/src/FileReaderWorkflow.cxx index b083a5133fae9..c50b5685cdcd0 100644 --- a/Detectors/TPC/workflow/src/FileReaderWorkflow.cxx +++ b/Detectors/TPC/workflow/src/FileReaderWorkflow.cxx @@ -12,6 +12,7 @@ /// @file FileReaderWorkflow.cxx #include "TPCReaderWorkflow/ClusterReaderSpec.h" +#include "TPCReaderWorkflow/TriggerReaderSpec.h" #include "TPCReaderWorkflow/TrackReaderSpec.h" #include "Algorithm/RangeTokenizer.h" @@ -67,6 +68,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) if (isEnabled(Input::Clusters)) { specs.emplace_back(o2::tpc::getClusterReaderSpec(doMC)); + if (!getenv("DPL_DISABLE_TPC_TRIGGER_READER") || atoi(getenv("DPL_DISABLE_TPC_TRIGGER_READER")) != 1) { + specs.emplace_back(o2::tpc::getTPCTriggerReaderSpec()); + } } if (isEnabled(Input::Tracks)) { diff --git a/Detectors/TPC/workflow/src/RecoWorkflow.cxx b/Detectors/TPC/workflow/src/RecoWorkflow.cxx index a529808978c9b..4e2ea2447306e 100644 --- a/Detectors/TPC/workflow/src/RecoWorkflow.cxx +++ b/Detectors/TPC/workflow/src/RecoWorkflow.cxx @@ -19,6 +19,7 @@ #include "Framework/Logger.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "TPCWorkflow/RecoWorkflow.h" +#include "TPCWorkflow/TPCTriggerWriterSpec.h" #include "TPCReaderWorkflow/PublisherSpec.h" #include "TPCWorkflow/ClustererSpec.h" #include "TPCWorkflow/ClusterDecoderRawSpec.h" @@ -40,6 +41,7 @@ #include "DataFormatsTPC/Helpers.h" #include "DataFormatsTPC/ZeroSuppression.h" #include "TPCReaderWorkflow/ClusterReaderSpec.h" +#include "TPCReaderWorkflow/TriggerReaderSpec.h" #include #include @@ -205,6 +207,9 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto propagateMC)); } else if (inputType == InputType::Clusters) { specs.emplace_back(o2::tpc::getClusterReaderSpec(propagateMC, &tpcSectors, &laneConfiguration)); + if (!getenv("DPL_DISABLE_TPC_TRIGGER_READER") || atoi(getenv("DPL_DISABLE_TPC_TRIGGER_READER")) != 1) { + specs.emplace_back(o2::tpc::getTPCTriggerReaderSpec()); + } } else if (inputType == InputType::CompClusters) { // TODO: need to check if we want to store the MC labels alongside with compressed clusters // for the moment reading of labels is disabled (last parameter is false) @@ -415,6 +420,10 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto (caClusterer || decompressTPC || inputType == InputType::PassThrough) && !isEnabled(OutputType::SendClustersPerSector))); } + if ((isEnabled(OutputType::TPCTriggers) || caClusterer) && !isEnabled(OutputType::DisableWriter)) { + specs.push_back(o2::tpc::getTPCTriggerWriterSpec()); + } + if (zsOnTheFly) { specs.emplace_back(o2::tpc::getZSEncoderSpec(tpcSectors, outRaw, tpcSectorMask)); } diff --git a/Detectors/TPC/workflow/src/TPCTriggerWriterSpec.cxx b/Detectors/TPC/workflow/src/TPCTriggerWriterSpec.cxx new file mode 100644 index 0000000000000..769185bfca2f0 --- /dev/null +++ b/Detectors/TPC/workflow/src/TPCTriggerWriterSpec.cxx @@ -0,0 +1,37 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TPCIntegrateClusterWriterSpec.cxx + +#include +#include "TPCWorkflow/TPCTriggerWriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsTPC/ZeroSuppression.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tpc +{ +template +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; + +DataProcessorSpec getTPCTriggerWriterSpec() +{ + return MakeRootTreeWriterSpec("tpc-trigger-writer", + "tpctriggers.root", + "triggers", + BranchDefinition>{InputSpec{"trig", o2::header::gDataOriginTPC, "TRIGGERWORDS", 0}, "Triggers"})(); +} + +} // namespace tpc +} // namespace o2 From 94a5ff0f698a70b722446746c6b13318e7f3b2f5 Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 21 Sep 2023 12:49:29 +0200 Subject: [PATCH 086/324] gpu-reco request tpc-trigger outputs only with raw input --- prodtests/full-system-test/dpl-workflow.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 53438f749ed63..5aa0a57281487 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -68,7 +68,7 @@ fi # --------------------------------------------------------------------------------------------------------------------- # Set some individual workflow arguments depending on configuration GPU_INPUT=zsraw -GPU_OUTPUT=tracks,clusters,tpc-triggers +GPU_OUTPUT=tracks,clusters GPU_CONFIG= GPU_CONFIG_KEY= TOF_CONFIG= @@ -96,7 +96,9 @@ CTP_CONFIG= if [[ -z ${ALPIDE_ERR_DUMPS:-} ]]; then [[ $EPNSYNCMODE == 1 ]] && ALPIDE_ERR_DUMPS="1" || ALPIDE_ERR_DUMPS="0" fi - +if [[ $CTFINPUT != 1 ]]; then + GPU_OUTPUT+=",tpc-triggers" +fi if [[ $SYNCMODE == 1 ]]; then if [[ $BEAMTYPE == "PbPb" ]]; then ITS_CONFIG_KEY+="fastMultConfig.cutMultClusLow=${CUT_MULT_MIN_ITS:-100};fastMultConfig.cutMultClusHigh=${CUT_MULT_MAX_ITS:-200};fastMultConfig.cutMultVtxHigh=${CUT_MULT_VTX_ITS:-20};" From 8d60663c796260e006bac23a8c6fff93beb2d20d Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Thu, 21 Sep 2023 11:59:33 +0200 Subject: [PATCH 087/324] Fix disable output file writing of ED in FST --- prodtests/full-system-test/start_tmux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prodtests/full-system-test/start_tmux.sh b/prodtests/full-system-test/start_tmux.sh index a84b5a2b043b8..acf7f43451f1f 100755 --- a/prodtests/full-system-test/start_tmux.sh +++ b/prodtests/full-system-test/start_tmux.sh @@ -16,7 +16,7 @@ if [[ -z "${WORKFLOW_PARAMETERS+x}" ]]; then else export WORKFLOW_PARAMETERS="${WORKFLOW_PARAMETERS},CALIB_PROXIES" fi - [[ -z $ARGS_EXTRA_PROCESS_o2_eve_export_workflow ]] && ARGS_EXTRA_PROCESS_o2_eve_export_workflow="--disable-write" + [[ -z $ARGS_EXTRA_PROCESS_o2_eve_export_workflow ]] && export ARGS_EXTRA_PROCESS_o2_eve_export_workflow="--disable-write" if [[ -z "${GEN_TOPO_WORKDIR}" ]]; then mkdir -p gen_topo_tmp export GEN_TOPO_WORKDIR=`pwd`/gen_topo_tmp From 241f8935aa5af45c353d8c81aa3eecddc1a5e91a Mon Sep 17 00:00:00 2001 From: rcaron Date: Tue, 5 Sep 2023 21:27:26 +0200 Subject: [PATCH 088/324] LTF and CA tracking parameters refined (alignment considerations) --- .../MFT/tracking/include/MFTTracking/MFTTrackingParam.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/MFTTrackingParam.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/MFTTrackingParam.h index 29fbf53bb63e6..98842e0a5470a 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/MFTTrackingParam.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/MFTTrackingParam.h @@ -49,9 +49,9 @@ struct MFTTrackingParam : public o2::conf::ConfigurableParamHelper Date: Thu, 21 Sep 2023 22:25:16 +0200 Subject: [PATCH 089/324] Bump catch2 to 3.4.0 to try C++20 support (#11930) --- .../3rdparty/catch2/catch_amalgamated.cxx | 1224 ++++--- .../3rdparty/catch2/catch_amalgamated.hpp | 3063 +++++++++-------- 2 files changed, 2393 insertions(+), 1894 deletions(-) diff --git a/Framework/Foundation/3rdparty/catch2/catch_amalgamated.cxx b/Framework/Foundation/3rdparty/catch2/catch_amalgamated.cxx index 0e12bd1438af3..eba3f00ac4868 100644 --- a/Framework/Foundation/3rdparty/catch2/catch_amalgamated.cxx +++ b/Framework/Foundation/3rdparty/catch2/catch_amalgamated.cxx @@ -5,8 +5,8 @@ // SPDX-License-Identifier: BSL-1.0 -// Catch v3.3.1 -// Generated: 2023-01-29 22:55:05.183536 +// Catch v3.4.0 +// Generated: 2023-07-13 13:23:09.554273 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -60,6 +60,7 @@ namespace Catch { + #include namespace Catch { @@ -88,7 +89,7 @@ namespace Catch { #include #include -#include +#include #include @@ -96,117 +97,172 @@ namespace Catch { #include #endif -namespace { +namespace Catch { + namespace Benchmark { + namespace Detail { + namespace { + + template + static sample + resample( URng& rng, + unsigned int resamples, + std::vector::const_iterator first, + std::vector::const_iterator last, + Estimator& estimator ) { + auto n = static_cast( last - first ); + std::uniform_int_distribution dist( 0, + n - 1 ); + + sample out; + out.reserve( resamples ); + // We allocate the vector outside the loop to avoid realloc + // per resample + std::vector resampled; + resampled.reserve( n ); + for ( size_t i = 0; i < resamples; ++i ) { + resampled.clear(); + for ( size_t s = 0; s < n; ++s ) { + resampled.push_back( + first[static_cast( + dist( rng ) )] ); + } + const auto estimate = + estimator( resampled.begin(), resampled.end() ); + out.push_back( estimate ); + } + std::sort( out.begin(), out.end() ); + return out; + } -using Catch::Benchmark::Detail::sample; - - template - sample resample(URng& rng, unsigned int resamples, std::vector::iterator first, std::vector::iterator last, Estimator& estimator) { - auto n = static_cast(last - first); - std::uniform_int_distribution dist(0, n - 1); - - sample out; - out.reserve(resamples); - std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] { - std::vector resampled; - resampled.reserve(n); - std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[static_cast(dist(rng))]; }); - return estimator(resampled.begin(), resampled.end()); - }); - std::sort(out.begin(), out.end()); - return out; - } - - - double erf_inv(double x) { - // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2 - double w, p; - - w = -log((1.0 - x) * (1.0 + x)); - - if (w < 6.250000) { - w = w - 3.125000; - p = -3.6444120640178196996e-21; - p = -1.685059138182016589e-19 + p * w; - p = 1.2858480715256400167e-18 + p * w; - p = 1.115787767802518096e-17 + p * w; - p = -1.333171662854620906e-16 + p * w; - p = 2.0972767875968561637e-17 + p * w; - p = 6.6376381343583238325e-15 + p * w; - p = -4.0545662729752068639e-14 + p * w; - p = -8.1519341976054721522e-14 + p * w; - p = 2.6335093153082322977e-12 + p * w; - p = -1.2975133253453532498e-11 + p * w; - p = -5.4154120542946279317e-11 + p * w; - p = 1.051212273321532285e-09 + p * w; - p = -4.1126339803469836976e-09 + p * w; - p = -2.9070369957882005086e-08 + p * w; - p = 4.2347877827932403518e-07 + p * w; - p = -1.3654692000834678645e-06 + p * w; - p = -1.3882523362786468719e-05 + p * w; - p = 0.0001867342080340571352 + p * w; - p = -0.00074070253416626697512 + p * w; - p = -0.0060336708714301490533 + p * w; - p = 0.24015818242558961693 + p * w; - p = 1.6536545626831027356 + p * w; - } else if (w < 16.000000) { - w = sqrt(w) - 3.250000; - p = 2.2137376921775787049e-09; - p = 9.0756561938885390979e-08 + p * w; - p = -2.7517406297064545428e-07 + p * w; - p = 1.8239629214389227755e-08 + p * w; - p = 1.5027403968909827627e-06 + p * w; - p = -4.013867526981545969e-06 + p * w; - p = 2.9234449089955446044e-06 + p * w; - p = 1.2475304481671778723e-05 + p * w; - p = -4.7318229009055733981e-05 + p * w; - p = 6.8284851459573175448e-05 + p * w; - p = 2.4031110387097893999e-05 + p * w; - p = -0.0003550375203628474796 + p * w; - p = 0.00095328937973738049703 + p * w; - p = -0.0016882755560235047313 + p * w; - p = 0.0024914420961078508066 + p * w; - p = -0.0037512085075692412107 + p * w; - p = 0.005370914553590063617 + p * w; - p = 1.0052589676941592334 + p * w; - p = 3.0838856104922207635 + p * w; - } else { - w = sqrt(w) - 5.000000; - p = -2.7109920616438573243e-11; - p = -2.5556418169965252055e-10 + p * w; - p = 1.5076572693500548083e-09 + p * w; - p = -3.7894654401267369937e-09 + p * w; - p = 7.6157012080783393804e-09 + p * w; - p = -1.4960026627149240478e-08 + p * w; - p = 2.9147953450901080826e-08 + p * w; - p = -6.7711997758452339498e-08 + p * w; - p = 2.2900482228026654717e-07 + p * w; - p = -9.9298272942317002539e-07 + p * w; - p = 4.5260625972231537039e-06 + p * w; - p = -1.9681778105531670567e-05 + p * w; - p = 7.5995277030017761139e-05 + p * w; - p = -0.00021503011930044477347 + p * w; - p = -0.00013871931833623122026 + p * w; - p = 1.0103004648645343977 + p * w; - p = 4.8499064014085844221 + p * w; - } - return p * x; - } - - double standard_deviation(std::vector::iterator first, std::vector::iterator last) { - auto m = Catch::Benchmark::Detail::mean(first, last); - double variance = std::accumulate( first, - last, - 0., - [m]( double a, double b ) { - double diff = b - m; - return a + diff * diff; - } ) / - ( last - first ); - return std::sqrt( variance ); - } + static double outlier_variance( Estimate mean, + Estimate stddev, + int n ) { + double sb = stddev.point; + double mn = mean.point / n; + double mg_min = mn / 2.; + double sg = (std::min)( mg_min / 4., sb / std::sqrt( n ) ); + double sg2 = sg * sg; + double sb2 = sb * sb; + + auto c_max = [n, mn, sb2, sg2]( double x ) -> double { + double k = mn - x; + double d = k * k; + double nd = n * d; + double k0 = -n * nd; + double k1 = sb2 - n * sg2 + nd; + double det = k1 * k1 - 4 * sg2 * k0; + return static_cast( -2. * k0 / + ( k1 + std::sqrt( det ) ) ); + }; + + auto var_out = [n, sb2, sg2]( double c ) { + double nc = n - c; + return ( nc / n ) * ( sb2 - nc * sg2 ); + }; + + return (std::min)( var_out( 1 ), + var_out( + (std::min)( c_max( 0. ), + c_max( mg_min ) ) ) ) / + sb2; + } -} + static double erf_inv( double x ) { + // Code accompanying the article "Approximating the erfinv + // function" in GPU Computing Gems, Volume 2 + double w, p; + + w = -log( ( 1.0 - x ) * ( 1.0 + x ) ); + + if ( w < 6.250000 ) { + w = w - 3.125000; + p = -3.6444120640178196996e-21; + p = -1.685059138182016589e-19 + p * w; + p = 1.2858480715256400167e-18 + p * w; + p = 1.115787767802518096e-17 + p * w; + p = -1.333171662854620906e-16 + p * w; + p = 2.0972767875968561637e-17 + p * w; + p = 6.6376381343583238325e-15 + p * w; + p = -4.0545662729752068639e-14 + p * w; + p = -8.1519341976054721522e-14 + p * w; + p = 2.6335093153082322977e-12 + p * w; + p = -1.2975133253453532498e-11 + p * w; + p = -5.4154120542946279317e-11 + p * w; + p = 1.051212273321532285e-09 + p * w; + p = -4.1126339803469836976e-09 + p * w; + p = -2.9070369957882005086e-08 + p * w; + p = 4.2347877827932403518e-07 + p * w; + p = -1.3654692000834678645e-06 + p * w; + p = -1.3882523362786468719e-05 + p * w; + p = 0.0001867342080340571352 + p * w; + p = -0.00074070253416626697512 + p * w; + p = -0.0060336708714301490533 + p * w; + p = 0.24015818242558961693 + p * w; + p = 1.6536545626831027356 + p * w; + } else if ( w < 16.000000 ) { + w = sqrt( w ) - 3.250000; + p = 2.2137376921775787049e-09; + p = 9.0756561938885390979e-08 + p * w; + p = -2.7517406297064545428e-07 + p * w; + p = 1.8239629214389227755e-08 + p * w; + p = 1.5027403968909827627e-06 + p * w; + p = -4.013867526981545969e-06 + p * w; + p = 2.9234449089955446044e-06 + p * w; + p = 1.2475304481671778723e-05 + p * w; + p = -4.7318229009055733981e-05 + p * w; + p = 6.8284851459573175448e-05 + p * w; + p = 2.4031110387097893999e-05 + p * w; + p = -0.0003550375203628474796 + p * w; + p = 0.00095328937973738049703 + p * w; + p = -0.0016882755560235047313 + p * w; + p = 0.0024914420961078508066 + p * w; + p = -0.0037512085075692412107 + p * w; + p = 0.005370914553590063617 + p * w; + p = 1.0052589676941592334 + p * w; + p = 3.0838856104922207635 + p * w; + } else { + w = sqrt( w ) - 5.000000; + p = -2.7109920616438573243e-11; + p = -2.5556418169965252055e-10 + p * w; + p = 1.5076572693500548083e-09 + p * w; + p = -3.7894654401267369937e-09 + p * w; + p = 7.6157012080783393804e-09 + p * w; + p = -1.4960026627149240478e-08 + p * w; + p = 2.9147953450901080826e-08 + p * w; + p = -6.7711997758452339498e-08 + p * w; + p = 2.2900482228026654717e-07 + p * w; + p = -9.9298272942317002539e-07 + p * w; + p = 4.5260625972231537039e-06 + p * w; + p = -1.9681778105531670567e-05 + p * w; + p = 7.5995277030017761139e-05 + p * w; + p = -0.00021503011930044477347 + p * w; + p = -0.00013871931833623122026 + p * w; + p = 1.0103004648645343977 + p * w; + p = 4.8499064014085844221 + p * w; + } + return p * x; + } + + static double + standard_deviation( std::vector::const_iterator first, + std::vector::const_iterator last ) { + auto m = Catch::Benchmark::Detail::mean( first, last ); + double variance = + std::accumulate( first, + last, + 0., + [m]( double a, double b ) { + double diff = b - m; + return a + diff * diff; + } ) / + ( last - first ); + return std::sqrt( variance ); + } + + } // namespace + } // namespace Detail + } // namespace Benchmark +} // namespace Catch namespace Catch { namespace Benchmark { @@ -236,6 +292,47 @@ namespace Catch { return xj + g * (xj1 - xj); } + OutlierClassification + classify_outliers( std::vector::const_iterator first, + std::vector::const_iterator last ) { + std::vector copy( first, last ); + + auto q1 = weighted_average_quantile( 1, 4, copy.begin(), copy.end() ); + auto q3 = weighted_average_quantile( 3, 4, copy.begin(), copy.end() ); + auto iqr = q3 - q1; + auto los = q1 - ( iqr * 3. ); + auto lom = q1 - ( iqr * 1.5 ); + auto him = q3 + ( iqr * 1.5 ); + auto his = q3 + ( iqr * 3. ); + + OutlierClassification o; + for ( ; first != last; ++first ) { + const double t = *first; + if ( t < los ) { + ++o.low_severe; + } else if ( t < lom ) { + ++o.low_mild; + } else if ( t > his ) { + ++o.high_severe; + } else if ( t > him ) { + ++o.high_mild; + } + ++o.samples_seen; + } + return o; + } + + double mean( std::vector::const_iterator first, + std::vector::const_iterator last ) { + auto count = last - first; + double sum = 0.; + while (first != last) { + sum += *first; + ++first; + } + return sum / static_cast(count); + } + double erfc_inv(double x) { return erf_inv(1.0 - x); @@ -257,35 +354,10 @@ namespace Catch { return result; } - - double outlier_variance(Estimate mean, Estimate stddev, int n) { - double sb = stddev.point; - double mn = mean.point / n; - double mg_min = mn / 2.; - double sg = (std::min)(mg_min / 4., sb / std::sqrt(n)); - double sg2 = sg * sg; - double sb2 = sb * sb; - - auto c_max = [n, mn, sb2, sg2](double x) -> double { - double k = mn - x; - double d = k * k; - double nd = n * d; - double k0 = -n * nd; - double k1 = sb2 - n * sg2 + nd; - double det = k1 * k1 - 4 * sg2 * k0; - return static_cast(-2. * k0 / (k1 + std::sqrt(det))); - }; - - auto var_out = [n, sb2, sg2](double c) { - double nc = n - c; - return (nc / n) * (sb2 - nc * sg2); - }; - - return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2; - } - - - bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector::iterator first, std::vector::iterator last) { + bootstrap_analysis analyse_samples(double confidence_level, + unsigned int n_resamples, + std::vector::iterator first, + std::vector::iterator last) { CATCH_INTERNAL_START_WARNINGS_SUPPRESSION CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS static std::random_device entropy; @@ -293,11 +365,12 @@ namespace Catch { auto n = static_cast(last - first); // seriously, one can't use integral types without hell in C++ - auto mean = &Detail::mean::iterator>; + auto mean = &Detail::mean; auto stddev = &standard_deviation; #if defined(CATCH_CONFIG_USE_ASYNC) - auto Estimate = [=](double(*f)(std::vector::iterator, std::vector::iterator)) { + auto Estimate = [=](double(*f)(std::vector::const_iterator, + std::vector::const_iterator)) { auto seed = entropy(); return std::async(std::launch::async, [=] { std::mt19937 rng(seed); @@ -312,7 +385,8 @@ namespace Catch { auto mean_estimate = mean_future.get(); auto stddev_estimate = stddev_future.get(); #else - auto Estimate = [=](double(*f)(std::vector::iterator, std::vector::iterator)) { + auto Estimate = [=](double(*f)(std::vector::const_iterator, + std::vector::const_iterator)) { auto seed = entropy(); std::mt19937 rng(seed); auto resampled = resample(rng, n_resamples, first, last, f); @@ -469,16 +543,15 @@ namespace Catch { } std::string AssertionResult::getExpressionInMacro() const { - std::string expr; - if( m_info.macroName.empty() ) - expr = static_cast(m_info.capturedExpression); - else { - expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); - expr += m_info.macroName; - expr += "( "; - expr += m_info.capturedExpression; - expr += " )"; + if ( m_info.macroName.empty() ) { + return static_cast( m_info.capturedExpression ); } + std::string expr; + expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); + expr += m_info.macroName; + expr += "( "; + expr += m_info.capturedExpression; + expr += " )"; return expr; } @@ -597,7 +670,7 @@ namespace Catch { elem = trim(elem); } - // Insert the default reporter if user hasn't asked for a specfic one + // Insert the default reporter if user hasn't asked for a specific one if ( m_data.reporterSpecifications.empty() ) { m_data.reporterSpecifications.push_back( { #if defined( CATCH_CONFIG_DEFAULT_REPORTER ) @@ -776,7 +849,11 @@ namespace Catch { } - Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { + Capturer::Capturer( StringRef macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType resultType, + StringRef names ): + m_resultCapture( getResultCapture() ) { auto trimmed = [&] (size_t start, size_t end) { while (names[start] == ',' || isspace(static_cast(names[start]))) { ++start; @@ -853,6 +930,8 @@ namespace Catch { +#include + namespace Catch { namespace { @@ -863,7 +942,7 @@ namespace Catch { public: // IRegistryHub RegistryHub() = default; - IReporterRegistry const& getReporterRegistry() const override { + ReporterRegistry const& getReporterRegistry() const override { return m_reporterRegistry; } ITestCaseRegistry const& getTestCaseRegistry() const override { @@ -939,6 +1018,7 @@ namespace Catch { #include #include +#include #include #include @@ -1421,12 +1501,20 @@ namespace Catch { for (size_t idx = 0; idx < originalTags.size(); ++idx) { auto c = originalTags[idx]; if (c == '[') { - assert(!inTag); + CATCH_ENFORCE( + !inTag, + "Found '[' inside a tag while registering test case '" + << _nameAndTags.name << "' at " << _lineInfo ); + inTag = true; tagStart = idx; } if (c == ']') { - assert(inTag); + CATCH_ENFORCE( + inTag, + "Found unmatched ']' while registering test case '" + << _nameAndTags.name << "' at " << _lineInfo ); + inTag = false; tagEnd = idx; assert(tagStart < tagEnd); @@ -1435,7 +1523,11 @@ namespace Catch { // it over to backing storage and actually reference the // backing storage in the saved tags StringRef tagStr = originalTags.substr(tagStart+1, tagEnd - tagStart - 1); - CATCH_ENFORCE(!tagStr.empty(), "Empty tags are not allowed"); + CATCH_ENFORCE( !tagStr.empty(), + "Found an empty tag while registering test case '" + << _nameAndTags.name << "' at " + << _lineInfo ); + enforceNotReservedTag(tagStr, lineInfo); properties |= parseSpecialTag(tagStr); // When copying a tag to the backing storage, we need to @@ -1449,8 +1541,12 @@ namespace Catch { // the tags. internalAppendTag(tagStr); } - (void)inTag; // Silence "set-but-unused" warning in release mode. } + CATCH_ENFORCE( !inTag, + "Found an unclosed tag while registering test case '" + << _nameAndTags.name << "' at " << _lineInfo ); + + // Add [.] if relevant if (isHidden()) { internalAppendTag("."_sr); @@ -1626,16 +1722,18 @@ namespace Catch { return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } ); } - TestSpec::Matches TestSpec::matchesByFilter( std::vector const& testCases, IConfig const& config ) const - { - Matches matches( m_filters.size() ); - std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){ + TestSpec::Matches TestSpec::matchesByFilter( std::vector const& testCases, IConfig const& config ) const { + Matches matches; + matches.reserve( m_filters.size() ); + for ( auto const& filter : m_filters ) { std::vector currentMatches; - for( auto const& test : testCases ) - if( isThrowSafe( test, config ) && filter.matches( test.getTestCaseInfo() ) ) + for ( auto const& test : testCases ) + if ( isThrowSafe( test, config ) && + filter.matches( test.getTestCaseInfo() ) ) currentMatches.emplace_back( &test ); - return FilterMatch{ extractFilterName(filter), currentMatches }; - } ); + matches.push_back( + FilterMatch{ extractFilterName( filter ), currentMatches } ); + } return matches; } @@ -1992,6 +2090,19 @@ namespace Catch { } + + +namespace Catch { + namespace Detail { + void registerTranslatorImpl( + Detail::unique_ptr&& translator ) { + getMutableRegistryHub().registerTranslator( + CATCH_MOVE( translator ) ); + } + } // namespace Detail +} // namespace Catch + + #include namespace Catch { @@ -2022,7 +2133,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 3, 3, 1, "", 0 ); + static Version version( 3, 4, 0, "", 0 ); return version; } @@ -2173,8 +2284,6 @@ namespace Catch { infoMessages( _infoMessages ), totals( _totals ) { - assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; - if( assertionResult.hasMessage() ) { // Copy message into messages list. // !TBD This should have been done earlier, somewhere @@ -2198,13 +2307,13 @@ namespace Catch { TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, + std::string&& _stdOut, + std::string&& _stdErr, bool _aborting ) : testInfo( &_testInfo ), totals( _totals ), - stdOut( _stdOut ), - stdErr( _stdErr ), + stdOut( CATCH_MOVE(_stdOut) ), + stdErr( CATCH_MOVE(_stdErr) ), aborting( _aborting ) {} @@ -2233,14 +2342,6 @@ namespace Catch { namespace Catch { - IReporterRegistry::~IReporterRegistry() = default; -} - - - - -namespace Catch { - ITestInvoker::~ITestInvoker() = default; ITestCaseRegistry::~ITestCaseRegistry() = default; } @@ -2255,7 +2356,9 @@ namespace Catch { ResultDisposition::Flags resultDisposition ) : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, m_resultCapture( getResultCapture() ) - {} + { + m_resultCapture.notifyAssertionStarted( m_assertionInfo ); + } void AssertionHandler::handleExpr( ITransientExpression const& expr ) { m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); @@ -2269,7 +2372,7 @@ namespace Catch { } void AssertionHandler::complete() { - setCompleted(); + m_completed = true; if( m_reaction.shouldDebugBreak ) { // If you find your debugger stopping you here then go one level up on the @@ -2282,16 +2385,9 @@ namespace Catch { throw_test_failure_exception(); } if ( m_reaction.shouldSkip ) { -#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) - throw Catch::TestSkipException(); -#else - CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" ); -#endif + throw_test_skip_exception(); } } - void AssertionHandler::setCompleted() { - m_completed = true; - } void AssertionHandler::handleUnexpectedInflightException() { m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); @@ -2918,7 +3014,7 @@ namespace Catch { auto const& reporterSpec = *parsed; - IReporterRegistry::FactoryMap const& factories = + auto const& factories = getRegistryHub().getReporterRegistry().getFactories(); auto result = factories.find( reporterSpec.name() ); @@ -3156,7 +3252,7 @@ namespace Catch { namespace { //! A do-nothing implementation of colour, used as fallback for unknown //! platforms, and when the user asks to deactivate all colours. - class NoColourImpl : public ColourImpl { + class NoColourImpl final : public ColourImpl { public: NoColourImpl( IStream* stream ): ColourImpl( stream ) {} @@ -3174,7 +3270,7 @@ namespace Catch { namespace Catch { namespace { - class Win32ColourImpl : public ColourImpl { + class Win32ColourImpl final : public ColourImpl { public: Win32ColourImpl(IStream* stream): ColourImpl(stream) { @@ -3240,7 +3336,7 @@ namespace { namespace Catch { namespace { - class ANSIColourImpl : public ColourImpl { + class ANSIColourImpl final : public ColourImpl { public: ANSIColourImpl( IStream* stream ): ColourImpl( stream ) {} @@ -3356,49 +3452,27 @@ namespace Catch { namespace Catch { - class Context : public IMutableContext, private Detail::NonCopyable { - - public: // IContext - IResultCapture* getResultCapture() override { - return m_resultCapture; - } - - IConfig const* getConfig() const override { - return m_config; - } - - ~Context() override; - - public: // IMutableContext - void setResultCapture( IResultCapture* resultCapture ) override { - m_resultCapture = resultCapture; - } - void setConfig( IConfig const* config ) override { - m_config = config; - } - - friend IMutableContext& getCurrentMutableContext(); - - private: - IConfig const* m_config = nullptr; - IResultCapture* m_resultCapture = nullptr; - }; - - IMutableContext *IMutableContext::currentContext = nullptr; + Context* Context::currentContext = nullptr; - void IMutableContext::createContext() - { + void cleanUpContext() { + delete Context::currentContext; + Context::currentContext = nullptr; + } + void Context::createContext() { currentContext = new Context(); } - void cleanUpContext() { - delete IMutableContext::currentContext; - IMutableContext::currentContext = nullptr; + Context& getCurrentMutableContext() { + if ( !Context::currentContext ) { Context::createContext(); } + // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) + return *Context::currentContext; + } + + void Context::setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; } - IContext::~IContext() = default; - IMutableContext::~IMutableContext() = default; - Context::~Context() = default; + void Context::setConfig( IConfig const* config ) { m_config = config; } SimplePcg32& sharedRng() { static SimplePcg32 s_rng; @@ -3681,8 +3755,24 @@ namespace Catch { +#include + namespace Catch { + namespace { + static std::string tryTranslators( + std::vector< + Detail::unique_ptr> const& translators ) { + if ( translators.empty() ) { + std::rethrow_exception( std::current_exception() ); + } else { + return translators[0]->translate( translators.begin() + 1, + translators.end() ); + } + } + + } + ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { } @@ -3707,7 +3797,7 @@ namespace Catch { // First we try user-registered translators. If none of them can // handle the exception, it will be rethrown handled by our defaults. try { - return tryTranslators(); + return tryTranslators(m_translators); } // To avoid having to handle TFE explicitly everywhere, we just // rethrow it so that it goes back up the caller. @@ -3731,25 +3821,12 @@ namespace Catch { } } - std::string ExceptionTranslatorRegistry::tryTranslators() const { - if (m_translators.empty()) { - std::rethrow_exception(std::current_exception()); - } else { - return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end()); - } - } - #else // ^^ Exceptions are enabled // Exceptions are disabled vv std::string ExceptionTranslatorRegistry::translateActiveException() const { CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); } - - std::string ExceptionTranslatorRegistry::tryTranslators() const { - CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); - } #endif - } @@ -4054,7 +4131,7 @@ namespace Catch { namespace Detail { namespace { template - class StreamBufImpl : public std::streambuf { + class StreamBufImpl final : public std::streambuf { char data[bufferSize]; WriterF m_writer; @@ -4102,7 +4179,7 @@ namespace Detail { /////////////////////////////////////////////////////////////////////////// - class FileStream : public IStream { + class FileStream final : public IStream { std::ofstream m_ofs; public: FileStream( std::string const& filename ) { @@ -4119,7 +4196,7 @@ namespace Detail { /////////////////////////////////////////////////////////////////////////// - class CoutStream : public IStream { + class CoutStream final : public IStream { std::ostream m_os; public: // Store the streambuf from cout up-front because @@ -4148,7 +4225,7 @@ namespace Detail { /////////////////////////////////////////////////////////////////////////// - class DebugOutStream : public IStream { + class DebugOutStream final : public IStream { Detail::unique_ptr> m_streamBuf; std::ostream m_os; public: @@ -4278,7 +4355,7 @@ namespace Catch { void listReporters(IEventListener& reporter) { std::vector descriptions; - IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + auto const& factories = getRegistryHub().getReporterRegistry().getFactories(); descriptions.reserve(factories.size()); for (auto const& fac : factories) { descriptions.push_back({ fac.first, fac.second->getDescription() }); @@ -4697,49 +4774,71 @@ namespace Catch { namespace Catch { + struct ReporterRegistry::ReporterRegistryImpl { + std::vector> listeners; + std::map + factories; + }; - ReporterRegistry::ReporterRegistry() { + ReporterRegistry::ReporterRegistry(): + m_impl( Detail::make_unique() ) { // Because it is impossible to move out of initializer list, // we have to add the elements manually - m_factories["Automake"] = Detail::make_unique>(); - m_factories["compact"] = Detail::make_unique>(); - m_factories["console"] = Detail::make_unique>(); - m_factories["JUnit"] = Detail::make_unique>(); - m_factories["SonarQube"] = Detail::make_unique>(); - m_factories["TAP"] = Detail::make_unique>(); - m_factories["TeamCity"] = Detail::make_unique>(); - m_factories["XML"] = Detail::make_unique>(); + m_impl->factories["Automake"] = + Detail::make_unique>(); + m_impl->factories["compact"] = + Detail::make_unique>(); + m_impl->factories["console"] = + Detail::make_unique>(); + m_impl->factories["JUnit"] = + Detail::make_unique>(); + m_impl->factories["SonarQube"] = + Detail::make_unique>(); + m_impl->factories["TAP"] = + Detail::make_unique>(); + m_impl->factories["TeamCity"] = + Detail::make_unique>(); + m_impl->factories["XML"] = + Detail::make_unique>(); } ReporterRegistry::~ReporterRegistry() = default; - - IEventListenerPtr ReporterRegistry::create( std::string const& name, ReporterConfig&& config ) const { - auto it = m_factories.find( name ); - if( it == m_factories.end() ) - return nullptr; - return it->second->create( CATCH_MOVE(config) ); + IEventListenerPtr + ReporterRegistry::create( std::string const& name, + ReporterConfig&& config ) const { + auto it = m_impl->factories.find( name ); + if ( it == m_impl->factories.end() ) return nullptr; + return it->second->create( CATCH_MOVE( config ) ); } - void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr factory ) { + void ReporterRegistry::registerReporter( std::string const& name, + IReporterFactoryPtr factory ) { CATCH_ENFORCE( name.find( "::" ) == name.npos, - "'::' is not allowed in reporter name: '" + name + '\'' ); - auto ret = m_factories.emplace(name, CATCH_MOVE(factory)); - CATCH_ENFORCE( ret.second, "reporter using '" + name + "' as name was already registered" ); + "'::' is not allowed in reporter name: '" + name + + '\'' ); + auto ret = m_impl->factories.emplace( name, CATCH_MOVE( factory ) ); + CATCH_ENFORCE( ret.second, + "reporter using '" + name + + "' as name was already registered" ); } void ReporterRegistry::registerListener( Detail::unique_ptr factory ) { - m_listeners.push_back( CATCH_MOVE(factory) ); + m_impl->listeners.push_back( CATCH_MOVE( factory ) ); } - IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { - return m_factories; - } - IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { - return m_listeners; + std::map const& + ReporterRegistry::getFactories() const { + return m_impl->factories; } -} + std::vector> const& + ReporterRegistry::getListeners() const { + return m_impl->listeners; + } +} // namespace Catch @@ -4755,9 +4854,9 @@ namespace Catch { }; kvPair splitKVPair(StringRef kvString) { - auto splitPos = static_cast( std::distance( - kvString.begin(), - std::find( kvString.begin(), kvString.end(), '=' ) ) ); + auto splitPos = static_cast( + std::find( kvString.begin(), kvString.end(), '=' ) - + kvString.begin() ); return { kvString.substr( 0, splitPos ), kvString.substr( splitPos + 1, kvString.size() ) }; @@ -4989,146 +5088,152 @@ namespace Catch { namespace Catch { namespace Generators { - struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { - GeneratorBasePtr m_generator; + namespace { + struct GeneratorTracker final : TestCaseTracking::TrackerBase, + IGeneratorTracker { + GeneratorBasePtr m_generator; + + GeneratorTracker( + TestCaseTracking::NameAndLocation&& nameAndLocation, + TrackerContext& ctx, + ITracker* parent ): + TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ) {} + ~GeneratorTracker() override = default; + + static GeneratorTracker* + acquire( TrackerContext& ctx, + TestCaseTracking::NameAndLocationRef const& + nameAndLocation ) { + GeneratorTracker* tracker; + + ITracker& currentTracker = ctx.currentTracker(); + // Under specific circumstances, the generator we want + // to acquire is also the current tracker. If this is + // the case, we have to avoid looking through current + // tracker's children, and instead return the current + // tracker. + // A case where this check is important is e.g. + // for (int i = 0; i < 5; ++i) { + // int n = GENERATE(1, 2); + // } + // + // without it, the code above creates 5 nested generators. + if ( currentTracker.nameAndLocation() == nameAndLocation ) { + auto thisTracker = currentTracker.parent()->findChild( + nameAndLocation ); + assert( thisTracker ); + assert( thisTracker->isGeneratorTracker() ); + tracker = static_cast( thisTracker ); + } else if ( ITracker* childTracker = + currentTracker.findChild( + nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isGeneratorTracker() ); + tracker = + static_cast( childTracker ); + } else { + return nullptr; + } - GeneratorTracker( TestCaseTracking::NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ) - {} - ~GeneratorTracker() override; - - static GeneratorTracker* acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocationRef nameAndLocation ) { - GeneratorTracker* tracker; - - ITracker& currentTracker = ctx.currentTracker(); - // Under specific circumstances, the generator we want - // to acquire is also the current tracker. If this is - // the case, we have to avoid looking through current - // tracker's children, and instead return the current - // tracker. - // A case where this check is important is e.g. - // for (int i = 0; i < 5; ++i) { - // int n = GENERATE(1, 2); - // } - // - // without it, the code above creates 5 nested generators. - if ( currentTracker.nameAndLocation() == nameAndLocation ) { - auto thisTracker = - currentTracker.parent()->findChild( nameAndLocation ); - assert( thisTracker ); - assert( thisTracker->isGeneratorTracker() ); - tracker = static_cast( thisTracker ); - } else if ( ITracker* childTracker = - currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isGeneratorTracker() ); - tracker = static_cast( childTracker ); - } else { - return nullptr; - } + if ( !tracker->isComplete() ) { tracker->open(); } - if( !tracker->isComplete() ) { - tracker->open(); + return tracker; } - return tracker; - } - - // TrackerBase interface - bool isGeneratorTracker() const override { return true; } - auto hasGenerator() const -> bool override { - return !!m_generator; - } - void close() override { - TrackerBase::close(); - // If a generator has a child (it is followed by a section) - // and none of its children have started, then we must wait - // until later to start consuming its values. - // This catches cases where `GENERATE` is placed between two - // `SECTION`s. - // **The check for m_children.empty cannot be removed**. - // doing so would break `GENERATE` _not_ followed by `SECTION`s. - const bool should_wait_for_child = [&]() { - // No children -> nobody to wait for - if ( m_children.empty() ) { - return false; - } - // If at least one child started executing, don't wait - if ( std::find_if( - m_children.begin(), - m_children.end(), - []( TestCaseTracking::ITrackerPtr const& tracker ) { - return tracker->hasStarted(); - } ) != m_children.end() ) { - return false; - } - - // No children have started. We need to check if they _can_ - // start, and thus we should wait for them, or they cannot - // start (due to filters), and we shouldn't wait for them - ITracker* parent = m_parent; - // This is safe: there is always at least one section - // tracker in a test case tracking tree - while ( !parent->isSectionTracker() ) { - parent = parent->parent(); - } - assert( parent && - "Missing root (test case) level section" ); - - auto const& parentSection = - static_cast( *parent ); - auto const& filters = parentSection.getFilters(); - // No filters -> no restrictions on running sections - if ( filters.empty() ) { - return true; - } + // TrackerBase interface + bool isGeneratorTracker() const override { return true; } + auto hasGenerator() const -> bool override { + return !!m_generator; + } + void close() override { + TrackerBase::close(); + // If a generator has a child (it is followed by a section) + // and none of its children have started, then we must wait + // until later to start consuming its values. + // This catches cases where `GENERATE` is placed between two + // `SECTION`s. + // **The check for m_children.empty cannot be removed**. + // doing so would break `GENERATE` _not_ followed by + // `SECTION`s. + const bool should_wait_for_child = [&]() { + // No children -> nobody to wait for + if ( m_children.empty() ) { return false; } + // If at least one child started executing, don't wait + if ( std::find_if( + m_children.begin(), + m_children.end(), + []( TestCaseTracking::ITrackerPtr const& + tracker ) { + return tracker->hasStarted(); + } ) != m_children.end() ) { + return false; + } - for ( auto const& child : m_children ) { - if ( child->isSectionTracker() && - std::find( - filters.begin(), - filters.end(), - static_cast( *child ) - .trimmedName() ) != filters.end() ) { - return true; + // No children have started. We need to check if they + // _can_ start, and thus we should wait for them, or + // they cannot start (due to filters), and we shouldn't + // wait for them + ITracker* parent = m_parent; + // This is safe: there is always at least one section + // tracker in a test case tracking tree + while ( !parent->isSectionTracker() ) { + parent = parent->parent(); + } + assert( parent && + "Missing root (test case) level section" ); + + auto const& parentSection = + static_cast( *parent ); + auto const& filters = parentSection.getFilters(); + // No filters -> no restrictions on running sections + if ( filters.empty() ) { return true; } + + for ( auto const& child : m_children ) { + if ( child->isSectionTracker() && + std::find( filters.begin(), + filters.end(), + static_cast( + *child ) + .trimmedName() ) != + filters.end() ) { + return true; + } } + return false; + }(); + + // This check is a bit tricky, because m_generator->next() + // has a side-effect, where it consumes generator's current + // value, but we do not want to invoke the side-effect if + // this generator is still waiting for any child to start. + assert( m_generator && "Tracker without generator" ); + if ( should_wait_for_child || + ( m_runState == CompletedSuccessfully && + m_generator->countedNext() ) ) { + m_children.clear(); + m_runState = Executing; } - return false; - }(); - - // This check is a bit tricky, because m_generator->next() - // has a side-effect, where it consumes generator's current - // value, but we do not want to invoke the side-effect if - // this generator is still waiting for any child to start. - assert( m_generator && "Tracker without generator" ); - if ( should_wait_for_child || - ( m_runState == CompletedSuccessfully && - m_generator->countedNext() ) ) { - m_children.clear(); - m_runState = Executing; } - } - // IGeneratorTracker interface - auto getGenerator() const -> GeneratorBasePtr const& override { - return m_generator; - } - void setGenerator( GeneratorBasePtr&& generator ) override { - m_generator = CATCH_MOVE( generator ); - } - }; - GeneratorTracker::~GeneratorTracker() = default; + // IGeneratorTracker interface + auto getGenerator() const -> GeneratorBasePtr const& override { + return m_generator; + } + void setGenerator( GeneratorBasePtr&& generator ) override { + m_generator = CATCH_MOVE( generator ); + } + }; + } // namespace } RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter) : m_runInfo(_config->name()), - m_context(getCurrentMutableContext()), m_config(_config), m_reporter(CATCH_MOVE(reporter)), m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) { - m_context.setResultCapture(this); + getCurrentMutableContext().setResultCapture( this ); m_reporter->testRunStarting(m_runInfo); } @@ -5139,13 +5244,8 @@ namespace Catch { Totals RunContext::runTest(TestCaseHandle const& testCase) { const Totals prevTotals = m_totals; - std::string redirectedCout; - std::string redirectedCerr; - auto const& testInfo = testCase.getTestCaseInfo(); - m_reporter->testCaseStarting(testInfo); - m_activeTestCase = &testCase; @@ -5187,6 +5287,8 @@ namespace Catch { seedRng( *m_config ); uint64_t testRuns = 0; + std::string redirectedCout; + std::string redirectedCerr; do { m_trackerContext.startCycle(); m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo)); @@ -5200,7 +5302,7 @@ namespace Catch { redirectedCerr += oneRunCerr; const auto singleRunTotals = m_totals.delta(beforeRunTotals); - auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, oneRunCout, oneRunCerr, aborting()); + auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting()); m_reporter->testCasePartialEnded(statsForOneRun, testRuns); ++testRuns; @@ -5215,8 +5317,8 @@ namespace Catch { m_totals.testCases += deltaTotals.testCases; m_reporter->testCaseEnded(TestCaseStats(testInfo, deltaTotals, - redirectedCout, - redirectedCerr, + CATCH_MOVE(redirectedCout), + CATCH_MOVE(redirectedCerr), aborting())); m_activeTestCase = nullptr; @@ -5226,7 +5328,7 @@ namespace Catch { } - void RunContext::assertionEnded(AssertionResult const & result) { + void RunContext::assertionEnded(AssertionResult&& result) { if (result.getResultType() == ResultWas::Ok) { m_totals.assertions.passed++; m_lastAssertionPassed = true; @@ -5248,19 +5350,26 @@ namespace Catch { m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)); - if (result.getResultType() != ResultWas::Warning) + if ( result.getResultType() != ResultWas::Warning ) { m_messageScopes.clear(); + } // Reset working state resetAssertionInfo(); - m_lastResult = result; + m_lastResult = CATCH_MOVE( result ); } void RunContext::resetAssertionInfo() { m_lastAssertionInfo.macroName = StringRef(); m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; } - bool RunContext::sectionStarted(StringRef sectionName, SourceLineInfo const& sectionLineInfo, Counts & assertions) { + void RunContext::notifyAssertionStarted( AssertionInfo const& info ) { + m_reporter->assertionStarting( info ); + } + + bool RunContext::sectionStarted( StringRef sectionName, + SourceLineInfo const& sectionLineInfo, + Counts& assertions ) { ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocationRef( @@ -5398,7 +5507,7 @@ namespace Catch { tempResult.message = static_cast(message); AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult)); - assertionEnded(result); + assertionEnded(CATCH_MOVE(result) ); handleUnfinishedSections(); @@ -5520,8 +5629,6 @@ namespace Catch { ITransientExpression const& expr, AssertionReaction& reaction ) { - m_reporter->assertionStarting( info ); - bool negated = isFalseTest( info.resultDisposition ); bool result = expr.getResult() != negated; @@ -5550,7 +5657,7 @@ namespace Catch { AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; - assertionEnded( assertionResult ); + assertionEnded( CATCH_MOVE(assertionResult) ); } void RunContext::handleMessage( @@ -5559,16 +5666,16 @@ namespace Catch { StringRef message, AssertionReaction& reaction ) { - m_reporter->assertionStarting( info ); - m_lastAssertionInfo = info; AssertionResultData data( resultType, LazyExpression( false ) ); data.message = static_cast(message); AssertionResult assertionResult{ m_lastAssertionInfo, CATCH_MOVE( data ) }; - assertionEnded( assertionResult ); - if ( !assertionResult.isOk() ) { + + const auto isOk = assertionResult.isOk(); + assertionEnded( CATCH_MOVE(assertionResult) ); + if ( !isOk ) { populateReaction( reaction ); } else if ( resultType == ResultWas::ExplicitSkip ) { // TODO: Need to handle this explicitly, as ExplicitSkip is @@ -5585,15 +5692,15 @@ namespace Catch { void RunContext::handleUnexpectedInflightException( AssertionInfo const& info, - std::string const& message, + std::string&& message, AssertionReaction& reaction ) { m_lastAssertionInfo = info; AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); - data.message = message; + data.message = CATCH_MOVE(message); AssertionResult assertionResult{ info, CATCH_MOVE(data) }; - assertionEnded( assertionResult ); + assertionEnded( CATCH_MOVE(assertionResult) ); populateReaction( reaction ); } @@ -5605,12 +5712,13 @@ namespace Catch { void RunContext::handleIncomplete( AssertionInfo const& info ) { + using namespace std::string_literals; m_lastAssertionInfo = info; AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); - data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; + data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s; AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; - assertionEnded( assertionResult ); + assertionEnded( CATCH_MOVE(assertionResult) ); } void RunContext::handleNonExpr( AssertionInfo const &info, @@ -5621,10 +5729,10 @@ namespace Catch { AssertionResultData data( resultType, LazyExpression( false ) ); AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; - assertionEnded( assertionResult ); - if( !assertionResult.isOk() ) - populateReaction( reaction ); + const auto isOk = assertionResult.isOk(); + assertionEnded( CATCH_MOVE(assertionResult) ); + if ( !isOk ) { populateReaction( reaction ); } } @@ -5663,7 +5771,7 @@ namespace Catch { Section::Section( SourceLineInfo const& _lineInfo, StringRef _name, const char* const ): - m_info( { "invalid", static_cast(-1) }, "" ), + m_info( { "invalid", static_cast( -1 ) }, std::string{} ), m_sectionIncluded( getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) { // We delay initialization the SectionInfo member until we know @@ -5793,7 +5901,6 @@ namespace Catch { -#include #include #include #include @@ -5817,9 +5924,9 @@ namespace Catch { return s.find( infix ) != std::string::npos; } void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), []( char c ) { - return toLower( c ); - } ); + for ( char& c : s ) { + c = toLower( c ); + } } std::string toLower( std::string const& s ) { std::string lc = s; @@ -5900,10 +6007,6 @@ namespace Catch { : StringRef( rawChars, std::strlen(rawChars) ) {} - auto StringRef::operator == ( StringRef other ) const noexcept -> bool { - return m_size == other.m_size - && (std::memcmp( m_start, other.m_start, m_size ) == 0); - } bool StringRef::operator<(StringRef rhs) const noexcept { if (m_size < rhs.m_size) { @@ -6037,6 +6140,38 @@ namespace Catch { namespace Catch { + namespace { + static void enforceNoDuplicateTestCases( + std::vector const& tests ) { + auto testInfoCmp = []( TestCaseInfo const* lhs, + TestCaseInfo const* rhs ) { + return *lhs < *rhs; + }; + std::set seenTests( + testInfoCmp ); + for ( auto const& test : tests ) { + const auto infoPtr = &test.getTestCaseInfo(); + const auto prev = seenTests.insert( infoPtr ); + CATCH_ENFORCE( prev.second, + "error: test case \"" + << infoPtr->name << "\", with tags \"" + << infoPtr->tagsAsString() + << "\" already defined.\n" + << "\tFirst seen at " + << ( *prev.first )->lineInfo << "\n" + << "\tRedefined at " << infoPtr->lineInfo ); + } + } + + static bool matchTest( TestCaseHandle const& testCase, + TestSpec const& testSpec, + IConfig const& config ) { + return testSpec.matches( testCase.getTestCaseInfo() ) && + isThrowSafe( testCase, config ); + } + + } // end unnamed namespace + std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { switch (config.runOrder()) { case TestRunOrder::Declared: @@ -6093,29 +6228,6 @@ namespace Catch { return !testCase.getTestCaseInfo().throws() || config.allowThrows(); } - bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ) { - return testSpec.matches( testCase.getTestCaseInfo() ) && isThrowSafe( testCase, config ); - } - - void - enforceNoDuplicateTestCases( std::vector const& tests ) { - auto testInfoCmp = []( TestCaseInfo const* lhs, - TestCaseInfo const* rhs ) { - return *lhs < *rhs; - }; - std::set seenTests(testInfoCmp); - for ( auto const& test : tests ) { - const auto infoPtr = &test.getTestCaseInfo(); - const auto prev = seenTests.insert( infoPtr ); - CATCH_ENFORCE( - prev.second, - "error: test case \"" << infoPtr->name << "\", with tags \"" - << infoPtr->tagsAsString() << "\" already defined.\n" - << "\tFirst seen at " << ( *prev.first )->lineInfo << "\n" - << "\tRedefined at " << infoPtr->lineInfo ); - } - } - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { std::vector filtered; filtered.reserve( testCases.size() ); @@ -6156,13 +6268,6 @@ namespace Catch { return m_sortedFunctions; } - - - /////////////////////////////////////////////////////////////////////////// - void TestInvokerAsFunction::invoke() const { - m_testAsFunction(); - } - } // end namespace Catch @@ -6195,12 +6300,17 @@ namespace TestCaseTracking { m_children.push_back( CATCH_MOVE(child) ); } - ITracker* ITracker::findChild( NameAndLocationRef nameAndLocation ) { + ITracker* ITracker::findChild( NameAndLocationRef const& nameAndLocation ) { auto it = std::find_if( m_children.begin(), m_children.end(), [&nameAndLocation]( ITrackerPtr const& tracker ) { - return tracker->nameAndLocation() == nameAndLocation; + auto const& tnameAndLoc = tracker->nameAndLocation(); + if ( tnameAndLoc.location.line != + nameAndLocation.location.line ) { + return false; + } + return tnameAndLoc == nameAndLocation; } ); return ( it != m_children.end() ) ? it->get() : nullptr; } @@ -6208,10 +6318,6 @@ namespace TestCaseTracking { bool ITracker::isSectionTracker() const { return false; } bool ITracker::isGeneratorTracker() const { return false; } - bool ITracker::isSuccessfullyCompleted() const { - return m_runState == CompletedSuccessfully; - } - bool ITracker::isOpen() const { return m_runState != NotStarted && !isComplete(); } @@ -6238,16 +6344,6 @@ namespace TestCaseTracking { return *m_rootTracker; } - void TrackerContext::endRun() { - m_rootTracker.reset(); - m_currentTracker = nullptr; - m_runState = NotStarted; - } - - void TrackerContext::startCycle() { - m_currentTracker = m_rootTracker.get(); - m_runState = Executing; - } void TrackerContext::completeCycle() { m_runState = CompletedCycle; } @@ -6255,9 +6351,6 @@ namespace TestCaseTracking { bool TrackerContext::completedCycle() const { return m_runState == CompletedCycle; } - ITracker& TrackerContext::currentTracker() { - return *m_currentTracker; - } void TrackerContext::setCurrentTracker( ITracker* tracker ) { m_currentTracker = tracker; } @@ -6326,7 +6419,7 @@ namespace TestCaseTracking { SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ) : TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ), - m_trimmed_name(trim(ITracker::nameAndLocation().name)) + m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name))) { if( parent ) { while ( !parent->isSectionTracker() ) { @@ -6351,7 +6444,7 @@ namespace TestCaseTracking { bool SectionTracker::isSectionTracker() const { return true; } - SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef nameAndLocation ) { + SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ) { SectionTracker* tracker; ITracker& currentTracker = ctx.currentTracker(); @@ -6395,10 +6488,6 @@ namespace TestCaseTracking { m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); } - std::vector const& SectionTracker::getFilters() const { - return m_filters; - } - StringRef SectionTracker::trimmedName() const { return m_trimmed_name; } @@ -6424,6 +6513,14 @@ namespace Catch { #endif } + void throw_test_skip_exception() { +#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) + throw Catch::TestSkipException(); +#else + CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" ); +#endif + } + } // namespace Catch @@ -6432,9 +6529,10 @@ namespace Catch { #include namespace Catch { + ITestInvoker::~ITestInvoker() = default; namespace { - StringRef extractClassName( StringRef classOrMethodName ) { + static StringRef extractClassName( StringRef classOrMethodName ) { if ( !startsWith( classOrMethodName, '&' ) ) { return classOrMethodName; } @@ -6461,6 +6559,18 @@ namespace Catch { static_cast( startIdx ), static_cast( classNameSize ) ); } + + class TestInvokerAsFunction final : public ITestInvoker { + using TestType = void ( * )(); + TestType m_testAsFunction; + + public: + TestInvokerAsFunction( TestType testAsFunction ) noexcept: + m_testAsFunction( testAsFunction ) {} + + void invoke() const override { m_testAsFunction(); } + }; + } // namespace Detail::unique_ptr makeTestInvoker( void(*testAsFunction)() ) { @@ -6697,10 +6807,8 @@ namespace Catch { token.erase(token.begin()); if (m_exclusion) { m_currentFilter.m_forbidden.emplace_back(Detail::make_unique(".", m_substring)); - m_currentFilter.m_forbidden.emplace_back(Detail::make_unique(token, m_substring)); } else { m_currentFilter.m_required.emplace_back(Detail::make_unique(".", m_substring)); - m_currentFilter.m_required.emplace_back(Detail::make_unique(token, m_substring)); } } if (m_exclusion) { @@ -7643,7 +7751,19 @@ WithinRelMatcher WithinRel(float target) { } -} // namespace Matchers + +bool IsNaNMatcher::match( double const& matchee ) const { + return std::isnan( matchee ); +} + +std::string IsNaNMatcher::describe() const { + using namespace std::string_literals; + return "is NaN"s; +} + +IsNaNMatcher IsNaN() { return IsNaNMatcher(); } + + } // namespace Matchers } // namespace Catch @@ -8059,7 +8179,7 @@ class AssertionPrinter { return; const auto itEnd = messages.cend(); - const auto N = static_cast(std::distance(itMessage, itEnd)); + const auto N = static_cast(itEnd - itMessage); stream << colourImpl->guardColour( colour ) << " with " << pluralise( N, "message"_sr ) << ':'; @@ -8080,7 +8200,7 @@ class AssertionPrinter { private: std::ostream& stream; AssertionResult const& result; - std::vector messages; + std::vector const& messages; std::vector::const_iterator itMessage; bool printInfoMessages; ColourImpl* colourImpl; @@ -8174,7 +8294,6 @@ class ConsoleAssertionPrinter { stats(_stats), result(_stats.assertionResult), colour(Colour::None), - message(result.getMessage()), messages(_stats.infoMessages), colourImpl(colourImpl_), printInfoMessages(_printInfoMessages) { @@ -8183,10 +8302,10 @@ class ConsoleAssertionPrinter { colour = Colour::Success; passOrFail = "PASSED"_sr; //if( result.hasMessage() ) - if (_stats.infoMessages.size() == 1) - messageLabel = "with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "with messages"; + if (messages.size() == 1) + messageLabel = "with message"_sr; + if (messages.size() > 1) + messageLabel = "with messages"_sr; break; case ResultWas::ExpressionFailed: if (result.isOk()) { @@ -8196,51 +8315,57 @@ class ConsoleAssertionPrinter { colour = Colour::Error; passOrFail = "FAILED"_sr; } - if (_stats.infoMessages.size() == 1) - messageLabel = "with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "with messages"; + if (messages.size() == 1) + messageLabel = "with message"_sr; + if (messages.size() > 1) + messageLabel = "with messages"_sr; break; case ResultWas::ThrewException: colour = Colour::Error; passOrFail = "FAILED"_sr; - messageLabel = "due to unexpected exception with "; - if (_stats.infoMessages.size() == 1) - messageLabel += "message"; - if (_stats.infoMessages.size() > 1) - messageLabel += "messages"; + // todo switch + switch (messages.size()) { case 0: + messageLabel = "due to unexpected exception with "_sr; + break; + case 1: + messageLabel = "due to unexpected exception with message"_sr; + break; + default: + messageLabel = "due to unexpected exception with messages"_sr; + break; + } break; case ResultWas::FatalErrorCondition: colour = Colour::Error; passOrFail = "FAILED"_sr; - messageLabel = "due to a fatal error condition"; + messageLabel = "due to a fatal error condition"_sr; break; case ResultWas::DidntThrowException: colour = Colour::Error; passOrFail = "FAILED"_sr; - messageLabel = "because no exception was thrown where one was expected"; + messageLabel = "because no exception was thrown where one was expected"_sr; break; case ResultWas::Info: - messageLabel = "info"; + messageLabel = "info"_sr; break; case ResultWas::Warning: - messageLabel = "warning"; + messageLabel = "warning"_sr; break; case ResultWas::ExplicitFailure: passOrFail = "FAILED"_sr; colour = Colour::Error; - if (_stats.infoMessages.size() == 1) - messageLabel = "explicitly with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "explicitly with messages"; + if (messages.size() == 1) + messageLabel = "explicitly with message"_sr; + if (messages.size() > 1) + messageLabel = "explicitly with messages"_sr; break; case ResultWas::ExplicitSkip: colour = Colour::Skip; passOrFail = "SKIPPED"_sr; - if (_stats.infoMessages.size() == 1) - messageLabel = "explicitly with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "explicitly with messages"; + if (messages.size() == 1) + messageLabel = "explicitly with message"_sr; + if (messages.size() > 1) + messageLabel = "explicitly with messages"_sr; break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: @@ -8304,9 +8429,8 @@ class ConsoleAssertionPrinter { AssertionResult const& result; Colour::Code colour; StringRef passOrFail; - std::string messageLabel; - std::string message; - std::vector messages; + StringRef messageLabel; + std::vector const& messages; ColourImpl* colourImpl; bool printInfoMessages; }; @@ -9308,6 +9432,8 @@ namespace Catch { gmtime_s(&timeInfo, &rawtime); #elif defined (CATCH_PLATFORM_PLAYSTATION) gmtime_s(&rawtime, &timeInfo); +#elif defined (__IAR_SYSTEMS_ICC__) + timeInfo = *std::gmtime(&rawtime); #else gmtime_r(&rawtime, &timeInfo); #endif @@ -9568,7 +9694,7 @@ namespace Catch { } } - if( !result.getMessage().empty() ) + if( result.hasMessage() ) rss << result.getMessage() << '\n'; for( auto const& msg : stats.infoMessages ) if( msg.type == ResultWas::Info ) @@ -9687,7 +9813,6 @@ namespace Catch { } } - // The return value indicates if the messages buffer should be cleared: void MultiReporter::assertionEnded( AssertionStats const& assertionStats ) { const bool reportByDefault = assertionStats.assertionResult.getResultType() != ResultWas::Ok || @@ -9790,6 +9915,11 @@ namespace Catch { } } + void registerListenerImpl( Detail::unique_ptr listenerFactory ) { + getMutableRegistryHub().registerListener( CATCH_MOVE(listenerFactory) ); + } + + } // namespace Detail } // namespace Catch @@ -9929,7 +10059,7 @@ namespace Catch { } } - if (!result.getMessage().empty()) + if (result.hasMessage()) textRss << result.getMessage() << '\n'; for (auto const& msg : stats.infoMessages) @@ -9963,7 +10093,6 @@ namespace Catch { #include -#include #include namespace Catch { @@ -10114,7 +10243,7 @@ namespace Catch { // using messages.end() directly (or auto) yields compilation error: std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast(std::distance(itMessage, itEnd)); + const std::size_t N = static_cast(itEnd - itMessage); stream << colourImpl->guardColour( colour ) << " with " << pluralise( N, "message"_sr ) << ':'; @@ -10133,7 +10262,7 @@ namespace Catch { private: std::ostream& stream; AssertionResult const& result; - std::vector messages; + std::vector const& messages; std::vector::const_iterator itMessage; bool printInfoMessages; std::size_t counter; @@ -10386,7 +10515,7 @@ namespace Catch { m_xml.startElement("Catch2TestRun") .writeAttribute("name"_sr, m_config->name()) .writeAttribute("rng-seed"_sr, m_config->rngSeed()) - .writeAttribute("xml-format-version"_sr, 2) + .writeAttribute("xml-format-version"_sr, 3) .writeAttribute("catch2-version"_sr, libraryVersion()); if ( m_config->testSpec().hasFilters() ) { m_xml.writeAttribute( "filters"_sr, m_config->testSpec() ); @@ -10396,7 +10525,7 @@ namespace Catch { void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ) - .writeAttribute( "name"_sr, trim( testInfo.name ) ) + .writeAttribute( "name"_sr, trim( StringRef(testInfo.name) ) ) .writeAttribute( "tags"_sr, testInfo.tagsAsString() ); writeSourceInfo( testInfo.lineInfo ); @@ -10410,7 +10539,7 @@ namespace Catch { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) - .writeAttribute( "name"_sr, trim( sectionInfo.name ) ); + .writeAttribute( "name"_sr, trim( StringRef(sectionInfo.name) ) ); writeSourceInfo( sectionInfo.lineInfo ); m_xml.ensureTagClosed(); } @@ -10428,11 +10557,13 @@ namespace Catch { // Print any info messages in tags. for( auto const& msg : assertionStats.infoMessages ) { if( msg.type == ResultWas::Info && includeResults ) { - m_xml.scopedElement( "Info" ) - .writeText( msg.message ); + auto t = m_xml.scopedElement( "Info" ); + writeSourceInfo( msg.lineInfo ); + t.writeText( msg.message ); } else if ( msg.type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( msg.message ); + auto t = m_xml.scopedElement( "Warning" ); + writeSourceInfo( msg.lineInfo ); + t.writeText( msg.message ); } } } @@ -10524,11 +10655,10 @@ namespace Catch { if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() ); - if( !testCaseStats.stdOut.empty() ) - m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline ); + m_xml.scopedElement( "StdOut" ).writeText( trim( StringRef(testCaseStats.stdOut) ), XmlFormatting::Newline ); if( !testCaseStats.stdErr.empty() ) - m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline ); + m_xml.scopedElement( "StdErr" ).writeText( trim( StringRef(testCaseStats.stdErr) ), XmlFormatting::Newline ); m_xml.endElement(); } diff --git a/Framework/Foundation/3rdparty/catch2/catch_amalgamated.hpp b/Framework/Foundation/3rdparty/catch2/catch_amalgamated.hpp index 88f2dd912c83c..694fe1e4d81b3 100644 --- a/Framework/Foundation/3rdparty/catch2/catch_amalgamated.hpp +++ b/Framework/Foundation/3rdparty/catch2/catch_amalgamated.hpp @@ -5,8 +5,8 @@ // SPDX-License-Identifier: BSL-1.0 -// Catch v3.3.1 -// Generated: 2023-01-29 22:55:03.856079 +// Catch v3.4.0 +// Generated: 2023-07-13 13:23:07.577770 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -59,233 +59,6 @@ -#ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED -#define CATCH_INTERFACES_CONFIG_HPP_INCLUDED - - - -#ifndef CATCH_NONCOPYABLE_HPP_INCLUDED -#define CATCH_NONCOPYABLE_HPP_INCLUDED - -namespace Catch { - namespace Detail { - - //! Deriving classes become noncopyable and nonmovable - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable&& ) = delete; - NonCopyable& operator=( NonCopyable const& ) = delete; - NonCopyable& operator=( NonCopyable&& ) = delete; - - protected: - NonCopyable() noexcept = default; - }; - - } // namespace Detail -} // namespace Catch - -#endif // CATCH_NONCOPYABLE_HPP_INCLUDED - - -#ifndef CATCH_STRINGREF_HPP_INCLUDED -#define CATCH_STRINGREF_HPP_INCLUDED - -#include -#include -#include -#include - -namespace Catch { - - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. - class StringRef { - public: - using size_type = std::size_t; - using const_iterator = const char*; - - private: - static constexpr char const* const s_empty = ""; - - char const* m_start = s_empty; - size_type m_size = 0; - - public: // construction - constexpr StringRef() noexcept = default; - - StringRef( char const* rawChars ) noexcept; - - constexpr StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - {} - - StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} - - explicit operator std::string() const { - return std::string(m_start, m_size); - } - - public: // operators - auto operator == ( StringRef other ) const noexcept -> bool; - auto operator != (StringRef other) const noexcept -> bool { - return !(*this == other); - } - - constexpr auto operator[] ( size_type index ) const noexcept -> char { - assert(index < m_size); - return m_start[index]; - } - - bool operator<(StringRef rhs) const noexcept; - - public: // named queries - constexpr auto empty() const noexcept -> bool { - return m_size == 0; - } - constexpr auto size() const noexcept -> size_type { - return m_size; - } - - // Returns a substring of [start, start + length). - // If start + length > size(), then the substring is [start, start + size()). - // If start > size(), then the substring is empty. - constexpr StringRef substr(size_type start, size_type length) const noexcept { - if (start < m_size) { - const auto shortened_size = m_size - start; - return StringRef(m_start + start, (shortened_size < length) ? shortened_size : length); - } else { - return StringRef(); - } - } - - // Returns the current start pointer. May not be null-terminated. - constexpr char const* data() const noexcept { - return m_start; - } - - constexpr const_iterator begin() const { return m_start; } - constexpr const_iterator end() const { return m_start + m_size; } - - - friend std::string& operator += (std::string& lhs, StringRef sr); - friend std::ostream& operator << (std::ostream& os, StringRef sr); - friend std::string operator+(StringRef lhs, StringRef rhs); - - /** - * Provides a three-way comparison with rhs - * - * Returns negative number if lhs < rhs, 0 if lhs == rhs, and a positive - * number if lhs > rhs - */ - int compare( StringRef rhs ) const; - }; - - - constexpr auto operator ""_sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { - return StringRef( rawChars, size ); - } -} // namespace Catch - -constexpr auto operator ""_catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { - return Catch::StringRef( rawChars, size ); -} - -#endif // CATCH_STRINGREF_HPP_INCLUDED - -#include -#include -#include -#include - -namespace Catch { - - enum class Verbosity { - Quiet = 0, - Normal, - High - }; - - struct WarnAbout { enum What { - Nothing = 0x00, - //! A test case or leaf section did not run any assertions - NoAssertions = 0x01, - //! A command line test spec matched no test cases - UnmatchedTestSpec = 0x02, - }; }; - - enum class ShowDurations { - DefaultForReporter, - Always, - Never - }; - enum class TestRunOrder { - Declared, - LexicographicallySorted, - Randomized - }; - enum class ColourMode : std::uint8_t { - //! Let Catch2 pick implementation based on platform detection - PlatformDefault, - //! Use ANSI colour code escapes - ANSI, - //! Use Win32 console colour API - Win32, - //! Don't use any colour - None - }; - struct WaitForKeypress { enum When { - Never, - BeforeStart = 1, - BeforeExit = 2, - BeforeStartAndExit = BeforeStart | BeforeExit - }; }; - - class TestSpec; - class IStream; - - class IConfig : public Detail::NonCopyable { - public: - virtual ~IConfig(); - - virtual bool allowThrows() const = 0; - virtual StringRef name() const = 0; - virtual bool includeSuccessfulResults() const = 0; - virtual bool shouldDebugBreak() const = 0; - virtual bool warnAboutMissingAssertions() const = 0; - virtual bool warnAboutUnmatchedTestSpecs() const = 0; - virtual bool zeroTestsCountAsSuccess() const = 0; - virtual int abortAfter() const = 0; - virtual bool showInvisibles() const = 0; - virtual ShowDurations showDurations() const = 0; - virtual double minDuration() const = 0; - virtual TestSpec const& testSpec() const = 0; - virtual bool hasTestFilters() const = 0; - virtual std::vector const& getTestsOrTags() const = 0; - virtual TestRunOrder runOrder() const = 0; - virtual uint32_t rngSeed() const = 0; - virtual unsigned int shardCount() const = 0; - virtual unsigned int shardIndex() const = 0; - virtual ColourMode defaultColourMode() const = 0; - virtual std::vector const& getSectionsToRun() const = 0; - virtual Verbosity verbosity() const = 0; - - virtual bool skipBenchmarks() const = 0; - virtual bool benchmarkNoAnalysis() const = 0; - virtual unsigned int benchmarkSamples() const = 0; - virtual double benchmarkConfidenceInterval() const = 0; - virtual unsigned int benchmarkResamples() const = 0; - virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0; - }; -} - -#endif // CATCH_INTERFACES_CONFIG_HPP_INCLUDED - - #ifndef CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED #define CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED @@ -352,7 +125,7 @@ namespace Catch { // Only GCC compiler should be used in this block, so other compilers trying to // mask themselves as GCC should be ignored. -#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) && !defined(__NVCOMPILER) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) @@ -361,16 +134,28 @@ namespace Catch { # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ + _Pragma( "GCC diagnostic ignored \"-Wunused-result\"" ) + # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ _Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" ) # define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ _Pragma( "GCC diagnostic ignored \"-Wuseless-cast\"" ) +# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + _Pragma( "GCC diagnostic ignored \"-Wshadow\"" ) + # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) #endif +#if defined(__NVCOMPILER) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "diag push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "diag pop" ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress declared_but_not_referenced" ) +#endif + #if defined(__CUDACC__) && !defined(__clang__) # ifdef __NVCC_DIAG_PRAGMA_SUPPORT__ // New pragmas introduced in CUDA 11.5+ @@ -433,6 +218,9 @@ namespace Catch { # define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wcomma\"" ) +# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wshadow\"" ) + #endif // __clang__ @@ -670,6 +458,9 @@ namespace Catch { #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS #endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS #endif @@ -679,6 +470,16 @@ namespace Catch { #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS #endif +#if !defined( CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif +#if !defined( CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS ) +# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS +#endif +#if !defined( CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS ) +# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS +#endif + // The goal of this macro is to avoid evaluation of the arguments, but // still have the compiler warn on problems inside... @@ -692,13 +493,6 @@ namespace Catch { # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if !defined(CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS -#endif #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) #define CATCH_TRY if ((true)) @@ -744,38 +538,31 @@ namespace Catch { class IResultCapture; class IConfig; - class IContext { - public: - virtual ~IContext(); // = default + class Context { + IConfig const* m_config = nullptr; + IResultCapture* m_resultCapture = nullptr; - virtual IResultCapture* getResultCapture() = 0; - virtual IConfig const* getConfig() const = 0; - }; + CATCH_EXPORT static Context* currentContext; + friend Context& getCurrentMutableContext(); + friend Context const& getCurrentContext(); + static void createContext(); + friend void cleanUpContext(); - class IMutableContext : public IContext { public: - ~IMutableContext() override; // = default - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setConfig( IConfig const* config ) = 0; - - private: - CATCH_EXPORT static IMutableContext* currentContext; - friend IMutableContext& getCurrentMutableContext(); - friend void cleanUpContext(); - static void createContext(); + IResultCapture* getResultCapture() const { return m_resultCapture; } + IConfig const* getConfig() const { return m_config; } + void setResultCapture( IResultCapture* resultCapture ); + void setConfig( IConfig const* config ); }; - inline IMutableContext& getCurrentMutableContext() - { - if( !IMutableContext::currentContext ) - IMutableContext::createContext(); - // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) - return *IMutableContext::currentContext; - } + Context& getCurrentMutableContext(); - inline IContext& getCurrentContext() - { - return getCurrentMutableContext(); + inline Context const& getCurrentContext() { + // We duplicate the logic from `getCurrentMutableContext` here, + // to avoid paying the call overhead in debug mode. + if ( !Context::currentContext ) { Context::createContext(); } + // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) + return *Context::currentContext; } void cleanUpContext(); @@ -787,18 +574,8 @@ namespace Catch { #endif // CATCH_CONTEXT_HPP_INCLUDED -#ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED -#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED - - - -#ifndef CATCH_SECTION_INFO_HPP_INCLUDED -#define CATCH_SECTION_INFO_HPP_INCLUDED - - - -#ifndef CATCH_MOVE_AND_FORWARD_HPP_INCLUDED -#define CATCH_MOVE_AND_FORWARD_HPP_INCLUDED +#ifndef CATCH_MOVE_AND_FORWARD_HPP_INCLUDED +#define CATCH_MOVE_AND_FORWARD_HPP_INCLUDED #include @@ -811,110 +588,199 @@ namespace Catch { #endif // CATCH_MOVE_AND_FORWARD_HPP_INCLUDED -#ifndef CATCH_SOURCE_LINE_INFO_HPP_INCLUDED -#define CATCH_SOURCE_LINE_INFO_HPP_INCLUDED - -#include -#include +#ifndef CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED +#define CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED namespace Catch { - struct SourceLineInfo { + //! Used to signal that an assertion macro failed + struct TestFailureException{}; + //! Used to signal that the remainder of a test should be skipped + struct TestSkipException {}; - SourceLineInfo() = delete; - constexpr SourceLineInfo( char const* _file, std::size_t _line ) noexcept: - file( _file ), - line( _line ) - {} + /** + * Outlines throwing of `TestFailureException` into a single TU + * + * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers. + */ + [[noreturn]] void throw_test_failure_exception(); - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; + /** + * Outlines throwing of `TestSkipException` into a single TU + * + * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers. + */ + [[noreturn]] void throw_test_skip_exception(); - char const* file; - std::size_t line; +} // namespace Catch - friend std::ostream& operator << (std::ostream& os, SourceLineInfo const& info); - }; -} +#endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) -#endif // CATCH_SOURCE_LINE_INFO_HPP_INCLUDED +#ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED +#define CATCH_UNIQUE_NAME_HPP_INCLUDED -#ifndef CATCH_TOTALS_HPP_INCLUDED -#define CATCH_TOTALS_HPP_INCLUDED -#include -namespace Catch { +/** \file + * Wrapper for the CONFIG configuration option + * + * When generating internal unique names, there are two options. Either + * we mix in the current line number, or mix in an incrementing number. + * We prefer the latter, using `__COUNTER__`, but users might want to + * use the former. + */ - struct Counts { - Counts operator - ( Counts const& other ) const; - Counts& operator += ( Counts const& other ); +#ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED +#define CATCH_CONFIG_COUNTER_HPP_INCLUDED - std::uint64_t total() const; - bool allPassed() const; - bool allOk() const; - std::uint64_t passed = 0; - std::uint64_t failed = 0; - std::uint64_t failedButOk = 0; - std::uint64_t skipped = 0; - }; +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif - struct Totals { +#if defined( CATCH_INTERNAL_CONFIG_COUNTER ) && \ + !defined( CATCH_CONFIG_NO_COUNTER ) && \ + !defined( CATCH_CONFIG_COUNTER ) +# define CATCH_CONFIG_COUNTER +#endif - Totals operator - ( Totals const& other ) const; - Totals& operator += ( Totals const& other ); - Totals delta( Totals const& prevTotals ) const; +#endif // CATCH_CONFIG_COUNTER_HPP_INCLUDED +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif - Counts assertions; - Counts testCases; - }; -} +#endif // CATCH_UNIQUE_NAME_HPP_INCLUDED -#endif // CATCH_TOTALS_HPP_INCLUDED +#ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED +#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED + +#include +#include + + + +#ifndef CATCH_STRINGREF_HPP_INCLUDED +#define CATCH_STRINGREF_HPP_INCLUDED + +#include #include +#include +#include + +#include namespace Catch { - struct SectionInfo { - // The last argument is ignored, so that people can write - // SECTION("ShortName", "Proper description that is long") and - // still use the `-c` flag comfortably. - SectionInfo( SourceLineInfo const& _lineInfo, std::string _name, - const char* const = nullptr ): - name(CATCH_MOVE(_name)), - lineInfo(_lineInfo) - {} + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char*; - std::string name; - SourceLineInfo lineInfo; - }; + private: + static constexpr char const* const s_empty = ""; - struct SectionEndInfo { - SectionInfo sectionInfo; - Counts prevAssertions; - double durationInSeconds; - }; + char const* m_start = s_empty; + size_type m_size = 0; -} // end namespace Catch + public: // construction + constexpr StringRef() noexcept = default; -#endif // CATCH_SECTION_INFO_HPP_INCLUDED + StringRef( char const* rawChars ) noexcept; + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} -#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED -#define CATCH_ASSERTION_RESULT_HPP_INCLUDED + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + explicit operator std::string() const { + return std::string(m_start, m_size); + } + + public: // operators + auto operator == ( StringRef other ) const noexcept -> bool { + return m_size == other.m_size + && (std::memcmp( m_start, other.m_start, m_size ) == 0); + } + auto operator != (StringRef other) const noexcept -> bool { + return !(*this == other); + } + constexpr auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } -#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED -#define CATCH_ASSERTION_INFO_HPP_INCLUDED + bool operator<(StringRef rhs) const noexcept; + + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } + + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, start + size()). + // If start > size(), then the substring is empty. + constexpr StringRef substr(size_type start, size_type length) const noexcept { + if (start < m_size) { + const auto shortened_size = m_size - start; + return StringRef(m_start + start, (shortened_size < length) ? shortened_size : length); + } else { + return StringRef(); + } + } + + // Returns the current start pointer. May not be null-terminated. + constexpr char const* data() const noexcept { + return m_start; + } + + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + + + friend std::string& operator += (std::string& lhs, StringRef sr); + friend std::ostream& operator << (std::ostream& os, StringRef sr); + friend std::string operator+(StringRef lhs, StringRef rhs); + + /** + * Provides a three-way comparison with rhs + * + * Returns negative number if lhs < rhs, 0 if lhs == rhs, and a positive + * number if lhs > rhs + */ + int compare( StringRef rhs ) const; + }; + + + constexpr auto operator ""_sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch +constexpr auto operator ""_catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + +#endif // CATCH_STRINGREF_HPP_INCLUDED #ifndef CATCH_RESULT_TYPE_HPP_INCLUDED @@ -968,120 +834,12 @@ namespace Catch { #endif // CATCH_RESULT_TYPE_HPP_INCLUDED -namespace Catch { - - struct AssertionInfo { - // AssertionInfo() = delete; - - StringRef macroName; - SourceLineInfo lineInfo; - StringRef capturedExpression; - ResultDisposition::Flags resultDisposition; - }; - -} // end namespace Catch - -#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED +#ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED +#define CATCH_UNIQUE_PTR_HPP_INCLUDED -#ifndef CATCH_LAZY_EXPR_HPP_INCLUDED -#define CATCH_LAZY_EXPR_HPP_INCLUDED - -#include - -namespace Catch { - - class ITransientExpression; - - class LazyExpression { - friend class AssertionHandler; - friend struct AssertionStats; - friend class RunContext; - - ITransientExpression const* m_transientExpression = nullptr; - bool m_isNegated; - public: - LazyExpression( bool isNegated ): - m_isNegated(isNegated) - {} - LazyExpression(LazyExpression const& other) = default; - LazyExpression& operator = ( LazyExpression const& ) = delete; - - explicit operator bool() const { - return m_transientExpression != nullptr; - } - - friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; - }; - -} // namespace Catch - -#endif // CATCH_LAZY_EXPR_HPP_INCLUDED - -#include - -namespace Catch { - - struct AssertionResultData - { - AssertionResultData() = delete; - - AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); - - std::string message; - mutable std::string reconstructedExpression; - LazyExpression lazyExpression; - ResultWas::OfType resultType; - - std::string reconstructExpression() const; - }; - - class AssertionResult { - public: - AssertionResult() = delete; - AssertionResult( AssertionInfo const& info, AssertionResultData&& data ); - - bool isOk() const; - bool succeeded() const; - ResultWas::OfType getResultType() const; - bool hasExpression() const; - bool hasMessage() const; - std::string getExpression() const; - std::string getExpressionInMacro() const; - bool hasExpandedExpression() const; - std::string getExpandedExpression() const; - StringRef getMessage() const; - SourceLineInfo getSourceInfo() const; - StringRef getTestMacroName() const; - - //protected: - AssertionInfo m_info; - AssertionResultData m_resultData; - }; - -} // end namespace Catch - -#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED - - -#ifndef CATCH_MESSAGE_INFO_HPP_INCLUDED -#define CATCH_MESSAGE_INFO_HPP_INCLUDED - - - -#ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED -#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED - -#include -#include - - - -#ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED -#define CATCH_UNIQUE_PTR_HPP_INCLUDED - -#include -#include +#include +#include namespace Catch { @@ -1188,6 +946,24 @@ namespace Detail { #endif // CATCH_UNIQUE_PTR_HPP_INCLUDED + +#ifndef CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED +#define CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED + +#include + +namespace Catch { + + // We cannot forward declare the type with default template argument + // multiple times, so it is split out into a separate header so that + // we can prevent multiple declarations in dependees + template > + struct BenchmarkStats; + +} // end namespace Catch + +#endif // CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED + namespace Catch { class AssertionResult; @@ -1204,8 +980,6 @@ namespace Catch { class IGeneratorTracker; struct BenchmarkInfo; - template > - struct BenchmarkStats; namespace Generators { class GeneratorUntypedBase; @@ -1217,6 +991,7 @@ namespace Catch { public: virtual ~IResultCapture(); + virtual void notifyAssertionStarted( AssertionInfo const& info ) = 0; virtual bool sectionStarted( StringRef sectionName, SourceLineInfo const& sectionLineInfo, Counts& assertions ) = 0; @@ -1257,7 +1032,7 @@ namespace Catch { AssertionReaction& reaction ) = 0; virtual void handleUnexpectedInflightException ( AssertionInfo const& info, - std::string const& message, + std::string&& message, AssertionReaction& reaction ) = 0; virtual void handleIncomplete ( AssertionInfo const& info ) = 0; @@ -1282,179 +1057,242 @@ namespace Catch { #endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED -#include - -namespace Catch { - - struct MessageInfo { - MessageInfo( StringRef _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ); - - StringRef macroName; - std::string message; - SourceLineInfo lineInfo; - ResultWas::OfType type; - unsigned int sequence; - - bool operator == (MessageInfo const& other) const { - return sequence == other.sequence; - } - bool operator < (MessageInfo const& other) const { - return sequence < other.sequence; - } - private: - static unsigned int globalCount; - }; - -} // end namespace Catch -#endif // CATCH_MESSAGE_INFO_HPP_INCLUDED +#ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED +#define CATCH_INTERFACES_CONFIG_HPP_INCLUDED -// Adapted from donated nonius code. -#ifndef CATCH_ESTIMATE_HPP_INCLUDED -#define CATCH_ESTIMATE_HPP_INCLUDED +#ifndef CATCH_NONCOPYABLE_HPP_INCLUDED +#define CATCH_NONCOPYABLE_HPP_INCLUDED namespace Catch { - namespace Benchmark { - template - struct Estimate { - Duration point; - Duration lower_bound; - Duration upper_bound; - double confidence_interval; - - template - operator Estimate() const { - return { point, lower_bound, upper_bound, confidence_interval }; - } - }; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_ESTIMATE_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED -#define CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED + namespace Detail { -namespace Catch { - namespace Benchmark { - struct OutlierClassification { - int samples_seen = 0; - int low_severe = 0; // more than 3 times IQR below Q1 - int low_mild = 0; // 1.5 to 3 times IQR below Q1 - int high_mild = 0; // 1.5 to 3 times IQR above Q3 - int high_severe = 0; // more than 3 times IQR above Q3 + //! Deriving classes become noncopyable and nonmovable + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable&& ) = delete; + NonCopyable& operator=( NonCopyable const& ) = delete; + NonCopyable& operator=( NonCopyable&& ) = delete; - int total() const { - return low_severe + low_mild + high_mild + high_severe; - } + protected: + NonCopyable() noexcept = default; }; - } // namespace Benchmark -} // namespace Catch -#endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED + } // namespace Detail +} // namespace Catch +#endif // CATCH_NONCOPYABLE_HPP_INCLUDED -#include +#include +#include #include #include -#include namespace Catch { - struct ReporterDescription; - struct ListenerDescription; - struct TagInfo; - struct TestCaseInfo; - class TestCaseHandle; - class IConfig; - class IStream; - enum class ColourMode : std::uint8_t; - - struct ReporterConfig { - ReporterConfig( IConfig const* _fullConfig, - Detail::unique_ptr _stream, - ColourMode colourMode, - std::map customOptions ); - - ReporterConfig( ReporterConfig&& ) = default; - ReporterConfig& operator=( ReporterConfig&& ) = default; - ~ReporterConfig(); // = default - - Detail::unique_ptr takeStream() &&; - IConfig const* fullConfig() const; - ColourMode colourMode() const; - std::map const& customOptions() const; - - private: - Detail::unique_ptr m_stream; - IConfig const* m_fullConfig; - ColourMode m_colourMode; - std::map m_customOptions; - }; - - struct TestRunInfo { - constexpr TestRunInfo(StringRef _name) : name(_name) {} - StringRef name; + enum class Verbosity { + Quiet = 0, + Normal, + High }; - struct AssertionStats { - AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ); - - AssertionStats( AssertionStats const& ) = default; - AssertionStats( AssertionStats && ) = default; - AssertionStats& operator = ( AssertionStats const& ) = delete; - AssertionStats& operator = ( AssertionStats && ) = delete; + struct WarnAbout { enum What { + Nothing = 0x00, + //! A test case or leaf section did not run any assertions + NoAssertions = 0x01, + //! A command line test spec matched no test cases + UnmatchedTestSpec = 0x02, + }; }; - AssertionResult assertionResult; - std::vector infoMessages; - Totals totals; + enum class ShowDurations { + DefaultForReporter, + Always, + Never }; - - struct SectionStats { - SectionStats( SectionInfo&& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ); - - SectionInfo sectionInfo; - Counts assertions; - double durationInSeconds; - bool missingAssertions; + enum class TestRunOrder { + Declared, + LexicographicallySorted, + Randomized + }; + enum class ColourMode : std::uint8_t { + //! Let Catch2 pick implementation based on platform detection + PlatformDefault, + //! Use ANSI colour code escapes + ANSI, + //! Use Win32 console colour API + Win32, + //! Don't use any colour + None }; + struct WaitForKeypress { enum When { + Never, + BeforeStart = 1, + BeforeExit = 2, + BeforeStartAndExit = BeforeStart | BeforeExit + }; }; - struct TestCaseStats { - TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ); + class TestSpec; + class IStream; - TestCaseInfo const * testInfo; - Totals totals; - std::string stdOut; - std::string stdErr; - bool aborting; + class IConfig : public Detail::NonCopyable { + public: + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual StringRef name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual bool warnAboutUnmatchedTestSpecs() const = 0; + virtual bool zeroTestsCountAsSuccess() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations showDurations() const = 0; + virtual double minDuration() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual bool hasTestFilters() const = 0; + virtual std::vector const& getTestsOrTags() const = 0; + virtual TestRunOrder runOrder() const = 0; + virtual uint32_t rngSeed() const = 0; + virtual unsigned int shardCount() const = 0; + virtual unsigned int shardIndex() const = 0; + virtual ColourMode defaultColourMode() const = 0; + virtual std::vector const& getSectionsToRun() const = 0; + virtual Verbosity verbosity() const = 0; + + virtual bool skipBenchmarks() const = 0; + virtual bool benchmarkNoAnalysis() const = 0; + virtual unsigned int benchmarkSamples() const = 0; + virtual double benchmarkConfidenceInterval() const = 0; + virtual unsigned int benchmarkResamples() const = 0; + virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0; }; +} - struct TestRunStats { - TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ); +#endif // CATCH_INTERFACES_CONFIG_HPP_INCLUDED - TestRunInfo runInfo; - Totals totals; - bool aborting; + +#ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED +#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED + + +#include + +namespace Catch { + + class TestCaseHandle; + struct TestCaseInfo; + class ITestCaseRegistry; + class IExceptionTranslatorRegistry; + class IExceptionTranslator; + class ReporterRegistry; + class IReporterFactory; + class ITagAliasRegistry; + class ITestInvoker; + class IMutableEnumValuesRegistry; + struct SourceLineInfo; + + class StartupExceptionRegistry; + class EventListenerFactory; + + using IReporterFactoryPtr = Detail::unique_ptr; + + class IRegistryHub { + public: + virtual ~IRegistryHub(); // = default + + virtual ReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; + virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; + + + virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; + }; + + class IMutableRegistryHub { + public: + virtual ~IMutableRegistryHub(); // = default + virtual void registerReporter( std::string const& name, IReporterFactoryPtr factory ) = 0; + virtual void registerListener( Detail::unique_ptr factory ) = 0; + virtual void registerTest(Detail::unique_ptr&& testInfo, Detail::unique_ptr&& invoker) = 0; + virtual void registerTranslator( Detail::unique_ptr&& translator ) = 0; + virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; + virtual void registerStartupException() noexcept = 0; + virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0; }; + IRegistryHub const& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +#endif // CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED + + +#ifndef CATCH_BENCHMARK_STATS_HPP_INCLUDED +#define CATCH_BENCHMARK_STATS_HPP_INCLUDED + + + +// Adapted from donated nonius code. + +#ifndef CATCH_ESTIMATE_HPP_INCLUDED +#define CATCH_ESTIMATE_HPP_INCLUDED + +namespace Catch { + namespace Benchmark { + template + struct Estimate { + Duration point; + Duration lower_bound; + Duration upper_bound; + double confidence_interval; + + template + operator Estimate() const { + return { point, lower_bound, upper_bound, confidence_interval }; + } + }; + } // namespace Benchmark +} // namespace Catch + +#endif // CATCH_ESTIMATE_HPP_INCLUDED + + +// Adapted from donated nonius code. + +#ifndef CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED +#define CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED + +namespace Catch { + namespace Benchmark { + struct OutlierClassification { + int samples_seen = 0; + int low_severe = 0; // more than 3 times IQR below Q1 + int low_mild = 0; // 1.5 to 3 times IQR below Q1 + int high_mild = 0; // 1.5 to 3 times IQR above Q3 + int high_severe = 0; // more than 3 times IQR above Q3 + + int total() const { + return low_severe + low_mild + high_mild + high_severe; + } + }; + } // namespace Benchmark +} // namespace Catch + +#endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED +// The fwd decl & default specialization needs to be seen by VS2017 before +// BenchmarkStats itself, or VS2017 will report compilation error. + +#include +#include + +namespace Catch { struct BenchmarkInfo { std::string name; @@ -1494,169 +1332,10 @@ namespace Catch { } }; - //! By setting up its preferences, a reporter can modify Catch2's behaviour - //! in some regards, e.g. it can request Catch2 to capture writes to - //! stdout/stderr during test execution, and pass them to the reporter. - struct ReporterPreferences { - //! Catch2 should redirect writes to stdout and pass them to the - //! reporter - bool shouldRedirectStdOut = false; - //! Catch2 should call `Reporter::assertionEnded` even for passing - //! assertions - bool shouldReportAllAssertions = false; - }; - - /** - * The common base for all reporters and event listeners - * - * Implementing classes must also implement: - * - * //! User-friendly description of the reporter/listener type - * static std::string getDescription() - * - * Generally shouldn't be derived from by users of Catch2 directly, - * instead they should derive from one of the utility bases that - * derive from this class. - */ - class IEventListener { - protected: - //! Derived classes can set up their preferences here - ReporterPreferences m_preferences; - //! The test run's config as filled in from CLI and defaults - IConfig const* m_config; - - public: - IEventListener( IConfig const* config ): m_config( config ) {} - - virtual ~IEventListener(); // = default; - - // Implementing class must also provide the following static methods: - // static std::string getDescription(); - - ReporterPreferences const& getPreferences() const { - return m_preferences; - } - - //! Called when no test cases match provided test spec - virtual void noMatchingTestCases( StringRef unmatchedSpec ) = 0; - //! Called for all invalid test specs from the cli - virtual void reportInvalidTestSpec( StringRef invalidArgument ) = 0; - - /** - * Called once in a testing run before tests are started - * - * Not called if tests won't be run (e.g. only listing will happen) - */ - virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; - - //! Called _once_ for each TEST_CASE, no matter how many times it is entered - virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; - //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections) - virtual void testCasePartialStarting( TestCaseInfo const& testInfo, uint64_t partNumber ) = 0; - //! Called when a `SECTION` is being entered. Not called for skipped sections - virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; - - //! Called when user-code is being probed before the actual benchmark runs - virtual void benchmarkPreparing( StringRef benchmarkName ) = 0; - //! Called after probe but before the user-code is being benchmarked - virtual void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) = 0; - //! Called with the benchmark results if benchmark successfully finishes - virtual void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) = 0; - //! Called if running the benchmarks fails for any reason - virtual void benchmarkFailed( StringRef benchmarkName ) = 0; - - //! Called before assertion success/failure is evaluated - virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; - - //! Called after assertion was fully evaluated - virtual void assertionEnded( AssertionStats const& assertionStats ) = 0; - - //! Called after a `SECTION` has finished running - virtual void sectionEnded( SectionStats const& sectionStats ) = 0; - //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections) - virtual void testCasePartialEnded(TestCaseStats const& testCaseStats, uint64_t partNumber ) = 0; - //! Called _once_ for each TEST_CASE, no matter how many times it is entered - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; - /** - * Called once after all tests in a testing run are finished - * - * Not called if tests weren't run (e.g. only listings happened) - */ - virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; - - /** - * Called with test cases that are skipped due to the test run aborting. - * NOT called for test cases that are explicitly skipped using the `SKIP` macro. - * - * Deprecated - will be removed in the next major release. - */ - virtual void skipTest( TestCaseInfo const& testInfo ) = 0; - - //! Called if a fatal error (signal/structured exception) occured - virtual void fatalErrorEncountered( StringRef error ) = 0; - - //! Writes out information about provided reporters using reporter-specific format - virtual void listReporters(std::vector const& descriptions) = 0; - //! Writes out the provided listeners descriptions using reporter-specific format - virtual void listListeners(std::vector const& descriptions) = 0; - //! Writes out information about provided tests using reporter-specific format - virtual void listTests(std::vector const& tests) = 0; - //! Writes out information about the provided tags using reporter-specific format - virtual void listTags(std::vector const& tags) = 0; - }; - using IEventListenerPtr = Detail::unique_ptr; - -} // end namespace Catch - -#endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED - - -#ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED -#define CATCH_UNIQUE_NAME_HPP_INCLUDED - - - - -/** \file - * Wrapper for the CONFIG configuration option - * - * When generating internal unique names, there are two options. Either - * we mix in the current line number, or mix in an incrementing number. - * We prefer the latter, using `__COUNTER__`, but users might want to - * use the former. - */ - -#ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED -#define CATCH_CONFIG_COUNTER_HPP_INCLUDED - -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER -#endif - -#if defined( CATCH_INTERNAL_CONFIG_COUNTER ) && \ - !defined( CATCH_CONFIG_NO_COUNTER ) && \ - !defined( CATCH_CONFIG_COUNTER ) -# define CATCH_CONFIG_COUNTER -#endif - - -#endif // CATCH_CONFIG_COUNTER_HPP_INCLUDED -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) -#else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) -#endif - -#endif // CATCH_UNIQUE_NAME_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_CHRONOMETER_HPP_INCLUDED -#define CATCH_CHRONOMETER_HPP_INCLUDED +} // end namespace Catch + +#endif // CATCH_BENCHMARK_STATS_HPP_INCLUDED // Adapted from donated nonius code. @@ -1693,12 +1372,63 @@ namespace Catch { #endif // CATCH_CLOCK_HPP_INCLUDED +// Adapted from donated nonius code. + +#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED +#define CATCH_ENVIRONMENT_HPP_INCLUDED + + +namespace Catch { + namespace Benchmark { + template + struct EnvironmentEstimate { + Duration mean; + OutlierClassification outliers; + + template + operator EnvironmentEstimate() const { + return { mean, outliers }; + } + }; + template + struct Environment { + using clock_type = Clock; + EnvironmentEstimate> clock_resolution; + EnvironmentEstimate> clock_cost; + }; + } // namespace Benchmark +} // namespace Catch + +#endif // CATCH_ENVIRONMENT_HPP_INCLUDED + + +// Adapted from donated nonius code. + +#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED +#define CATCH_EXECUTION_PLAN_HPP_INCLUDED + + + +// Adapted from donated nonius code. + +#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED +#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED + + + +// Adapted from donated nonius code. + +#ifndef CATCH_CHRONOMETER_HPP_INCLUDED +#define CATCH_CHRONOMETER_HPP_INCLUDED + + + // Adapted from donated nonius code. #ifndef CATCH_OPTIMIZER_HPP_INCLUDED #define CATCH_OPTIMIZER_HPP_INCLUDED -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__) # include // atomic_thread_fence #endif @@ -1719,16 +1449,23 @@ namespace Catch { namespace Detail { inline void optimizer_barrier() { keep_memory(); } } // namespace Detail -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__) +#if defined(_MSVC_VER) #pragma optimize("", off) +#elif defined(__IAR_SYSTEMS_ICC__) +// For IAR the pragma only affects the following function +#pragma optimize=disable +#endif template inline void keep_memory(T* p) { // thanks @milleniumbug *reinterpret_cast(p) = *reinterpret_cast(p); } // TODO equivalent keep_memory() +#if defined(_MSVC_VER) #pragma optimize("", on) +#endif namespace Detail { inline void optimizer_barrier() { @@ -1758,36 +1495,6 @@ namespace Catch { #endif // CATCH_OPTIMIZER_HPP_INCLUDED -// Adapted from donated nonius code. - -#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED -#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED - - - -#ifndef CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED -#define CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED - -namespace Catch { - - //! Used to signal that an assertion macro failed - struct TestFailureException{}; - - /** - * Outlines throwing of `TestFailureException` into a single TU - * - * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers. - */ - [[noreturn]] void throw_test_failure_exception(); - - //! Used to signal that the remainder of a test should be skipped - struct TestSkipException{}; - -} // namespace Catch - -#endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED - - #ifndef CATCH_META_HPP_INCLUDED #define CATCH_META_HPP_INCLUDED @@ -1829,112 +1536,6 @@ namespace mpl_{ #endif // CATCH_META_HPP_INCLUDED - -#ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED -#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED - - -#include - -namespace Catch { - - class TestCaseHandle; - struct TestCaseInfo; - class ITestCaseRegistry; - class IExceptionTranslatorRegistry; - class IExceptionTranslator; - class IReporterRegistry; - class IReporterFactory; - class ITagAliasRegistry; - class ITestInvoker; - class IMutableEnumValuesRegistry; - struct SourceLineInfo; - - class StartupExceptionRegistry; - class EventListenerFactory; - - using IReporterFactoryPtr = Detail::unique_ptr; - - class IRegistryHub { - public: - virtual ~IRegistryHub(); // = default - - virtual IReporterRegistry const& getReporterRegistry() const = 0; - virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; - virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; - virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; - - - virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; - }; - - class IMutableRegistryHub { - public: - virtual ~IMutableRegistryHub(); // = default - virtual void registerReporter( std::string const& name, IReporterFactoryPtr factory ) = 0; - virtual void registerListener( Detail::unique_ptr factory ) = 0; - virtual void registerTest(Detail::unique_ptr&& testInfo, Detail::unique_ptr&& invoker) = 0; - virtual void registerTranslator( Detail::unique_ptr&& translator ) = 0; - virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; - virtual void registerStartupException() noexcept = 0; - virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0; - }; - - IRegistryHub const& getRegistryHub(); - IMutableRegistryHub& getMutableRegistryHub(); - void cleanUp(); - std::string translateActiveException(); - -} - -#endif // CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED - -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - struct CompleteType { using type = T; }; - template <> - struct CompleteType { struct type {}; }; - - template - using CompleteType_t = typename CompleteType::type; - - template - struct CompleteInvoker { - template - static Result invoke(Fun&& fun, Args&&... args) { - return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); - } - }; - template <> - struct CompleteInvoker { - template - static CompleteType_t invoke(Fun&& fun, Args&&... args) { - CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); - return {}; - } - }; - - // invoke and not return void :( - template - CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { - return CompleteInvoker>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...); - } - - } // namespace Detail - - template - Detail::CompleteType_t> user_code(Fun&& fun) { - return Detail::complete_invoke(CATCH_FORWARD(fun)); - } - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED - namespace Catch { namespace Benchmark { namespace Detail { @@ -1957,85 +1558,41 @@ namespace Catch { TimePoint started; TimePoint finished; }; - } // namespace Detail - - struct Chronometer { - public: - template - void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable()); } - - int runs() const { return repeats; } - - Chronometer(Detail::ChronometerConcept& meter, int repeats_) - : impl(&meter) - , repeats(repeats_) {} - - private: - template - void measure(Fun&& fun, std::false_type) { - measure([&fun](int) { return fun(); }, std::true_type()); - } - - template - void measure(Fun&& fun, std::true_type) { - Detail::optimizer_barrier(); - impl->start(); - for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i); - impl->finish(); - Detail::optimizer_barrier(); - } - - Detail::ChronometerConcept* impl; - int repeats; - }; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_CHRONOMETER_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED -#define CATCH_ENVIRONMENT_HPP_INCLUDED - - -namespace Catch { - namespace Benchmark { - template - struct EnvironmentEstimate { - Duration mean; - OutlierClassification outliers; - - template - operator EnvironmentEstimate() const { - return { mean, outliers }; - } - }; - template - struct Environment { - using clock_type = Clock; - EnvironmentEstimate> clock_resolution; - EnvironmentEstimate> clock_cost; - }; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_ENVIRONMENT_HPP_INCLUDED - + } // namespace Detail -// Adapted from donated nonius code. + struct Chronometer { + public: + template + void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable()); } -#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED -#define CATCH_EXECUTION_PLAN_HPP_INCLUDED + int runs() const { return repeats; } + Chronometer(Detail::ChronometerConcept& meter, int repeats_) + : impl(&meter) + , repeats(repeats_) {} + private: + template + void measure(Fun&& fun, std::false_type) { + measure([&fun](int) { return fun(); }, std::true_type()); + } -// Adapted from donated nonius code. + template + void measure(Fun&& fun, std::true_type) { + Detail::optimizer_barrier(); + impl->start(); + for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i); + impl->finish(); + Detail::optimizer_barrier(); + } -#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED -#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED + Detail::ChronometerConcept* impl; + int repeats; + }; + } // namespace Benchmark +} // namespace Catch +#endif // CATCH_CHRONOMETER_HPP_INCLUDED #include @@ -2173,6 +1730,57 @@ namespace Catch { +// Adapted from donated nonius code. + +#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED +#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED + + +namespace Catch { + namespace Benchmark { + namespace Detail { + template + struct CompleteType { using type = T; }; + template <> + struct CompleteType { struct type {}; }; + + template + using CompleteType_t = typename CompleteType::type; + + template + struct CompleteInvoker { + template + static Result invoke(Fun&& fun, Args&&... args) { + return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); + } + }; + template <> + struct CompleteInvoker { + template + static CompleteType_t invoke(Fun&& fun, Args&&... args) { + CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); + return {}; + } + }; + + // invoke and not return void :( + template + CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { + return CompleteInvoker>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...); + } + + } // namespace Detail + + template + Detail::CompleteType_t> user_code(Fun&& fun) { + return Detail::complete_invoke(CATCH_FORWARD(fun)); + } + } // namespace Benchmark +} // namespace Catch + +#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED + + // Adapted from donated nonius code. #ifndef CATCH_TIMING_HPP_INCLUDED @@ -2259,8 +1867,7 @@ namespace Catch { #endif // CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED -#include -#include +#include namespace Catch { namespace Benchmark { @@ -2283,14 +1890,17 @@ namespace Catch { Detail::run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_iterations, Detail::repeat(now{})); std::vector> times; - times.reserve(cfg.benchmarkSamples()); - std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { + const auto num_samples = cfg.benchmarkSamples(); + times.reserve( num_samples ); + for ( size_t i = 0; i < num_samples; ++i ) { Detail::ChronometerModel model; - this->benchmark(Chronometer(model, iterations_per_sample)); + this->benchmark( Chronometer( model, iterations_per_sample ) ); auto sample_time = model.elapsed() - env.clock_cost.mean; - if (sample_time < FloatDuration::zero()) sample_time = FloatDuration::zero(); - return sample_time / iterations_per_sample; - }); + if ( sample_time < FloatDuration::zero() ) { + sample_time = FloatDuration::zero(); + } + times.push_back(sample_time / iterations_per_sample); + } return times; } }; @@ -2315,8 +1925,6 @@ namespace Catch { #include #include -#include -#include #include namespace Catch { @@ -2330,39 +1938,17 @@ namespace Catch { double weighted_average_quantile(int k, int q, std::vector::iterator first, std::vector::iterator last); - template - OutlierClassification classify_outliers(Iterator first, Iterator last) { - std::vector copy(first, last); - - auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end()); - auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end()); - auto iqr = q3 - q1; - auto los = q1 - (iqr * 3.); - auto lom = q1 - (iqr * 1.5); - auto him = q3 + (iqr * 1.5); - auto his = q3 + (iqr * 3.); - - OutlierClassification o; - for (; first != last; ++first) { - auto&& t = *first; - if (t < los) ++o.low_severe; - else if (t < lom) ++o.low_mild; - else if (t > his) ++o.high_severe; - else if (t > him) ++o.high_mild; - ++o.samples_seen; - } - return o; - } + OutlierClassification + classify_outliers( std::vector::const_iterator first, + std::vector::const_iterator last ); - template - double mean(Iterator first, Iterator last) { - auto count = last - first; - double sum = std::accumulate(first, last, 0.); - return sum / static_cast(count); - } + double mean( std::vector::const_iterator first, + std::vector::const_iterator last ); - template - sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { + template + sample jackknife(Estimator&& estimator, + std::vector::iterator first, + std::vector::iterator last) { auto n = static_cast(last - first); auto second = first; ++second; @@ -2385,8 +1971,12 @@ namespace Catch { double normal_quantile(double p); - template - Estimate bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) { + template + Estimate bootstrap( double confidence_level, + std::vector::iterator first, + std::vector::iterator last, + sample const& resample, + Estimator&& estimator ) { auto n_samples = last - first; double point = estimator(first, last); @@ -2395,13 +1985,13 @@ namespace Catch { sample jack = jackknife(estimator, first, last); double jack_mean = mean(jack.begin(), jack.end()); - double sum_squares, sum_cubes; - std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair sqcb, double x) -> std::pair { - auto d = jack_mean - x; - auto d2 = d * d; - auto d3 = d2 * d; - return { sqcb.first + d2, sqcb.second + d3 }; - }); + double sum_squares = 0, sum_cubes = 0; + for (double x : jack) { + auto difference = jack_mean - x; + auto square = difference * difference; + auto cube = square * difference; + sum_squares += square; sum_cubes += cube; + } double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); long n = static_cast(resample.size()); @@ -2428,15 +2018,16 @@ namespace Catch { return { point, resample[lo], resample[hi], confidence_level }; } - double outlier_variance(Estimate mean, Estimate stddev, int n); - struct bootstrap_analysis { Estimate mean; Estimate standard_deviation; double outlier_variance; }; - bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector::iterator first, std::vector::iterator last); + bootstrap_analysis analyse_samples(double confidence_level, + unsigned int n_resamples, + std::vector::iterator first, + std::vector::iterator last); } // namespace Detail } // namespace Benchmark } // namespace Catch @@ -2444,7 +2035,6 @@ namespace Catch { #endif // CATCH_STATS_HPP_INCLUDED #include -#include #include #include @@ -2455,26 +2045,29 @@ namespace Catch { std::vector resolution(int k) { std::vector> times; times.reserve(static_cast(k + 1)); - std::generate_n(std::back_inserter(times), k + 1, now{}); + for ( int i = 0; i < k + 1; ++i ) { + times.push_back( Clock::now() ); + } std::vector deltas; deltas.reserve(static_cast(k)); - std::transform(std::next(times.begin()), times.end(), times.begin(), - std::back_inserter(deltas), - [](TimePoint a, TimePoint b) { return static_cast((a - b).count()); }); + for ( size_t idx = 1; idx < times.size(); ++idx ) { + deltas.push_back( static_cast( + ( times[idx] - times[idx - 1] ).count() ) ); + } return deltas; } - const auto warmup_iterations = 10000; - const auto warmup_time = std::chrono::milliseconds(100); - const auto minimum_ticks = 1000; - const auto warmup_seed = 10000; - const auto clock_resolution_estimation_time = std::chrono::milliseconds(500); - const auto clock_cost_estimation_time_limit = std::chrono::seconds(1); - const auto clock_cost_estimation_tick_limit = 100000; - const auto clock_cost_estimation_time = std::chrono::milliseconds(10); - const auto clock_cost_estimation_iterations = 10000; + constexpr auto warmup_iterations = 10000; + constexpr auto warmup_time = std::chrono::milliseconds(100); + constexpr auto minimum_ticks = 1000; + constexpr auto warmup_seed = 10000; + constexpr auto clock_resolution_estimation_time = std::chrono::milliseconds(500); + constexpr auto clock_cost_estimation_time_limit = std::chrono::seconds(1); + constexpr auto clock_cost_estimation_tick_limit = 100000; + constexpr auto clock_cost_estimation_time = std::chrono::milliseconds(10); + constexpr auto clock_cost_estimation_iterations = 10000; template int warmup() { @@ -2509,9 +2102,11 @@ namespace Catch { std::vector times; int nsamples = static_cast(std::ceil(time_limit / r.elapsed)); times.reserve(static_cast(nsamples)); - std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { - return static_cast((time_clock(r.iterations) / r.iterations).count()); - }); + for ( int s = 0; s < nsamples; ++s ) { + times.push_back( static_cast( + ( time_clock( r.iterations ) / r.iterations ) + .count() ) ); + } return { FloatDuration(mean(times.begin(), times.end())), classify_outliers(times.begin(), times.end()), @@ -2559,9 +2154,7 @@ namespace Catch { #define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED -#include #include -#include namespace Catch { namespace Benchmark { @@ -2577,7 +2170,9 @@ namespace Catch { operator SampleAnalysis() const { std::vector samples2; samples2.reserve(samples.size()); - std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); + for (auto const& d : samples) { + samples2.push_back(Duration2(d)); + } return { CATCH_MOVE(samples2), mean, @@ -2592,8 +2187,6 @@ namespace Catch { #endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED -#include -#include #include namespace Catch { @@ -2604,7 +2197,9 @@ namespace Catch { if (!cfg.benchmarkNoAnalysis()) { std::vector samples; samples.reserve(static_cast(last - first)); - std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); + for (auto current = first; current != last; ++current) { + samples.push_back( current->count() ); + } auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end()); auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end()); @@ -2619,7 +2214,10 @@ namespace Catch { }; std::vector samples2; samples2.reserve(samples.size()); - std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); + for (auto s : samples) { + samples2.push_back( Duration( s ) ); + } + return { CATCH_MOVE(samples2), wrap_estimate(analysis.mean), @@ -2655,6 +2253,8 @@ namespace Catch { #endif // CATCH_ANALYSE_HPP_INCLUDED #include +#include +#include #include #include #include @@ -2710,7 +2310,7 @@ namespace Catch { auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); BenchmarkStats> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance }; getResultCapture().benchmarkEnded(stats); - } CATCH_CATCH_ANON (TestFailureException) { + } CATCH_CATCH_ANON (TestFailureException const&) { getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr); } CATCH_CATCH_ALL{ getResultCapture().benchmarkFailed(translateActiveException()); @@ -2878,6 +2478,7 @@ namespace Catch { #ifndef CATCH_CONFIG_WCHAR_HPP_INCLUDED #define CATCH_CONFIG_WCHAR_HPP_INCLUDED + // We assume that WCHAR should be enabled by default, and only disabled // for a shortlist (so far only DJGPP) of compilers. @@ -3101,7 +2702,6 @@ namespace Catch { } // namespace Detail - // If we decide for C++14, change these to enable_if_ts template struct StringMaker { template @@ -3701,73 +3301,210 @@ namespace Catch { return !operator==( lhs, rhs ); } - template ::value>> - friend bool operator != ( Approx const& lhs, T const& rhs ) { - return !operator==( rhs, lhs ); + template ::value>> + friend bool operator != ( Approx const& lhs, T const& rhs ) { + return !operator==( rhs, lhs ); + } + + template ::value>> + friend bool operator <= ( T const& lhs, Approx const& rhs ) { + return static_cast(lhs) < rhs.m_value || lhs == rhs; + } + + template ::value>> + friend bool operator <= ( Approx const& lhs, T const& rhs ) { + return lhs.m_value < static_cast(rhs) || lhs == rhs; + } + + template ::value>> + friend bool operator >= ( T const& lhs, Approx const& rhs ) { + return static_cast(lhs) > rhs.m_value || lhs == rhs; + } + + template ::value>> + friend bool operator >= ( Approx const& lhs, T const& rhs ) { + return lhs.m_value > static_cast(rhs) || lhs == rhs; + } + + template ::value>> + Approx& epsilon( T const& newEpsilon ) { + const auto epsilonAsDouble = static_cast(newEpsilon); + setEpsilon(epsilonAsDouble); + return *this; + } + + template ::value>> + Approx& margin( T const& newMargin ) { + const auto marginAsDouble = static_cast(newMargin); + setMargin(marginAsDouble); + return *this; + } + + template ::value>> + Approx& scale( T const& newScale ) { + m_scale = static_cast(newScale); + return *this; + } + + std::string toString() const; + + private: + double m_epsilon; + double m_margin; + double m_scale; + double m_value; + }; + +namespace literals { + Approx operator ""_a(long double val); + Approx operator ""_a(unsigned long long val); +} // end namespace literals + +template<> +struct StringMaker { + static std::string convert(Catch::Approx const& value); +}; + +} // end namespace Catch + +#endif // CATCH_APPROX_HPP_INCLUDED + + +#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED +#define CATCH_ASSERTION_INFO_HPP_INCLUDED + + + +#ifndef CATCH_SOURCE_LINE_INFO_HPP_INCLUDED +#define CATCH_SOURCE_LINE_INFO_HPP_INCLUDED + +#include +#include + +namespace Catch { + + struct SourceLineInfo { + + SourceLineInfo() = delete; + constexpr SourceLineInfo( char const* _file, std::size_t _line ) noexcept: + file( _file ), + line( _line ) + {} + + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + + friend std::ostream& operator << (std::ostream& os, SourceLineInfo const& info); + }; +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +#endif // CATCH_SOURCE_LINE_INFO_HPP_INCLUDED + +namespace Catch { + + struct AssertionInfo { + // AssertionInfo() = delete; + + StringRef macroName; + SourceLineInfo lineInfo; + StringRef capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + +} // end namespace Catch + +#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED + + +#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED +#define CATCH_ASSERTION_RESULT_HPP_INCLUDED + + + +#ifndef CATCH_LAZY_EXPR_HPP_INCLUDED +#define CATCH_LAZY_EXPR_HPP_INCLUDED + +#include + +namespace Catch { + + class ITransientExpression; + + class LazyExpression { + friend class AssertionHandler; + friend struct AssertionStats; + friend class RunContext; + + ITransientExpression const* m_transientExpression = nullptr; + bool m_isNegated; + public: + LazyExpression( bool isNegated ): + m_isNegated(isNegated) + {} + LazyExpression(LazyExpression const& other) = default; + LazyExpression& operator = ( LazyExpression const& ) = delete; + + explicit operator bool() const { + return m_transientExpression != nullptr; } - template ::value>> - friend bool operator <= ( T const& lhs, Approx const& rhs ) { - return static_cast(lhs) < rhs.m_value || lhs == rhs; - } + friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; + }; - template ::value>> - friend bool operator <= ( Approx const& lhs, T const& rhs ) { - return lhs.m_value < static_cast(rhs) || lhs == rhs; - } +} // namespace Catch - template ::value>> - friend bool operator >= ( T const& lhs, Approx const& rhs ) { - return static_cast(lhs) > rhs.m_value || lhs == rhs; - } +#endif // CATCH_LAZY_EXPR_HPP_INCLUDED - template ::value>> - friend bool operator >= ( Approx const& lhs, T const& rhs ) { - return lhs.m_value > static_cast(rhs) || lhs == rhs; - } +#include - template ::value>> - Approx& epsilon( T const& newEpsilon ) { - const auto epsilonAsDouble = static_cast(newEpsilon); - setEpsilon(epsilonAsDouble); - return *this; - } +namespace Catch { - template ::value>> - Approx& margin( T const& newMargin ) { - const auto marginAsDouble = static_cast(newMargin); - setMargin(marginAsDouble); - return *this; - } + struct AssertionResultData + { + AssertionResultData() = delete; - template ::value>> - Approx& scale( T const& newScale ) { - m_scale = static_cast(newScale); - return *this; - } + AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); - std::string toString() const; + std::string message; + mutable std::string reconstructedExpression; + LazyExpression lazyExpression; + ResultWas::OfType resultType; - private: - double m_epsilon; - double m_margin; - double m_scale; - double m_value; + std::string reconstructExpression() const; }; -namespace literals { - Approx operator ""_a(long double val); - Approx operator ""_a(unsigned long long val); -} // end namespace literals + class AssertionResult { + public: + AssertionResult() = delete; + AssertionResult( AssertionInfo const& info, AssertionResultData&& data ); -template<> -struct StringMaker { - static std::string convert(Catch::Approx const& value); -}; + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + StringRef getMessage() const; + SourceLineInfo getSourceInfo() const; + StringRef getTestMacroName() const; + + //protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; } // end namespace Catch -#endif // CATCH_APPROX_HPP_INCLUDED +#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED #ifndef CATCH_CONFIG_HPP_INCLUDED @@ -3934,6 +3671,7 @@ namespace Catch { #ifndef CATCH_OPTIONAL_HPP_INCLUDED #define CATCH_OPTIONAL_HPP_INCLUDED + #include namespace Catch { @@ -3942,35 +3680,50 @@ namespace Catch { template class Optional { public: - Optional() : nullableValue( nullptr ) {} - Optional( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Optional( Optional const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) - {} + Optional(): nullableValue( nullptr ) {} + ~Optional() { reset(); } + + Optional( T const& _value ): + nullableValue( new ( storage ) T( _value ) ) {} + Optional( T&& _value ): + nullableValue( new ( storage ) T( CATCH_MOVE( _value ) ) ) {} - ~Optional() { + Optional& operator=( T const& _value ) { + reset(); + nullableValue = new ( storage ) T( _value ); + return *this; + } + Optional& operator=( T&& _value ) { reset(); + nullableValue = new ( storage ) T( CATCH_MOVE( _value ) ); + return *this; } - Optional& operator= ( Optional const& _other ) { - if( &_other != this ) { + Optional( Optional const& _other ): + nullableValue( _other ? new ( storage ) T( *_other ) : nullptr ) {} + Optional( Optional&& _other ): + nullableValue( _other ? new ( storage ) T( CATCH_MOVE( *_other ) ) + : nullptr ) {} + + Optional& operator=( Optional const& _other ) { + if ( &_other != this ) { reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); + if ( _other ) { nullableValue = new ( storage ) T( *_other ); } } return *this; } - Optional& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); + Optional& operator=( Optional&& _other ) { + if ( &_other != this ) { + reset(); + if ( _other ) { + nullableValue = new ( storage ) T( CATCH_MOVE( *_other ) ); + } + } return *this; } void reset() { - if( nullableValue ) - nullableValue->~T(); + if ( nullableValue ) { nullableValue->~T(); } nullableValue = nullptr; } @@ -4017,7 +3770,7 @@ namespace Catch { } private: - T *nullableValue; + T* nullableValue; alignas(alignof(T)) char storage[sizeof(T)]; }; @@ -4424,10 +4177,10 @@ namespace Catch { // as well as // << stuff +StreamEndStop struct StreamEndStop { - StringRef operator+() const { return StringRef(); } + constexpr StringRef operator+() const { return StringRef(); } template - friend T const& operator+( T const& value, StreamEndStop ) { + constexpr friend T const& operator+( T const& value, StreamEndStop ) { return value; } }; @@ -4436,12 +4189,47 @@ namespace Catch { #endif // CATCH_STREAM_END_STOP_HPP_INCLUDED + +#ifndef CATCH_MESSAGE_INFO_HPP_INCLUDED +#define CATCH_MESSAGE_INFO_HPP_INCLUDED + + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( StringRef _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + StringRef macroName; + std::string message; + SourceLineInfo lineInfo; + ResultWas::OfType type; + unsigned int sequence; + + bool operator == (MessageInfo const& other) const { + return sequence == other.sequence; + } + bool operator < (MessageInfo const& other) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + +} // end namespace Catch + +#endif // CATCH_MESSAGE_INFO_HPP_INCLUDED + #include #include namespace Catch { struct SourceLineInfo; + class IResultCapture; struct MessageStream { @@ -4482,7 +4270,7 @@ namespace Catch { class Capturer { std::vector m_messages; - IResultCapture& m_resultCapture = getResultCapture(); + IResultCapture& m_resultCapture; size_t m_captured = 0; public: Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); @@ -4518,7 +4306,10 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ - Catch::Capturer varName( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \ + Catch::Capturer varName( macroName##_catch_sr, \ + CATCH_INTERNAL_LINEINFO, \ + Catch::ResultWas::Info, \ + #__VA_ARGS__##_catch_sr ); \ varName.captureValues( 0, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// @@ -4566,6 +4357,75 @@ namespace Catch { #endif // CATCH_MESSAGE_HPP_INCLUDED +#ifndef CATCH_SECTION_INFO_HPP_INCLUDED +#define CATCH_SECTION_INFO_HPP_INCLUDED + + + +#ifndef CATCH_TOTALS_HPP_INCLUDED +#define CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + + struct Counts { + Counts operator - ( Counts const& other ) const; + Counts& operator += ( Counts const& other ); + + std::uint64_t total() const; + bool allPassed() const; + bool allOk() const; + + std::uint64_t passed = 0; + std::uint64_t failed = 0; + std::uint64_t failedButOk = 0; + std::uint64_t skipped = 0; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const; + Totals& operator += ( Totals const& other ); + + Totals delta( Totals const& prevTotals ) const; + + Counts assertions; + Counts testCases; + }; +} + +#endif // CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + + struct SectionInfo { + // The last argument is ignored, so that people can write + // SECTION("ShortName", "Proper description that is long") and + // still use the `-c` flag comfortably. + SectionInfo( SourceLineInfo const& _lineInfo, std::string _name, + const char* const = nullptr ): + name(CATCH_MOVE(_name)), + lineInfo(_lineInfo) + {} + + std::string name; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +#endif // CATCH_SECTION_INFO_HPP_INCLUDED + + #ifndef CATCH_SESSION_HPP_INCLUDED #define CATCH_SESSION_HPP_INCLUDED @@ -5841,8 +5701,6 @@ namespace Catch { namespace Catch { - class IResultCapture; - struct AssertionReaction { bool shouldDebugBreak = false; bool shouldThrow = false; @@ -5883,7 +5741,6 @@ namespace Catch { void handleUnexpectedInflightException(); void complete(); - void setCompleted(); // query auto allowThrows() const -> bool; @@ -5895,6 +5752,19 @@ namespace Catch { #endif // CATCH_ASSERTION_HANDLER_HPP_INCLUDED + +#ifndef CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED +#define CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED + + +#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) + #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr +#else + #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr +#endif + +#endif // CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED + // We need this suppression to leak, because it took until GCC 10 // for the front end to handle local suppression via _Pragma properly #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ <= 9 @@ -5903,12 +5773,6 @@ namespace Catch { #if !defined(CATCH_CONFIG_DISABLE) -#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) - #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ -#else - #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" -#endif - #if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) /////////////////////////////////////////////////////////////////////////////// @@ -5976,6 +5840,7 @@ namespace Catch { if( catchAssertionHandler.allowThrows() ) \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(__VA_ARGS__); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ @@ -5996,6 +5861,7 @@ namespace Catch { if( catchAssertionHandler.allowThrows() ) \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(expr); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ @@ -6022,6 +5888,7 @@ namespace Catch { if( catchAssertionHandler.allowThrows() ) \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(__VA_ARGS__); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ @@ -6045,6 +5912,34 @@ namespace Catch { + +/** \file + * Wrapper for the STATIC_ANALYSIS_SUPPORT configuration option + * + * Some of Catch2's macros can be defined differently to work better with + * static analysis tools, like clang-tidy or coverity. + * Currently the main use case is to show that `SECTION`s are executed + * exclusively, and not all in one run of a `TEST_CASE`. + */ + +#ifndef CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED +#define CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED + + +#if defined(__clang_analyzer__) || defined(__COVERITY__) + #define CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT +#endif + +#if defined( CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT ) && \ + !defined( CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) && \ + !defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) +# define CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT +#endif + + +#endif // CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED + + #ifndef CATCH_TIMER_HPP_INCLUDED #define CATCH_TIMER_HPP_INCLUDED @@ -6089,17 +5984,63 @@ namespace Catch { } // end namespace Catch -#define INTERNAL_CATCH_SECTION( ... ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT) +# define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \ + catch_internal_Section ) = \ + Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \ + catch_internal_Section ) = \ + Catch::SectionInfo( \ + CATCH_INTERNAL_LINEINFO, \ + ( Catch::ReusableStringStream() << __VA_ARGS__ ) \ + .str() ) ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +#else + +// These section definitions imply that at most one section at one level +// will be intered (because only one section's __LINE__ can be equal to +// the dummy `catchInternalSectionHint` variable from `TEST_CASE`). + +namespace Catch { + namespace Detail { + // Intentionally without linkage, as it should only be used as a dummy + // symbol for static analysis. + int GetNewSectionHint(); + } // namespace Detail +} // namespace Catch + + +# define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + if ( [[maybe_unused]] int catchInternalPreviousSectionHint = \ + catchInternalSectionHint, \ + catchInternalSectionHint = Catch::Detail::GetNewSectionHint(); \ + catchInternalPreviousSectionHint == __LINE__ ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + if ( [[maybe_unused]] int catchInternalPreviousSectionHint = \ + catchInternalSectionHint, \ + catchInternalSectionHint = Catch::Detail::GetNewSectionHint(); \ + catchInternalPreviousSectionHint == __LINE__ ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +#endif -#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #endif // CATCH_SECTION_HPP_INCLUDED @@ -6109,42 +6050,20 @@ namespace Catch { -#ifndef CATCH_INTERFACES_TESTCASE_HPP_INCLUDED -#define CATCH_INTERFACES_TESTCASE_HPP_INCLUDED - -#include +#ifndef CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED +#define CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED namespace Catch { - class TestSpec; - struct TestCaseInfo; - class ITestInvoker { public: - virtual void invoke () const = 0; + virtual void invoke() const = 0; virtual ~ITestInvoker(); // = default }; - class TestCaseHandle; - class IConfig; - - class ITestCaseRegistry { - public: - virtual ~ITestCaseRegistry(); // = default - // TODO: this exists only for adding filenames to test cases -- let's expose this in a saner way later - virtual std::vector const& getAllInfos() const = 0; - virtual std::vector const& getAllTests() const = 0; - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; - }; - - bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ); - bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - -} +} // namespace Catch -#endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED +#endif // CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED #ifndef CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED @@ -6216,6 +6135,9 @@ struct AutoReg : Detail::NonCopyable { void TestName::test() #endif + +#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT) + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ @@ -6228,13 +6150,40 @@ struct AutoReg : Detail::NonCopyable { #define INTERNAL_CATCH_TESTCASE( ... ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__ ) - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - namespace{ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT + + +// Dummy registrator for the dumy test case macros +namespace Catch { + namespace Detail { + struct DummyUse { + DummyUse( void ( * )( int ) ); + }; + } // namespace Detail +} // namespace Catch + +// Note that both the presence of the argument and its exact name are +// necessary for the section support. + +// We provide a shadowed variable so that a `SECTION` inside non-`TEST_CASE` +// tests can compile. The redefined `TEST_CASE` shadows this with param. +static int catchInternalSectionHint = 0; + +# define INTERNAL_CATCH_TESTCASE2( fname ) \ + static void fname( int ); \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + static const Catch::Detail::DummyUse INTERNAL_CATCH_UNIQUE_NAME( \ + dummyUser )( &fname ); \ + CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \ + static void fname( [[maybe_unused]] int catchInternalSectionHint ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +# define INTERNAL_CATCH_TESTCASE( ... ) \ + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( dummyFunction ) ) + + +#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ @@ -6245,13 +6194,33 @@ struct AutoReg : Detail::NonCopyable { struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ void test(); \ }; \ - const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \ + Catch::makeTestInvoker( &TestName::test ), \ + CATCH_INTERNAL_LINEINFO, \ + #ClassName##_catch_sr, \ + Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ } \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ + namespace { \ + const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \ + Catch::makeTestInvoker( &QualifiedMethod ), \ + CATCH_INTERNAL_LINEINFO, \ + "&" #QualifiedMethod##_catch_sr, \ + Catch::NameAndTags{ __VA_ARGS__ } ); \ + } /* NOLINT */ \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ do { \ @@ -6878,7 +6847,7 @@ struct AutoReg : Detail::NonCopyable { void reg_tests() { \ size_t index = 0; \ using expander = size_t[]; \ - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ } \ };\ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ @@ -7013,7 +6982,7 @@ struct AutoReg : Detail::NonCopyable { void reg_tests(){\ size_t index = 0;\ using expander = size_t[];\ - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ }\ };\ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ @@ -7294,6 +7263,10 @@ namespace Catch { #include namespace Catch { + namespace Detail { + void registerTranslatorImpl( + Detail::unique_ptr&& translator ); + } class ExceptionTranslatorRegistrar { template @@ -7327,9 +7300,9 @@ namespace Catch { public: template ExceptionTranslatorRegistrar( std::string(*translateFunction)( T const& ) ) { - getMutableRegistryHub().registerTranslator( - Detail::make_unique>(translateFunction) - ); + Detail::registerTranslatorImpl( + Detail::make_unique>( + translateFunction ) ); } }; @@ -7401,8 +7374,8 @@ namespace Catch { #define CATCH_VERSION_MACROS_HPP_INCLUDED #define CATCH_VERSION_MAJOR 3 -#define CATCH_VERSION_MINOR 3 -#define CATCH_VERSION_PATCH 1 +#define CATCH_VERSION_MINOR 4 +#define CATCH_VERSION_PATCH 0 #endif // CATCH_VERSION_MACROS_HPP_INCLUDED @@ -7754,16 +7727,19 @@ namespace Detail { } // namespace Generators } // namespace Catch +#define CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL( ... ) #__VA_ARGS__##_catch_sr +#define CATCH_INTERNAL_GENERATOR_STRINGIZE(...) CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL(__VA_ARGS__) + #define GENERATE( ... ) \ - Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ CATCH_INTERNAL_LINEINFO, \ [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) #define GENERATE_COPY( ... ) \ - Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ CATCH_INTERNAL_LINEINFO, \ [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) #define GENERATE_REF( ... ) \ - Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ CATCH_INTERNAL_LINEINFO, \ [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) @@ -8248,28 +8224,254 @@ GeneratorWrapper from_range(Container const& cnt) { } // namespace Catch -#endif // CATCH_GENERATORS_RANGE_HPP_INCLUDED +#endif // CATCH_GENERATORS_RANGE_HPP_INCLUDED + +#endif // CATCH_GENERATORS_ALL_HPP_INCLUDED + + +/** \file + * This is a convenience header for Catch2's interfaces. It includes + * **all** of Catch2 headers related to interfaces. + * + * Generally the Catch2 users should use specific includes they need, + * but this header can be used instead for ease-of-experimentation, or + * just plain convenience, at the cost of somewhat increased compilation + * times. + * + * When a new header is added to either the `interfaces` folder, or to + * the corresponding internal subfolder, it should be added here. + */ + + +#ifndef CATCH_INTERFACES_ALL_HPP_INCLUDED +#define CATCH_INTERFACES_ALL_HPP_INCLUDED + + + +#ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED +#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED + + + +#ifndef CATCH_TEST_RUN_INFO_HPP_INCLUDED +#define CATCH_TEST_RUN_INFO_HPP_INCLUDED + + +namespace Catch { + + struct TestRunInfo { + constexpr TestRunInfo(StringRef _name) : name(_name) {} + StringRef name; + }; + +} // end namespace Catch + +#endif // CATCH_TEST_RUN_INFO_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + + struct ReporterDescription; + struct ListenerDescription; + struct TagInfo; + struct TestCaseInfo; + class TestCaseHandle; + class IConfig; + class IStream; + enum class ColourMode : std::uint8_t; + + struct ReporterConfig { + ReporterConfig( IConfig const* _fullConfig, + Detail::unique_ptr _stream, + ColourMode colourMode, + std::map customOptions ); + + ReporterConfig( ReporterConfig&& ) = default; + ReporterConfig& operator=( ReporterConfig&& ) = default; + ~ReporterConfig(); // = default + + Detail::unique_ptr takeStream() &&; + IConfig const* fullConfig() const; + ColourMode colourMode() const; + std::map const& customOptions() const; + + private: + Detail::unique_ptr m_stream; + IConfig const* m_fullConfig; + ColourMode m_colourMode; + std::map m_customOptions; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ); + + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = delete; + AssertionStats& operator = ( AssertionStats && ) = delete; + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo&& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ); + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string&& _stdOut, + std::string&& _stdErr, + bool _aborting ); + + TestCaseInfo const * testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ); + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + //! By setting up its preferences, a reporter can modify Catch2's behaviour + //! in some regards, e.g. it can request Catch2 to capture writes to + //! stdout/stderr during test execution, and pass them to the reporter. + struct ReporterPreferences { + //! Catch2 should redirect writes to stdout and pass them to the + //! reporter + bool shouldRedirectStdOut = false; + //! Catch2 should call `Reporter::assertionEnded` even for passing + //! assertions + bool shouldReportAllAssertions = false; + }; + + /** + * The common base for all reporters and event listeners + * + * Implementing classes must also implement: + * + * //! User-friendly description of the reporter/listener type + * static std::string getDescription() + * + * Generally shouldn't be derived from by users of Catch2 directly, + * instead they should derive from one of the utility bases that + * derive from this class. + */ + class IEventListener { + protected: + //! Derived classes can set up their preferences here + ReporterPreferences m_preferences; + //! The test run's config as filled in from CLI and defaults + IConfig const* m_config; + + public: + IEventListener( IConfig const* config ): m_config( config ) {} + + virtual ~IEventListener(); // = default; + + // Implementing class must also provide the following static methods: + // static std::string getDescription(); + + ReporterPreferences const& getPreferences() const { + return m_preferences; + } + + //! Called when no test cases match provided test spec + virtual void noMatchingTestCases( StringRef unmatchedSpec ) = 0; + //! Called for all invalid test specs from the cli + virtual void reportInvalidTestSpec( StringRef invalidArgument ) = 0; + + /** + * Called once in a testing run before tests are started + * + * Not called if tests won't be run (e.g. only listing will happen) + */ + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + + //! Called _once_ for each TEST_CASE, no matter how many times it is entered + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections) + virtual void testCasePartialStarting( TestCaseInfo const& testInfo, uint64_t partNumber ) = 0; + //! Called when a `SECTION` is being entered. Not called for skipped sections + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + //! Called when user-code is being probed before the actual benchmark runs + virtual void benchmarkPreparing( StringRef benchmarkName ) = 0; + //! Called after probe but before the user-code is being benchmarked + virtual void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) = 0; + //! Called with the benchmark results if benchmark successfully finishes + virtual void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) = 0; + //! Called if running the benchmarks fails for any reason + virtual void benchmarkFailed( StringRef benchmarkName ) = 0; + + //! Called before assertion success/failure is evaluated + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + //! Called after assertion was fully evaluated + virtual void assertionEnded( AssertionStats const& assertionStats ) = 0; -#endif // CATCH_GENERATORS_ALL_HPP_INCLUDED + //! Called after a `SECTION` has finished running + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections) + virtual void testCasePartialEnded(TestCaseStats const& testCaseStats, uint64_t partNumber ) = 0; + //! Called _once_ for each TEST_CASE, no matter how many times it is entered + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + /** + * Called once after all tests in a testing run are finished + * + * Not called if tests weren't run (e.g. only listings happened) + */ + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + /** + * Called with test cases that are skipped due to the test run aborting. + * NOT called for test cases that are explicitly skipped using the `SKIP` macro. + * + * Deprecated - will be removed in the next major release. + */ + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; -/** \file - * This is a convenience header for Catch2's interfaces. It includes - * **all** of Catch2 headers related to interfaces. - * - * Generally the Catch2 users should use specific includes they need, - * but this header can be used instead for ease-of-experimentation, or - * just plain convenience, at the cost of somewhat increased compilation - * times. - * - * When a new header is added to either the `interfaces` folder, or to - * the corresponding internal subfolder, it should be added here. - */ + //! Called if a fatal error (signal/structured exception) occurred + virtual void fatalErrorEncountered( StringRef error ) = 0; + //! Writes out information about provided reporters using reporter-specific format + virtual void listReporters(std::vector const& descriptions) = 0; + //! Writes out the provided listeners descriptions using reporter-specific format + virtual void listListeners(std::vector const& descriptions) = 0; + //! Writes out information about provided tests using reporter-specific format + virtual void listTests(std::vector const& tests) = 0; + //! Writes out information about the provided tags using reporter-specific format + virtual void listTags(std::vector const& tags) = 0; + }; + using IEventListenerPtr = Detail::unique_ptr; -#ifndef CATCH_INTERFACES_ALL_HPP_INCLUDED -#define CATCH_INTERFACES_ALL_HPP_INCLUDED +} // end namespace Catch +#endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED #ifndef CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED @@ -8310,89 +8512,79 @@ namespace Catch { #endif // CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED -#ifndef CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED -#define CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED +#ifndef CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED +#define CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +#include +namespace Catch { + struct TagAlias; -#ifndef CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED -#define CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED + class ITagAliasRegistry { + public: + virtual ~ITagAliasRegistry(); // = default + // Nullptr if not present + virtual TagAlias const* find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + static ITagAliasRegistry const& get(); + }; -namespace Catch { - namespace Detail { - //! Provides case-insensitive `op<` semantics when called - struct CaseInsensitiveLess { - bool operator()( StringRef lhs, - StringRef rhs ) const; - }; +} // end namespace Catch - //! Provides case-insensitive `op==` semantics when called - struct CaseInsensitiveEqualTo { - bool operator()( StringRef lhs, - StringRef rhs ) const; - }; +#endif // CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED - } // namespace Detail -} // namespace Catch -#endif // CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED +#ifndef CATCH_INTERFACES_TESTCASE_HPP_INCLUDED +#define CATCH_INTERFACES_TESTCASE_HPP_INCLUDED -#include #include -#include namespace Catch { + struct TestCaseInfo; + class TestCaseHandle; class IConfig; - class IEventListener; - using IEventListenerPtr = Detail::unique_ptr; - class IReporterFactory; - using IReporterFactoryPtr = Detail::unique_ptr; - struct ReporterConfig; - class EventListenerFactory; - - class IReporterRegistry { + class ITestCaseRegistry { public: - using FactoryMap = std::map; - using Listeners = std::vector>; - - virtual ~IReporterRegistry(); // = default - virtual IEventListenerPtr create( std::string const& name, ReporterConfig&& config ) const = 0; - virtual FactoryMap const& getFactories() const = 0; - virtual Listeners const& getListeners() const = 0; + virtual ~ITestCaseRegistry(); // = default + // TODO: this exists only for adding filenames to test cases -- let's expose this in a saner way later + virtual std::vector const& getAllInfos() const = 0; + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; -} // end namespace Catch - -#endif // CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED - +} -#ifndef CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED -#define CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED +#endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED -#include +#endif // CATCH_INTERFACES_ALL_HPP_INCLUDED -namespace Catch { - struct TagAlias; +#ifndef CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED +#define CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED - class ITagAliasRegistry { - public: - virtual ~ITagAliasRegistry(); // = default - // Nullptr if not present - virtual TagAlias const* find( std::string const& alias ) const = 0; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; - static ITagAliasRegistry const& get(); - }; +namespace Catch { + namespace Detail { + //! Provides case-insensitive `op<` semantics when called + struct CaseInsensitiveLess { + bool operator()( StringRef lhs, + StringRef rhs ) const; + }; -} // end namespace Catch + //! Provides case-insensitive `op==` semantics when called + struct CaseInsensitiveEqualTo { + bool operator()( StringRef lhs, + StringRef rhs ) const; + }; -#endif // CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED + } // namespace Detail +} // namespace Catch -#endif // CATCH_INTERFACES_ALL_HPP_INCLUDED +#endif // CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED @@ -8434,6 +8626,7 @@ namespace Catch { #ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED #define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED + #if defined(_MSC_VER) # if _MSC_VER >= 1900 // Visual Studio 2015 or newer # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS @@ -8724,7 +8917,6 @@ namespace Catch { ~ExceptionTranslatorRegistry() override; void registerTranslator( Detail::unique_ptr&& translator ); std::string translateActiveException() const override; - std::string tryTranslators() const; private: ExceptionTranslators m_translators; @@ -8919,6 +9111,139 @@ namespace Detail { #endif // CATCH_GETENV_HPP_INCLUDED +#ifndef CATCH_IS_PERMUTATION_HPP_INCLUDED +#define CATCH_IS_PERMUTATION_HPP_INCLUDED + +#include +#include + +namespace Catch { + namespace Detail { + + template + ForwardIter find_sentinel( ForwardIter start, + Sentinel sentinel, + T const& value, + Comparator cmp ) { + while ( start != sentinel ) { + if ( cmp( *start, value ) ) { break; } + ++start; + } + return start; + } + + template + std::ptrdiff_t count_sentinel( ForwardIter start, + Sentinel sentinel, + T const& value, + Comparator cmp ) { + std::ptrdiff_t count = 0; + while ( start != sentinel ) { + if ( cmp( *start, value ) ) { ++count; } + ++start; + } + return count; + } + + template + std::enable_if_t::value, + std::ptrdiff_t> + sentinel_distance( ForwardIter iter, const Sentinel sentinel ) { + std::ptrdiff_t dist = 0; + while ( iter != sentinel ) { + ++iter; + ++dist; + } + return dist; + } + + template + std::ptrdiff_t sentinel_distance( ForwardIter first, + ForwardIter last ) { + return std::distance( first, last ); + } + + template + bool check_element_counts( ForwardIter1 first_1, + const Sentinel1 end_1, + ForwardIter2 first_2, + const Sentinel2 end_2, + Comparator cmp ) { + auto cursor = first_1; + while ( cursor != end_1 ) { + if ( find_sentinel( first_1, cursor, *cursor, cmp ) == + cursor ) { + // we haven't checked this element yet + const auto count_in_range_2 = + count_sentinel( first_2, end_2, *cursor, cmp ); + // Not a single instance in 2nd range, so it cannot be a + // permutation of 1st range + if ( count_in_range_2 == 0 ) { return false; } + + const auto count_in_range_1 = + count_sentinel( cursor, end_1, *cursor, cmp ); + if ( count_in_range_1 != count_in_range_2 ) { + return false; + } + } + + ++cursor; + } + + return true; + } + + template + bool is_permutation( ForwardIter1 first_1, + const Sentinel1 end_1, + ForwardIter2 first_2, + const Sentinel2 end_2, + Comparator cmp ) { + // TODO: no optimization for stronger iterators, because we would also have to constrain on sentinel vs not sentinel types + // TODO: Comparator has to be "both sides", e.g. a == b => b == a + // This skips shared prefix of the two ranges + while (first_1 != end_1 && first_2 != end_2 && cmp(*first_1, *first_2)) { + ++first_1; + ++first_2; + } + + // We need to handle case where at least one of the ranges has no more elements + if (first_1 == end_1 || first_2 == end_2) { + return first_1 == end_1 && first_2 == end_2; + } + + // pair counting is n**2, so we pay linear walk to compare the sizes first + auto dist_1 = sentinel_distance( first_1, end_1 ); + auto dist_2 = sentinel_distance( first_2, end_2 ); + + if (dist_1 != dist_2) { return false; } + + // Since we do not try to handle stronger iterators pair (e.g. + // bidir) optimally, the only thing left to do is to check counts in + // the remaining ranges. + return check_element_counts( first_1, end_1, first_2, end_2, cmp ); + } + + } // namespace Detail +} // namespace Catch + +#endif // CATCH_IS_PERMUTATION_HPP_INCLUDED + + #ifndef CATCH_ISTREAM_HPP_INCLUDED #define CATCH_ISTREAM_HPP_INCLUDED @@ -9152,28 +9477,45 @@ namespace Catch { #include +#include +#include namespace Catch { - class ReporterRegistry : public IReporterRegistry { - public: + class IEventListener; + using IEventListenerPtr = Detail::unique_ptr; + class IReporterFactory; + using IReporterFactoryPtr = Detail::unique_ptr; + struct ReporterConfig; + class EventListenerFactory; + + class ReporterRegistry { + struct ReporterRegistryImpl; + Detail::unique_ptr m_impl; + public: ReporterRegistry(); - ~ReporterRegistry() override; // = default, out of line to allow fwd decl + ~ReporterRegistry(); // = default; - IEventListenerPtr create( std::string const& name, ReporterConfig&& config ) const override; + IEventListenerPtr create( std::string const& name, + ReporterConfig&& config ) const; - void registerReporter( std::string const& name, IReporterFactoryPtr factory ); - void registerListener( Detail::unique_ptr factory ); + void registerReporter( std::string const& name, + IReporterFactoryPtr factory ); - FactoryMap const& getFactories() const override; - Listeners const& getListeners() const override; + void + registerListener( Detail::unique_ptr factory ); - private: - FactoryMap m_factories; - Listeners m_listeners; + std::map const& + getFactories() const; + + std::vector> const& + getListeners() const; }; -} + +} // end namespace Catch #endif // CATCH_REPORTER_REGISTRY_HPP_INCLUDED @@ -9199,8 +9541,12 @@ namespace TestCaseTracking { NameAndLocation( std::string&& _name, SourceLineInfo const& _location ); friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) { - return lhs.name == rhs.name - && lhs.location == rhs.location; + // This is a very cheap check that should have a very high hit rate. + // If we get to SourceLineInfo::operator==, we will redo it, but the + // cost of repeating is trivial at that point (we will be paying + // multiple strcmp/memcmps at that point). + if ( lhs.location.line != rhs.location.line ) { return false; } + return lhs.name == rhs.name && lhs.location == rhs.location; } friend bool operator!=(NameAndLocation const& lhs, NameAndLocation const& rhs) { @@ -9224,11 +9570,16 @@ namespace TestCaseTracking { name( name_ ), location( location_ ) {} friend bool operator==( NameAndLocation const& lhs, - NameAndLocationRef rhs ) { + NameAndLocationRef const& rhs ) { + // This is a very cheap check that should have a very high hit rate. + // If we get to SourceLineInfo::operator==, we will redo it, but the + // cost of repeating is trivial at that point (we will be paying + // multiple strcmp/memcmps at that point). + if ( lhs.location.line != rhs.location.line ) { return false; } return StringRef( lhs.name ) == rhs.name && lhs.location == rhs.location; } - friend bool operator==( NameAndLocationRef lhs, + friend bool operator==( NameAndLocationRef const& lhs, NameAndLocation const& rhs ) { return rhs == lhs; } @@ -9279,8 +9630,10 @@ namespace TestCaseTracking { //! Returns true if tracker run to completion (successfully or not) virtual bool isComplete() const = 0; - //! Returns true if tracker run to completion succesfully - bool isSuccessfullyCompleted() const; + //! Returns true if tracker run to completion successfully + bool isSuccessfullyCompleted() const { + return m_runState == CompletedSuccessfully; + } //! Returns true if tracker has started but hasn't been completed bool isOpen() const; //! Returns true iff tracker has started @@ -9298,7 +9651,7 @@ namespace TestCaseTracking { * * Returns nullptr if not found. */ - ITracker* findChild( NameAndLocationRef nameAndLocation ); + ITracker* findChild( NameAndLocationRef const& nameAndLocation ); //! Have any children been added? bool hasChildren() const { return !m_children.empty(); @@ -9339,13 +9692,15 @@ namespace TestCaseTracking { public: ITracker& startRun(); - void endRun(); - void startCycle(); + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } void completeCycle(); bool completedCycle() const; - ITracker& currentTracker(); + ITracker& currentTracker() { return *m_currentTracker; } void setCurrentTracker( ITracker* tracker ); }; @@ -9371,7 +9726,11 @@ namespace TestCaseTracking { class SectionTracker : public TrackerBase { std::vector m_filters; - std::string m_trimmed_name; + // Note that lifetime-wise we piggy back off the name stored in the `ITracker` parent`. + // Currently it allocates owns the name, so this is safe. If it is later refactored + // to not own the name, the name still has to outlive the `ITracker` parent, so + // this should still be safe. + StringRef m_trimmed_name; public: SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ); @@ -9379,14 +9738,14 @@ namespace TestCaseTracking { bool isComplete() const override; - static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef nameAndLocation ); + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ); void tryOpen(); void addInitialFilters( std::vector const& filters ); void addNextFilters( std::vector const& filters ); //! Returns filters active in this tracker - std::vector const& getFilters() const; + std::vector const& getFilters() const { return m_filters; } //! Returns whitespace-trimmed name of the tracked section StringRef trimmedName() const; }; @@ -9405,13 +9764,14 @@ using TestCaseTracking::SectionTracker; namespace Catch { - class IMutableContext; class IGeneratorTracker; class IConfig; + class IEventListener; + using IEventListenerPtr = Detail::unique_ptr; /////////////////////////////////////////////////////////////////////////// - class RunContext : public IResultCapture { + class RunContext final : public IResultCapture { public: RunContext( RunContext const& ) = delete; @@ -9440,7 +9800,7 @@ namespace Catch { AssertionReaction& reaction ) override; void handleUnexpectedInflightException ( AssertionInfo const& info, - std::string const& message, + std::string&& message, AssertionReaction& reaction ) override; void handleIncomplete ( AssertionInfo const& info ) override; @@ -9449,6 +9809,7 @@ namespace Catch { ResultWas::OfType resultType, AssertionReaction &reaction ) override; + void notifyAssertionStarted( AssertionInfo const& info ) override; bool sectionStarted( StringRef sectionName, SourceLineInfo const& sectionLineInfo, Counts& assertions ) override; @@ -9499,7 +9860,7 @@ namespace Catch { void resetAssertionInfo(); bool testForMissingAssertions( Counts& assertions ); - void assertionEnded( AssertionResult const& result ); + void assertionEnded( AssertionResult&& result ); void reportExpr ( AssertionInfo const &info, ResultWas::OfType resultType, @@ -9513,7 +9874,6 @@ namespace Catch { void handleUnfinishedSections(); TestRunInfo m_runInfo; - IMutableContext& m_context; TestCaseHandle const* m_activeTestCase = nullptr; ITracker* m_testCaseTracker = nullptr; Optional m_lastResult; @@ -9770,16 +10130,14 @@ namespace Catch { namespace Catch { - class TestCaseHandle; class IConfig; + class ITestInvoker; + class TestCaseHandle; class TestSpec; std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ); - bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ); - - void enforceNoDuplicateTestCases( std::vector const& functions ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); @@ -9808,18 +10166,6 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////// - class TestInvokerAsFunction final : public ITestInvoker { - using TestType = void(*)(); - TestType m_testAsFunction; - public: - TestInvokerAsFunction(TestType testAsFunction) noexcept: - m_testAsFunction(testAsFunction) {} - - void invoke() const override; - }; - - /////////////////////////////////////////////////////////////////////////// - } // end namespace Catch @@ -9955,7 +10301,7 @@ namespace Catch { // Calculates the length of the current line void calcLength(); - // Returns current indention width + // Returns current indentation width size_t indentSize() const; // Creates an indented and (optionally) suffixed string from @@ -10268,6 +10614,8 @@ namespace Catch { #define CATCH_MATCHERS_IMPL_HPP_INCLUDED +#include + namespace Catch { template @@ -10960,13 +11308,11 @@ namespace Catch { } template - bool match(RangeLike&& rng) const { - using std::begin; using std::end; - - return end(rng) != std::find_if(begin(rng), end(rng), - [&](auto const& elem) { - return m_eq(elem, m_desired); - }); + bool match( RangeLike&& rng ) const { + for ( auto&& elem : rng ) { + if ( m_eq( elem, m_desired ) ) { return true; } + } + return false; } }; @@ -11018,7 +11364,7 @@ namespace Catch { /** * Creates a matcher that checks whether a range contains a specific element. * - * Uses `eq` to do the comparisons + * Uses `eq` to do the comparisons, the element is provided on the rhs */ template ContainsElementMatcher Contains(T&& elem, Equality&& eq) { @@ -11107,6 +11453,11 @@ namespace Matchers { double m_margin; }; + //! Creates a matcher that accepts numbers within certain range of target + WithinAbsMatcher WithinAbs( double target, double margin ); + + + class WithinUlpsMatcher final : public MatcherBase { public: WithinUlpsMatcher( double target, @@ -11120,6 +11471,13 @@ namespace Matchers { Detail::FloatingPointKind m_type; }; + //! Creates a matcher that accepts doubles within certain ULP range of target + WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff); + //! Creates a matcher that accepts floats within certain ULP range of target + WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff); + + + // Given IEEE-754 format for floats and doubles, we can assume // that float -> double promotion is lossless. Given this, we can // assume that if we do the standard relative comparison of @@ -11136,13 +11494,6 @@ namespace Matchers { double m_epsilon; }; - //! Creates a matcher that accepts doubles within certain ULP range of target - WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff); - //! Creates a matcher that accepts floats within certain ULP range of target - WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff); - //! Creates a matcher that accepts numbers within certain range of target - WithinAbsMatcher WithinAbs(double target, double margin); - //! Creates a matcher that accepts doubles within certain relative range of target WithinRelMatcher WithinRel(double target, double eps); //! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target @@ -11152,6 +11503,17 @@ namespace Matchers { //! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target WithinRelMatcher WithinRel(float target); + + + class IsNaNMatcher final : public MatcherBase { + public: + IsNaNMatcher() = default; + bool match( double const& matchee ) const override; + std::string describe() const override; + }; + + IsNaNMatcher IsNaN(); + } // namespace Matchers } // namespace Catch @@ -11370,6 +11732,7 @@ namespace Catch { #ifndef CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED #define CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED + #include #include @@ -11394,13 +11757,19 @@ namespace Catch { template bool match( RangeLike&& rng ) const { - using std::begin; - using std::end; - return std::equal( begin(m_desired), - end(m_desired), - begin(rng), - end(rng), - m_predicate ); + auto rng_start = begin( rng ); + const auto rng_end = end( rng ); + auto target_start = begin( m_desired ); + const auto target_end = end( m_desired ); + + while (rng_start != rng_end && target_start != target_end) { + if (!m_predicate(*rng_start, *target_start)) { + return false; + } + ++rng_start; + ++target_start; + } + return rng_start == rng_end && target_start == target_end; } std::string describe() const override { @@ -11428,11 +11797,11 @@ namespace Catch { bool match( RangeLike&& rng ) const { using std::begin; using std::end; - return std::is_permutation( begin( m_desired ), - end( m_desired ), - begin( rng ), - end( rng ), - m_predicate ); + return Catch::Detail::is_permutation( begin( m_desired ), + end( m_desired ), + begin( rng ), + end( rng ), + m_predicate ); } std::string describe() const override { @@ -11482,7 +11851,7 @@ namespace Catch { /** * Creates a matcher that checks if all elements in a range are equal - * to all elements in another range, in some permuation. + * to all elements in another range, in some permutation. * * Uses to provided predicate `predicate` to do the comparisons */ @@ -11652,11 +12021,10 @@ namespace Matchers { // - a more general approach would be via a compare template that defaults // to using !=. but could be specialised for, e.g. std::vector etc // - then just call that directly - if (m_comparator.size() != v.size()) - return false; - for (std::size_t i = 0; i < v.size(); ++i) - if (m_comparator[i] != v[i]) - return false; + if ( m_comparator.size() != v.size() ) { return false; } + for ( std::size_t i = 0; i < v.size(); ++i ) { + if ( !( m_comparator[i] == v[i] ) ) { return false; } + } return true; } std::string describe() const override { @@ -12160,7 +12528,7 @@ namespace Catch { void skipTest(TestCaseInfo const&) override {} protected: - //! Should the cumulative base store the assertion expansion for succesful assertions? + //! Should the cumulative base store the assertion expansion for successful assertions? bool m_shouldStoreSuccesfulAssertions = true; //! Should the cumulative base store the assertion expansion for failed assertions? bool m_shouldStoreFailedAssertions = true; @@ -12467,7 +12835,8 @@ namespace Catch { //! independent on the reporter's concrete type void registerReporterImpl( std::string const& name, IReporterFactoryPtr reporterPtr ); - + //! Actually registers the factory, independent on listener's concrete type + void registerListenerImpl( Detail::unique_ptr listenerFactory ); } // namespace Detail class IEventListener; @@ -12528,7 +12897,7 @@ namespace Catch { public: ListenerRegistrar(StringRef listenerName) { - getMutableRegistryHub().registerListener( Detail::make_unique(listenerName) ); + registerListenerImpl( Detail::make_unique(listenerName) ); } }; } @@ -12549,7 +12918,7 @@ namespace Catch { CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace { \ Catch::ListenerRegistrar INTERNAL_CATCH_UNIQUE_NAME( \ - catch_internal_RegistrarFor )( #listenerType ); \ + catch_internal_RegistrarFor )( #listenerType##_catch_sr ); \ } \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION From e45d5923dc9c9913d11640dd3795b54d79de9d51 Mon Sep 17 00:00:00 2001 From: Ruben Shahoyan Date: Fri, 22 Sep 2023 07:52:48 +0200 Subject: [PATCH 090/324] Add CTP Lumi inputs to its CTF header (#11935) Co-authored-by: shahoian --- DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h | 4 +++- .../CTP/reconstruction/include/CTPReconstruction/CTFCoder.h | 2 ++ .../CTP/reconstruction/include/CTPReconstruction/CTFHelper.h | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h index 8481db8f6d7e5..eb6c2cb98c761 100644 --- a/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h @@ -34,8 +34,10 @@ struct CTFHeader : public o2::ctf::CTFDictHeader { uint32_t nTriggers = 0; /// number of triggers uint32_t firstOrbit = 0; /// orbit of 1st trigger uint16_t firstBC = 0; /// bc of 1st trigger + uint16_t inp1 = 0; /// lumiCounts input ID + uint16_t inp2 = 0; /// lumiCountsFV0 input ID - ClassDefNV(CTFHeader, 3); + ClassDefNV(CTFHeader, 4); }; /// wrapper for the Entropy-encoded trigger inputs and classes of the TF diff --git a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h index deef6149e0d0e..efe31c431d368 100644 --- a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h +++ b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h @@ -147,6 +147,8 @@ o2::ctf::CTFIOSize CTFCoder::decode(const CTF::base& ec, VTRG& data, LumiInfo& l lumi.nHBFCounted = header.lumiNHBFs; lumi.counts = header.lumiCounts; lumi.orbit = header.lumiOrbit; + lumi.inp1 = int(header.inp1); + lumi.inp2 = int(header.inp2); auto itInp = bytesInput.begin(); auto itCls = bytesClass.begin(); bool checkIROK = (mBCShift == 0); // need to check if CTP offset correction does not make the local time negative ? diff --git a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h index 89859e8cdbb3a..b2847a59ab3ff 100644 --- a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h +++ b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h @@ -39,7 +39,7 @@ class CTFHelper { CTFHeader h{o2::detectors::DetID::CTP, 0, 1, 0, // dummy timestamp, version 1.0 lumi.counts, lumi.countsFV0, lumi.nHBFCounted, lumi.orbit, - uint32_t(mData.size()), 0, 0}; + uint32_t(mData.size()), 0, 0, uint16_t(lumi.inp1), uint16_t(lumi.inp2)}; if (mData.size()) { h.firstOrbit = mData[0].intRecord.orbit; h.firstBC = mData[0].intRecord.bc; From 22e7feca5c31b5c686c367ab7b952321a6ef906e Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Fri, 22 Sep 2023 11:30:27 +0200 Subject: [PATCH 091/324] TRD raw stats add TFID info (#11888) --- .../TRD/include/DataFormatsTRD/RawDataStats.h | 4 +++- .../TRD/reconstruction/macros/checkRawStats.C | 16 ++++++++++++++-- Detectors/TRD/reconstruction/src/EventRecord.cxx | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h index acc241d55cf90..04ebd9c7eea3a 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h @@ -22,6 +22,7 @@ #include #include #include "DataFormatsTRD/Constants.h" +#include "CommonDataFormat/TFIDInfo.h" namespace o2::trd { @@ -149,6 +150,7 @@ class TRDDataCountersPerTimeFrame uint16_t mNTriggersCalib; // number of triggers with digit readout uint16_t mNTriggersTotal; // total number of triggers std::array mDataFormatRead{}; // We just keep the major version number + o2::dataformats::TFIDInfo mTFIDInfo; // keep track of TF ID void clear() { mLinkNoData.fill(0); @@ -167,7 +169,7 @@ class TRDDataCountersPerTimeFrame mNTriggersTotal = 0; mDataFormatRead.fill(0); }; - ClassDefNV(TRDDataCountersPerTimeFrame, 2); // primarily for serialisation so we can send this as a message in o2 + ClassDefNV(TRDDataCountersPerTimeFrame, 3); // primarily for serialisation so we can send this as a message in o2 }; } // namespace o2::trd diff --git a/Detectors/TRD/reconstruction/macros/checkRawStats.C b/Detectors/TRD/reconstruction/macros/checkRawStats.C index 96a6fa85a796c..82661a4d55d91 100644 --- a/Detectors/TRD/reconstruction/macros/checkRawStats.C +++ b/Detectors/TRD/reconstruction/macros/checkRawStats.C @@ -24,9 +24,10 @@ #include "DataFormatsTRD/RawDataStats.h" #include "DataFormatsTRD/Constants.h" #include "DataFormatsTRD/HelperMethods.h" - +#include #include #include +#include #include #endif @@ -81,12 +82,23 @@ void checkRawStats() c->Divide(2, 2); gStyle->SetOptStat(""); + std::vector tfIndices(chain.GetEntries()); + std::iota(tfIndices.begin(), tfIndices.end(), static_cast(0)); + std::vector tfCounters; + for (int iEntry = 0; iEntry < chain.GetEntries(); ++iEntry) { chain.GetEntry(iEntry); // for each TimeFrame there is one tree entry + tfCounters.push_back(rawstats.mTFIDInfo.tfCounter); + } + std::sort(tfIndices.begin(), tfIndices.end(), [&](size_t a, size_t b) { return tfCounters[a] < tfCounters[b]; }); + LOGP(info, "Got {} TFs in total from {} tree entries", tfCounters.size(), chain.GetEntries()); + + for (int iEntry = 0; iEntry < chain.GetEntries(); ++iEntry) { + chain.GetEntry(tfIndices[iEntry]); int triggerCounter = 0; for (const auto& stats : linkstats) { c->Update(); - c->SetTitle(TString::Format("TF %i, Trigger %i", iEntry, triggerCounter)); + c->SetTitle(TString::Format("Run %i: TF %u, Trigger %i", rawstats.mTFIDInfo.runNumber, rawstats.mTFIDInfo.tfCounter, triggerCounter)); for (int hcid = 0; hcid < MAXHALFCHAMBER; ++hcid) { int stackLayer = HelperMethods::getStack(hcid / 2) * NLAYER + HelperMethods::getLayer(hcid / 2); int sectorSide = (hcid / NHCPERSEC) * 2 + (hcid % 2); diff --git a/Detectors/TRD/reconstruction/src/EventRecord.cxx b/Detectors/TRD/reconstruction/src/EventRecord.cxx index ab9207d2fc74d..147b052a8ca3f 100644 --- a/Detectors/TRD/reconstruction/src/EventRecord.cxx +++ b/Detectors/TRD/reconstruction/src/EventRecord.cxx @@ -28,6 +28,7 @@ #include "Framework/InputRecordWalker.h" #include "DataFormatsTRD/Constants.h" +#include "DetectorsBase/TFIDInfoHelper.h" #include #include @@ -81,6 +82,7 @@ void EventRecordContainer::sendData(o2::framework::ProcessingContext& pc, bool g pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginTRD, "TRKTRGRD", 0, o2::framework::Lifetime::Timeframe}, triggers); if (generatestats) { accumulateStats(); + o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mTFStats.mTFIDInfo); pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginTRD, "RAWSTATS", 0, o2::framework::Lifetime::Timeframe}, mTFStats); } if (sendLinkStats) { From 641cd1145db555b24d37cc14663bd41b075aea51 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 21 Sep 2023 22:35:36 +0200 Subject: [PATCH 092/324] DPL: do not inject DISTSUBTIMEFRAME --- .../Core/src/ExternalFairMQDeviceProxy.cxx | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 3a3d1162b2a4a..6637309b3de1a 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -243,32 +243,43 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve unmatchedDescriptions.clear(); bool allFound = true; DataProcessingHeader const* dph = nullptr; + + // Do not check anything which has DISTSUBTIMEFRAME in it. + for (size_t pi = 0; pi < present.size(); ++pi) { + auto& spec = routes[pi].matcher; + if (DataSpecUtils::asConcreteDataTypeMatcher(spec).description == header::DataDescription("DISTSUBTIMEFRAME")) { + present[pi] = true; + continue; + } + } + for (int msgidx = 0; msgidx < parts.Size(); msgidx += 2) { const auto dh = o2::header::get(parts.At(msgidx)->GetData()); auto const sih = o2::header::get(parts.At(msgidx)->GetData()); if (sih != nullptr) { continue; } + if (parts.At(msgidx).get() == nullptr) { + LOG(error) << "unexpected nullptr found. Skipping message pair."; + continue; + } + // Copy the DataProcessingHeader from the first message. + if (dph == nullptr) { + dph = o2::header::get(parts.At(msgidx)->GetData()); + } + if (!dh) { + LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataHeader missing"; + if (msgidx > 0) { + --msgidx; + } + continue; + } for (size_t pi = 0; pi < present.size(); ++pi) { if (present[pi]) { continue; } + allFound = false; auto& spec = routes[pi].matcher; - if (parts.At(msgidx).get() == nullptr) { - LOG(error) << "unexpected nullptr found. Skipping message pair."; - continue; - } - // Copy the DataProcessingHeader from the first message. - if (dph == nullptr) { - dph = o2::header::get(parts.At(msgidx)->GetData()); - } - if (!dh) { - LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataHeader missing"; - if (msgidx > 0) { - --msgidx; - } - continue; - } OutputSpec query{dh->dataOrigin, dh->dataDescription, dh->subSpecification}; if (DataSpecUtils::match(spec, query)) { present[pi] = true; From 3b1cdc8ff92c350d071103fd6155b416aeb08f30 Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Thu, 21 Sep 2023 15:48:37 +0200 Subject: [PATCH 093/324] [EMCAL-795] Reject ALTRO bunches with impossible length and pages with impossible FEC ordering --- Detectors/EMCAL/base/src/RCUTrailer.cxx | 6 +- .../EMCALReconstruction/AltroDecoder.h | 16 ++++- .../include/EMCALReconstruction/RecoParam.h | 26 +++++++- .../EMCAL/reconstruction/src/AltroDecoder.cxx | 66 ++++++++++++++++++- .../EMCAL/reconstruction/src/RecoParam.cxx | 7 +- .../test/testMinorAltroDecodingError.cxx | 26 ++++++-- .../workflow/src/RawToCellConverterSpec.cxx | 7 +- 7 files changed, 134 insertions(+), 20 deletions(-) diff --git a/Detectors/EMCAL/base/src/RCUTrailer.cxx b/Detectors/EMCAL/base/src/RCUTrailer.cxx index 770f2857ac86a..8ab06d7a90bd9 100644 --- a/Detectors/EMCAL/base/src/RCUTrailer.cxx +++ b/Detectors/EMCAL/base/src/RCUTrailer.cxx @@ -62,7 +62,7 @@ void RCUTrailer::constructFromRawPayload(const gsl::span payload foundTrailerWords++; int parCode = (word >> 26) & 0xF; int parData = word & 0x3FFFFFF; - // std::cout << "Found trailer word 0x" << std::hex << word << "(Par code: " << std::dec << parCode << ", Par data: 0x" << std::hex << parData << std::dec << ")"; + // std::cout << "Found trailer word 0x" << std::hex << word << "(Par code: " << std::dec << parCode << ", Par data: 0x" << std::hex << parData << std::dec << ")" << std::endl; switch (parCode) { case 1: // ERR_REG1 @@ -226,8 +226,8 @@ void RCUTrailer::printStream(std::ostream& stream) const << "Sparse readout: " << (isSparseReadout() ? "yes" : "no") << "\n" << "AltroCFG1: 0x" << std::hex << mAltroConfig.mWord1 << "\n" << "AltroCFG2: 0x" << std::hex << mAltroConfig.mWord2 << "\n" - << "Sampling time: " << timesample << " ns\n" - << "L1 Phase: " << l1phase << " ns\n" + << "Sampling time: " << std::dec << timesample << " ns\n" + << "L1 Phase: " << std::dec << l1phase << " ns (" << mAltroConfig.mL1Phase << ")\n" << std::dec << std::fixed; if (errors.size()) { stream << "Errors: \n" diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h index e46c466356545..e5a9c59158828 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h @@ -11,6 +11,7 @@ #ifndef ALICEO2_EMCAL_ALTRODECODER_H #define ALICEO2_EMCAL_ALTRODECODER_H +#include #include #include #include @@ -157,7 +158,10 @@ class MinorAltroDecodingError BUNCH_HEADER_NULL, ///< Bunch header is 0 CHANNEL_END_PAYLOAD_UNEXPECT, ///< Unexpected end of payload (channel or trailer word in bunch words) CHANNEL_PAYLOAD_EXCEED, ///< Exceeding channel payload block - BUNCH_LENGTH_EXCEED ///< Bunch length exceeding channel payload size + CHANNEL_ORDER, ///< Channels not in increasing order + BUNCH_LENGTH_EXCEED, ///< Bunch length exceeding channel payload size + BUNCH_LENGTH_ALLOW_EXCEED, ///< Exceeds maximum allowed bunch length + BUNCH_STARTTIME ///< Bunch start time exceeding }; /// \brief Dummy constructor @@ -206,7 +210,7 @@ class MinorAltroDecodingError /// \brief Get the number of error types handled by the AltroDecoderError /// \return Number of error types - static constexpr int getNumberOfErrorTypes() noexcept { return 4; } + static constexpr int getNumberOfErrorTypes() noexcept { return 7; } /// \brief Get the name connected to the error type /// @@ -302,6 +306,13 @@ class AltroDecoder /// \brief Destructor ~AltroDecoder() = default; + /// \brief Set the max. allowed bunch length + /// \param maxBunchLength Max. allowed bunch lengths + /// + /// Rejects bunches in case the decoded bunch length or the + /// decoded start time exceeds the maximum allowed bunch length. + void setMaxBunchLength(int maxBunchLength) { mMaxBunchLength = maxBunchLength; } + /// \brief Decode the ALTRO stream /// \throw AltroDecoderError if the RCUTrailer or ALTRO payload cannot be decoded /// @@ -346,6 +357,7 @@ class AltroDecoder std::vector mChannels; ///< vector of channels in the raw stream std::vector mMinorDecodingErrors; ///< Container for minor (non-crashing) errors bool mChannelsInitialized = false; ///< check whether the channels are initialized + unsigned int mMaxBunchLength = UINT_MAX; ///< Max bunch length ClassDefNV(AltroDecoder, 1); }; diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RecoParam.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RecoParam.h index 98217825ab1ce..c675f57b3506a 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RecoParam.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RecoParam.h @@ -27,22 +27,46 @@ namespace emcal class RecoParam : public o2::conf::ConfigurableParamHelper { public: + /// \brief Destructor ~RecoParam() override = default; + /// \brief Get the average cell time shift + /// \return Average cell time shift double getCellTimeShiftNanoSec() const { return mCellTimeShiftNanoSec; } + + /// \brief Get noise threshold for LGnoHG error + /// \return Noise threshold double getNoiseThresholdLGnoHG() const { return mNoiseThresholdLGnoHG; } + + /// \brief Get the BC phase + /// \return BC phase int getPhaseBCmod4() const { return mPhaseBCmod4; } + /// \brief Get the max. allowed bunch length + /// \return Max. allowed bunch length + /// + /// In case of max. bunch length 0 the max. bunch length is auto-determined from + /// the RCU trailer + int getMaxAllowedBunchLength() const { return mMaxBunchLength; } + + /// \brief Print current reconstruction parameters to stream + /// \param stream Stream to print on void PrintStream(std::ostream& stream) const; private: double mNoiseThresholdLGnoHG = 10.; ///< Noise threshold applied to suppress LGnoHG error double mCellTimeShiftNanoSec = 470.; ///< Time shift applied on the cell time to center trigger peak around 0 int mPhaseBCmod4 = 1; ///< Rollback of the BC ID in the correction of the cell time for the BC mod 4 + unsigned int mMaxBunchLength = 15; ///< Max. allowed bunch length O2ParamDef(RecoParam, "EMCRecoParam"); }; -std::ostream& operator<<(std::ostream& stream, const RecoParam& s); + +/// \brief Streaming operator for the reconstruction parameters +/// \param stream Stream to print on +/// \param par RecoParams to be printed +/// \return Stream after printing the reco params +std::ostream& operator<<(std::ostream& stream, const RecoParam& par); } // namespace emcal namespace framework diff --git a/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx b/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx index 2df0890c2ef5b..e1b1294a6349d 100644 --- a/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx +++ b/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx @@ -63,6 +63,7 @@ void AltroDecoder::readChannels() int currentpos = 0; auto& buffer = mRawReader.getPayload().getPayloadWords(); auto maxpayloadsize = buffer.size() - mRCUTrailer.getTrailerSize(); + int lastFEC = -1; while (currentpos < maxpayloadsize) { auto currentword = buffer[currentpos++]; if (currentword >> 30 != 1) { @@ -75,6 +76,16 @@ void AltroDecoder::readChannels() uint16_t payloadsize = (channelheader >> 16) & 0x3FF; bool badchannel = (channelheader >> 29) & 0x1; + int currentfec = 10 * Channel::getBranchIndexFromHwAddress(hwaddress) + Channel::getFecIndexFromHwAddress(hwaddress); + // std::cout << "Branch: " << Channel::getBranchIndexFromHwAddress(hwaddress) << ", FEC " << Channel::getFecIndexFromHwAddress(hwaddress) << " -> " << currentfec << " (channel " << Channel::getChannelIndexFromHwAddress(hwaddress) << " )" << std::endl; + if (currentfec < lastFEC) { + // FECs are ordered by the SRU, breaking the order is a clear sign of data corruption + // std::cout << "Error Fec, current " << currentfec << ", last " << lastFEC << std::endl; + mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::CHANNEL_ORDER, channelheader, currentword); + continue; + } + lastFEC = currentfec; + /// decode all words for channel bool foundChannelError = false; int numberofwords = (payloadsize + 2) / 3; @@ -122,6 +133,18 @@ void AltroDecoder::readChannels() // we must break here as well, the bunch is cut and the pointer would be set to invalid memory break; } + // Raise minor decoding error in case the bunch length exceeds the maximum possible amount of samples + if ((unsigned int)bunchlength > mMaxBunchLength) { + mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::BUNCH_LENGTH_ALLOW_EXCEED, channelheader, 0); + // Same as above: if the bunch length exceeds the maximum possible bunch length it will for sure conflict with the next bunch + break; + } + // Raise minor decoding error in case the start timne the maximum possible amount of samples (resulting in negative first sample index) + if ((unsigned int)starttime > mMaxBunchLength) { + mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::BUNCH_STARTTIME, channelheader, 0); + // Also here we must break, out-of-bounds start time will create troubles in the raw fit + break; + } if (bunchlength == 0) { // skip bunches with bunch size 0, they don't contain any payload // Map error type to NULL header since header word is null @@ -186,6 +209,7 @@ int AltroDecoderError::errorTypeToInt(AltroErrType errortype) case AltroErrType::CHANNEL_ERROR: errorNumber = 7; break; + default: break; } @@ -328,12 +352,21 @@ int MinorAltroDecodingError::errorTypeToInt(MinorAltroErrType errortype) case MinorAltroErrType::CHANNEL_PAYLOAD_EXCEED: errorNumber = 1; break; - case MinorAltroErrType::BUNCH_HEADER_NULL: + case MinorAltroErrType::CHANNEL_ORDER: errorNumber = 2; break; - case MinorAltroErrType::BUNCH_LENGTH_EXCEED: + case MinorAltroErrType::BUNCH_HEADER_NULL: errorNumber = 3; break; + case MinorAltroErrType::BUNCH_LENGTH_EXCEED: + errorNumber = 4; + break; + case MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED: + errorNumber = 5; + break; + case MinorAltroErrType::BUNCH_STARTTIME: + errorNumber = 6; + break; }; return errorNumber; @@ -352,11 +385,20 @@ MinorAltroErrType MinorAltroDecodingError::intToErrorType(int errornumber) errorType = MinorAltroErrType::CHANNEL_PAYLOAD_EXCEED; break; case 2: - errorType = MinorAltroErrType::BUNCH_HEADER_NULL; + errorType = MinorAltroErrType::CHANNEL_ORDER; break; case 3: + errorType = MinorAltroErrType::BUNCH_HEADER_NULL; + break; + case 4: errorType = MinorAltroErrType::BUNCH_LENGTH_EXCEED; break; + case 5: + errorType = MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED; + break; + case 6: + errorType = MinorAltroErrType::BUNCH_STARTTIME; + break; default: break; } @@ -371,10 +413,16 @@ const char* MinorAltroDecodingError::getErrorTypeName(ErrorType_t errortype) return "ChannelEndPayloadUnexpected"; case MinorAltroErrType::CHANNEL_PAYLOAD_EXCEED: return "ChannelPayloadExceed"; + case MinorAltroErrType::CHANNEL_ORDER: + return "ChannelOrderError"; case MinorAltroErrType::BUNCH_HEADER_NULL: return "BunchHeaderNull"; case MinorAltroErrType::BUNCH_LENGTH_EXCEED: return "BunchLengthExceed"; + case MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED: + return "BunchLengthAllowExceed"; + case MinorAltroErrType::BUNCH_STARTTIME: + return "BunchStarttimeExceed"; }; return ""; } @@ -386,10 +434,16 @@ const char* MinorAltroDecodingError::getErrorTypeTitle(ErrorType_t errortype) return "Channel end unexpected"; case MinorAltroErrType::CHANNEL_PAYLOAD_EXCEED: return "Channel exceed"; + case MinorAltroErrType::CHANNEL_ORDER: + return "FEC order"; case MinorAltroErrType::BUNCH_HEADER_NULL: return "Bunch header null"; case MinorAltroErrType::BUNCH_LENGTH_EXCEED: return "Bunch length exceed"; + case MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED: + return "Bunch length impossible"; + case MinorAltroErrType::BUNCH_STARTTIME: + return "Bunch starttime exceed"; }; return ""; } @@ -401,10 +455,16 @@ const char* MinorAltroDecodingError::getErrorTypeDescription(ErrorType_t errorty return "Unexpected end of payload in altro channel payload!"; case MinorAltroErrType::CHANNEL_PAYLOAD_EXCEED: return "Trying to access out-of-bound payload!"; + case MinorAltroErrType::CHANNEL_ORDER: + return "Invalid FEC order"; case MinorAltroErrType::BUNCH_HEADER_NULL: return "Bunch header 0 or not configured!"; case MinorAltroErrType::BUNCH_LENGTH_EXCEED: return "Bunch length exceeding channel payload size!"; + case MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED: + return "Bunch length exceeding max. possible bunch size!"; + case MinorAltroErrType::BUNCH_STARTTIME: + return "Bunch start time outside range!"; }; return ""; } diff --git a/Detectors/EMCAL/reconstruction/src/RecoParam.cxx b/Detectors/EMCAL/reconstruction/src/RecoParam.cxx index 00f95b613d1e5..f80721ba9b88e 100644 --- a/Detectors/EMCAL/reconstruction/src/RecoParam.cxx +++ b/Detectors/EMCAL/reconstruction/src/RecoParam.cxx @@ -16,9 +16,9 @@ O2ParamImpl(o2::emcal::RecoParam); using namespace o2::emcal; -std::ostream& o2::emcal::operator<<(std::ostream& stream, const o2::emcal::RecoParam& s) +std::ostream& o2::emcal::operator<<(std::ostream& stream, const o2::emcal::RecoParam& par) { - s.PrintStream(stream); + par.PrintStream(stream); return stream; } @@ -28,5 +28,6 @@ void RecoParam::PrintStream(std::ostream& stream) const << "\n=============================================" << "\nTime offset (ns): " << mCellTimeShiftNanoSec << "\nNoise threshold HGLG suppression: " << mNoiseThresholdLGnoHG - << "\nPhase in BC mod 4 correction: " << mPhaseBCmod4; + << "\nPhase in BC mod 4 correction: " << mPhaseBCmod4 + << "\nMax number of ALTRO samples: " << mMaxBunchLength; } \ No newline at end of file diff --git a/Detectors/EMCAL/reconstruction/test/testMinorAltroDecodingError.cxx b/Detectors/EMCAL/reconstruction/test/testMinorAltroDecodingError.cxx index 785ace30e9307..472954a90e6df 100644 --- a/Detectors/EMCAL/reconstruction/test/testMinorAltroDecodingError.cxx +++ b/Detectors/EMCAL/reconstruction/test/testMinorAltroDecodingError.cxx @@ -23,23 +23,35 @@ namespace emcal BOOST_AUTO_TEST_CASE(MinorAltroDecodingError_test) { - BOOST_CHECK_EQUAL(MinorAltroDecodingError::getNumberOfErrorTypes(), 4); - std::array errornames = {{"ChannelEndPayloadUnexpected", + BOOST_CHECK_EQUAL(MinorAltroDecodingError::getNumberOfErrorTypes(), 7); + std::array errornames = {{"ChannelEndPayloadUnexpected", "ChannelPayloadExceed", + "ChannelOrderError", "BunchHeaderNull", - "BunchLengthExceed"}}, + "BunchLengthExceed", + "BunchLengthAllowExceed", + "BunchStarttimeExceed"}}, errortitles = {{"Channel end unexpected", "Channel exceed", + "FEC order", "Bunch header null", - "Bunch length exceed"}}, + "Bunch length exceed", + "Bunch length impossible", + "Bunch starttime exceed"}}, errordescriptions = {{"Unexpected end of payload in altro channel payload!", "Trying to access out-of-bound payload!", + "Invalid FEC order", "Bunch header 0 or not configured!", - "Bunch length exceeding channel payload size!"}}; - std::array errortypes = {{MinorAltroDecodingError::ErrorType_t::CHANNEL_END_PAYLOAD_UNEXPECT, + "Bunch length exceeding channel payload size!", + "Bunch length exceeding max. possible bunch size!", + "Bunch start time outside range!"}}; + std::array errortypes = {{MinorAltroDecodingError::ErrorType_t::CHANNEL_END_PAYLOAD_UNEXPECT, MinorAltroDecodingError::ErrorType_t::CHANNEL_PAYLOAD_EXCEED, + MinorAltroDecodingError::ErrorType_t::CHANNEL_ORDER, MinorAltroDecodingError::ErrorType_t::BUNCH_HEADER_NULL, - MinorAltroDecodingError::ErrorType_t::BUNCH_LENGTH_EXCEED}}; + MinorAltroDecodingError::ErrorType_t::BUNCH_LENGTH_EXCEED, + MinorAltroDecodingError::ErrorType_t::BUNCH_LENGTH_ALLOW_EXCEED, + MinorAltroDecodingError::ErrorType_t::BUNCH_STARTTIME}}; for (int errortype = 0; errortype < MinorAltroDecodingError::getNumberOfErrorTypes(); errortype++) { BOOST_CHECK_EQUAL(MinorAltroDecodingError::errorTypeToInt(errortypes[errortype]), errortype); BOOST_CHECK_EQUAL(MinorAltroDecodingError::intToErrorType(errortype), errortypes[errortype]); diff --git a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx index 86ae5a16e74b5..f2833afb0d230 100644 --- a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx +++ b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx @@ -114,7 +114,8 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) // container with BCid and feeID std::unordered_map> bcFreq; - double timeshift = RecoParam::Instance().getCellTimeShiftNanoSec(); // subtract offset in ns in order to center the time peak around the nominal delay + double timeshift = RecoParam::Instance().getCellTimeShiftNanoSec(); // subtract offset in ns in order to center the time peak around the nominal delay + auto maxBunchLengthRP = RecoParam::Instance().getMaxAllowedBunchLength(); // exclude bunches where either the start time or the bunch length is above the expected maximum constexpr auto originEMC = o2::header::gDataOriginEMC; constexpr auto descRaw = o2::header::gDataDescriptionRawData; @@ -216,6 +217,10 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) // use the altro decoder to decode the raw data, and extract the RCU trailer AltroDecoder decoder(rawreader); + if (maxBunchLengthRP) { + // apply user-defined max. bunch length + decoder.setMaxBunchLength(maxBunchLengthRP); + } // check the words of the payload exception in altrodecoder try { decoder.decode(); From 1584d178119cc1b16de2319ff6b7c91ce582c9d9 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 21 Sep 2023 22:04:16 +0200 Subject: [PATCH 094/324] GPU: Clarify some function names --- GPU/GPUTracking/Base/GPUReconstruction.cxx | 10 +++++++--- GPU/GPUTracking/Base/GPUReconstruction.h | 4 ++-- GPU/GPUTracking/Base/GPUReconstructionIncludes.h | 2 +- GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu | 4 ++-- GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h | 2 +- GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h | 2 +- GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx | 4 ++-- .../Base/opencl-common/GPUReconstructionOCL.cxx | 4 ++-- .../Base/opencl-common/GPUReconstructionOCL.h | 2 +- GPU/GPUTracking/Benchmark/standalone.cxx | 6 +++--- GPU/GPUTracking/Global/GPUChainTracking.cxx | 6 +++--- GPU/GPUTracking/Global/GPUChainTracking.h | 2 +- GPU/GPUTracking/Interface/GPUO2Interface.cxx | 2 +- 13 files changed, 27 insertions(+), 23 deletions(-) diff --git a/GPU/GPUTracking/Base/GPUReconstruction.cxx b/GPU/GPUTracking/Base/GPUReconstruction.cxx index 166c02889d439..a184672fee3bc 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.cxx +++ b/GPU/GPUTracking/Base/GPUReconstruction.cxx @@ -289,8 +289,8 @@ int GPUReconstruction::InitPhaseBeforeDevice() } } - UpdateSettings(); - GPUCA_GPUReconstructionUpdateDefailts(); + UpdateAutomaticProcessingSettings(); + GPUCA_GPUReconstructionUpdateDefaults(); if (!mProcessingSettings.trackletConstructorInPipeline) { mProcessingSettings.trackletSelectorInPipeline = false; } @@ -1059,9 +1059,13 @@ void GPUReconstruction::DumpSettings(const char* dir) } } -void GPUReconstruction::UpdateGRPSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p) +void GPUReconstruction::UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p) { mGRPSettings = *g; + if (p) { + mProcessingSettings.debugLevel = p->debugLevel; + mProcessingSettings.resetTimers = p->resetTimers; + } param().UpdateSettings(g, p); if (mInitialized) { WriteConstantParams(); diff --git a/GPU/GPUTracking/Base/GPUReconstruction.h b/GPU/GPUTracking/Base/GPUReconstruction.h index 190a2e3d2a7c2..8b56e46888e9b 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.h +++ b/GPU/GPUTracking/Base/GPUReconstruction.h @@ -240,7 +240,7 @@ class GPUReconstruction void SetResetTimers(bool reset) { mProcessingSettings.resetTimers = reset; } // May update also after Init() void SetDebugLevelTmp(int level) { mProcessingSettings.debugLevel = level; } // Temporarily, before calling SetSettings() GPUParam& GetNonConstParam() { return mHostConstantMem->param; } // Kind of hack, but needed for manual updates after SetSettings(), if the default configKeyValues parsing for SetSettings() is used. - void UpdateGRPSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p = nullptr); + void UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p = nullptr); void SetOutputControl(const GPUOutputControl& v) { mOutputControl = v; } void SetOutputControl(void* ptr, size_t size); void SetInputControl(void* ptr, size_t size); @@ -278,7 +278,7 @@ class GPUReconstruction void FreeRegisteredMemory(GPUMemoryResource* res); GPUReconstruction(const GPUSettingsDeviceBackend& cfg); // Constructor int InitPhaseBeforeDevice(); - virtual void UpdateSettings() {} + virtual void UpdateAutomaticProcessingSettings() {} virtual int InitDevice() = 0; int InitPhasePermanentMemory(); int InitPhaseAfterDevice(); diff --git a/GPU/GPUTracking/Base/GPUReconstructionIncludes.h b/GPU/GPUTracking/Base/GPUReconstructionIncludes.h index 6cbb80cc71dc9..77732623eee31 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionIncludes.h +++ b/GPU/GPUTracking/Base/GPUReconstructionIncludes.h @@ -39,7 +39,7 @@ #define RANDOM_ERROR //#define RANDOM_ERROR || rand() % 500 == 1 -#define GPUCA_GPUReconstructionUpdateDefailts() \ +#define GPUCA_GPUReconstructionUpdateDefaults() \ if (mProcessingSettings.trackletConstructorInPipeline < 0) { \ mProcessingSettings.trackletConstructorInPipeline = GPUCA_CONSTRUCTOR_IN_PIPELINE; \ } \ diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu index b115070c7aec3..bcf3ec33b61d6 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu @@ -124,9 +124,9 @@ void GPUReconstructionCUDA::GetITSTraits(std::unique_ptr } } -void GPUReconstructionCUDA::UpdateSettings() +void GPUReconstructionCUDA::UpdateAutomaticProcessingSettings() { - GPUCA_GPUReconstructionUpdateDefailts(); + GPUCA_GPUReconstructionUpdateDefaults(); } int GPUReconstructionCUDA::InitDevice_Runtime() diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h index 33da396652f83..6d1d43bdea768 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h @@ -63,7 +63,7 @@ class GPUReconstructionCUDA : public GPUReconstructionKernels GetThreadContext() override; bool CanQueryMaxMemory() override { return true; } diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h b/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h index 472e04100bbd8..44729cc4da58f 100644 --- a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h +++ b/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h @@ -41,7 +41,7 @@ class GPUReconstructionHIPBackend : public GPUReconstructionDeviceBase int InitDevice_Runtime() override; int ExitDevice_Runtime() override; - void UpdateSettings() override; + void UpdateAutomaticProcessingSettings() override; std::unique_ptr GetThreadContext() override; void SynchronizeGPU() override; diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx b/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx index 73177bad20660..b84deaf28ed1a 100644 --- a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx +++ b/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx @@ -241,9 +241,9 @@ void GPUReconstructionHIPBackend::GetITSTraits(std::unique_ptrmIOPtrs.tpcZS ? GPUReconstructionConvert::GetMaxTimeBin(*chainTracking->mIOPtrs.tpcZS) : chainTracking->mIOPtrs.tpcPackedDigits ? GPUReconstructionConvert::GetMaxTimeBin(*chainTracking->mIOPtrs.tpcPackedDigits) : GPUReconstructionConvert::GetMaxTimeBin(*chainTracking->mIOPtrs.clustersNative); printf("Max time bin set to %d\n", (int)grp.continuousMaxTimeBin); - rec->UpdateGRPSettings(&grp); + rec->UpdateSettings(&grp); if (recAsync) { - recAsync->UpdateGRPSettings(&grp); + recAsync->UpdateSettings(&grp); } if (recPipeline) { - recPipeline->UpdateGRPSettings(&grp); + recPipeline->UpdateSettings(&grp); } } } diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index f271afca78967..42017d515082e 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -607,7 +607,7 @@ void GPUChainTracking::SetTRDGeometry(std::unique_ptr&& g processors()->calibObjects.trdGeometry = mTRDGeometryU.get(); } -void GPUChainTracking::DoQueuedCalibUpdates(int stream) +void GPUChainTracking::DoQueuedUpdates(int stream) { if (mUpdateNewCalibObjects) { void** pSrc = (void**)&mNewCalibObjects; @@ -636,7 +636,7 @@ void GPUChainTracking::DoQueuedCalibUpdates(int stream) if (mNewCalibValues->newContinuousMaxTimeBin) { grp.continuousMaxTimeBin = mNewCalibValues->continuousMaxTimeBin; } - mRec->UpdateGRPSettings(&grp); + mRec->UpdateSettings(&grp); } } if ((mUpdateNewCalibObjects || mRec->slavesExist()) && mRec->IsGPU()) { @@ -666,7 +666,7 @@ int GPUChainTracking::RunChain() if (GetProcessingSettings().debugLevel >= 6) { *mDebugFile << "\n\nProcessing event " << mRec->getNEventsProcessed() << std::endl; } - DoQueuedCalibUpdates(0); + DoQueuedUpdates(0); mRec->getGeneralStepTimer(GeneralStep::Prepare).Start(); try { diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index cf8c9f04c1bb1..a81fee89f8c67 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -84,7 +84,7 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega bool SupportsDoublePipeline() override { return true; } int FinalizePipelinedProcessing() override; void ClearErrorCodes(bool cpuOnly = false); - void DoQueuedCalibUpdates(int stream); // Forces doing queue calib updates, don't call when you are not sure you are allowed to do so! + void DoQueuedUpdates(int stream); // Forces doing queue calib updates, don't call when you are not sure you are allowed to do so! bool QARanForTF() const { return mFractionalQAEnabled; } // Structures for input and output data diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index 684bf658a73e6..27f5cf30d03f7 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -156,7 +156,7 @@ void GPUO2Interface::DumpSettings() if (mConfig->configProcessing.doublePipeline) { throw std::runtime_error("Cannot dump events in double pipeline mode"); } - mCtx[0].mChain->DoQueuedCalibUpdates(-1); + mCtx[0].mChain->DoQueuedUpdates(-1); mCtx[0].mRec->DumpSettings(); } From 8b51bf89cf6cecb81ace7b34851f4a4a5770c9b5 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 21 Sep 2023 22:27:04 +0200 Subject: [PATCH 095/324] GPU TPC: Add option to downscale TPC dEdx computation --- .../TPC/include/DataFormatsTPC/dEdxInfo.h | 36 +++++++++---------- GPU/GPUTracking/Base/GPUParam.cxx | 13 ++++--- GPU/GPUTracking/Base/GPUParam.h | 2 +- GPU/GPUTracking/Base/GPUReconstruction.cxx | 7 ++-- GPU/GPUTracking/Definitions/GPUSettingsList.h | 1 + GPU/GPUTracking/Global/GPUChainTracking.cxx | 16 ++++++--- 6 files changed, 45 insertions(+), 30 deletions(-) diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/dEdxInfo.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/dEdxInfo.h index 63b64a50b63dc..bdf9c41aae421 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/dEdxInfo.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/dEdxInfo.h @@ -22,24 +22,24 @@ namespace o2 namespace tpc { struct dEdxInfo { - float dEdxTotIROC; - float dEdxTotOROC1; - float dEdxTotOROC2; - float dEdxTotOROC3; - float dEdxTotTPC; - float dEdxMaxIROC; - float dEdxMaxOROC1; - float dEdxMaxOROC2; - float dEdxMaxOROC3; - float dEdxMaxTPC; - unsigned char NHitsIROC; - unsigned char NHitsSubThresholdIROC; - unsigned char NHitsOROC1; - unsigned char NHitsSubThresholdOROC1; - unsigned char NHitsOROC2; - unsigned char NHitsSubThresholdOROC2; - unsigned char NHitsOROC3; - unsigned char NHitsSubThresholdOROC3; + float dEdxTotIROC = 0.f; + float dEdxTotOROC1 = 0.f; + float dEdxTotOROC2 = 0.f; + float dEdxTotOROC3 = 0.f; + float dEdxTotTPC = 0.f; + float dEdxMaxIROC = 0.f; + float dEdxMaxOROC1 = 0.f; + float dEdxMaxOROC2 = 0.f; + float dEdxMaxOROC3 = 0.f; + float dEdxMaxTPC = 0.f; + unsigned char NHitsIROC = 0; + unsigned char NHitsSubThresholdIROC = 0; + unsigned char NHitsOROC1 = 0; + unsigned char NHitsSubThresholdOROC1 = 0; + unsigned char NHitsOROC2 = 0; + unsigned char NHitsSubThresholdOROC2 = 0; + unsigned char NHitsOROC3 = 0; + unsigned char NHitsSubThresholdOROC3 = 0; ClassDefNV(dEdxInfo, 1); }; } // namespace tpc diff --git a/GPU/GPUTracking/Base/GPUParam.cxx b/GPU/GPUTracking/Base/GPUParam.cxx index cfdc0709bee20..5eb83c6457e9c 100644 --- a/GPU/GPUTracking/Base/GPUParam.cxx +++ b/GPU/GPUTracking/Base/GPUParam.cxx @@ -128,7 +128,7 @@ void GPUParam::SetDefaults(float solenoidBz) GPUTPCGMPolynomialFieldManager::GetPolynomialField(bzkG, polynomialField); } -void GPUParam::UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p) +void GPUParam::UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p, const GPURecoStepConfiguration* w) { if (g) { bzkG = g->solenoidBz; @@ -151,21 +151,24 @@ void GPUParam::UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessi par.resetTimers = p->resetTimers; UpdateRun3ClusterErrors(p->param.tpcErrorParamY, p->param.tpcErrorParamZ); } + if (w) { + par.dodEdx = w->steps.isSet(GPUDataTypes::RecoStep::TPCdEdx); + if (par.dodEdx && p && p->tpcDownscaledEdx != 0) { + par.dodEdx = (rand() % 100) < p->tpcDownscaledEdx; + } + } } void GPUParam::SetDefaults(const GPUSettingsGRP* g, const GPUSettingsRec* r, const GPUSettingsProcessing* p, const GPURecoStepConfiguration* w) { SetDefaults(g->solenoidBz); - if (w) { - par.dodEdx = w->steps.isSet(GPUDataTypes::RecoStep::TPCdEdx); - } if (r) { rec = *r; if (rec.fitPropagateBzOnly == -1) { rec.fitPropagateBzOnly = rec.tpc.nWays - 1; } } - UpdateSettings(g, p); + UpdateSettings(g, p, w); } void GPUParam::UpdateRun3ClusterErrors(const float* yErrorParam, const float* zErrorParam) diff --git a/GPU/GPUTracking/Base/GPUParam.h b/GPU/GPUTracking/Base/GPUParam.h index f6fe0ed950e09..5d8ae5dee4f86 100644 --- a/GPU/GPUTracking/Base/GPUParam.h +++ b/GPU/GPUTracking/Base/GPUParam.h @@ -79,7 +79,7 @@ struct GPUParam : public internal::GPUParam_t #ifndef GPUCA_GPUCODE void SetDefaults(float solenoidBz); void SetDefaults(const GPUSettingsGRP* g, const GPUSettingsRec* r = nullptr, const GPUSettingsProcessing* p = nullptr, const GPURecoStepConfiguration* w = nullptr); - void UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p = nullptr); + void UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p = nullptr, const GPURecoStepConfiguration* w = nullptr); void LoadClusterErrors(bool Print = 0); o2::base::Propagator* GetDefaultO2Propagator(bool useGPUField = false) const; void UpdateRun3ClusterErrors(const float* yErrorParam, const float* zErrorParam); diff --git a/GPU/GPUTracking/Base/GPUReconstruction.cxx b/GPU/GPUTracking/Base/GPUReconstruction.cxx index a184672fee3bc..e27e43eb41134 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.cxx +++ b/GPU/GPUTracking/Base/GPUReconstruction.cxx @@ -1061,12 +1061,15 @@ void GPUReconstruction::DumpSettings(const char* dir) void GPUReconstruction::UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p) { - mGRPSettings = *g; + if (g) { + mGRPSettings = *g; + } if (p) { mProcessingSettings.debugLevel = p->debugLevel; mProcessingSettings.resetTimers = p->resetTimers; } - param().UpdateSettings(g, p); + GPURecoStepConfiguration w = {mRecoSteps, mRecoStepsGPU, mRecoStepsInputs, mRecoStepsOutputs}; + param().UpdateSettings(g, p, &w); if (mInitialized) { WriteConstantParams(); } diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 590eab609b579..7322d6edeaef0 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -249,6 +249,7 @@ AddOption(lateO2MatLutProvisioningSize, unsigned int, 0u, "", 0, "Memory size to AddOption(throttleAlarms, bool, false, "", 0, "Throttle rate at which alarms are sent to the InfoLogger in online runs") AddOption(outputSanityCheck, bool, false, "", 0, "Run some simple sanity checks finding errors in the output") AddOption(tpcSingleSector, int, -1, "", 0, "Restrict TPC processing to a single sector") +AddOption(tpcDownscaledEdx, unsigned char, 0, "", 0, "If != 0, downscale dEdx processing (if enabled) to x %") AddVariable(eventDisplay, GPUCA_NAMESPACE::gpu::GPUDisplayFrontendInterface*, nullptr) AddSubConfig(GPUSettingsProcessingRTC, rtc) AddSubConfig(GPUSettingsProcessingParam, param) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 42017d515082e..01ee9f9d013a1 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -609,6 +609,8 @@ void GPUChainTracking::SetTRDGeometry(std::unique_ptr&& g void GPUChainTracking::DoQueuedUpdates(int stream) { + std::unique_ptr grp; + const GPUSettingsProcessing* p = nullptr; if (mUpdateNewCalibObjects) { void** pSrc = (void**)&mNewCalibObjects; void** pDst = (void**)&processors()->calibObjects; @@ -629,16 +631,22 @@ void GPUChainTracking::DoQueuedUpdates(int stream) UpdateGPUCalibObjects(stream, ptrsChanged ? nullptr : &mNewCalibObjects); } if (mNewCalibValues->newSolenoidField || mNewCalibValues->newContinuousMaxTimeBin) { - GPUSettingsGRP grp = mRec->GetGRPSettings(); + grp = std::make_unique(mRec->GetGRPSettings()); if (mNewCalibValues->newSolenoidField) { - grp.solenoidBz = mNewCalibValues->solenoidField; + grp->solenoidBz = mNewCalibValues->solenoidField; } if (mNewCalibValues->newContinuousMaxTimeBin) { - grp.continuousMaxTimeBin = mNewCalibValues->continuousMaxTimeBin; + grp->continuousMaxTimeBin = mNewCalibValues->continuousMaxTimeBin; } - mRec->UpdateSettings(&grp); } } + if (GetProcessingSettings().tpcDownscaledEdx != 0) { + p = &GetProcessingSettings(); + } + if (grp || p) { + mRec->UpdateSettings(grp.get(), p); + } + if ((mUpdateNewCalibObjects || mRec->slavesExist()) && mRec->IsGPU()) { UpdateGPUCalibObjectsPtrs(stream); // Reinitialize } From 4ff44d6f342d57eea7f820e336fab1ef5f0fa65f Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 21 Sep 2023 22:49:20 +0200 Subject: [PATCH 096/324] GPU Standalone Benchmark: fix enabling dEdx --- GPU/GPUTracking/Benchmark/standalone.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GPU/GPUTracking/Benchmark/standalone.cxx b/GPU/GPUTracking/Benchmark/standalone.cxx index b12d1dc3db0ef..6bff74b1d4705 100644 --- a/GPU/GPUTracking/Benchmark/standalone.cxx +++ b/GPU/GPUTracking/Benchmark/standalone.cxx @@ -415,7 +415,9 @@ int SetupReconstruction() if (configStandalone.testSyncAsync || configStandalone.testSync) { // Set settings for synchronous - steps.steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, 0); + if (configStandalone.rundEdx == -1) { + steps.steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, 0); + } recSet.useMatLUT = false; if (configStandalone.testSyncAsync) { procSet.eventDisplay = nullptr; From 108a915e387d6e08aceeeef9035c136306cd1d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Jacazio?= Date: Fri, 28 Jul 2023 11:03:54 +0200 Subject: [PATCH 097/324] Add labelled string array --- Framework/Core/include/Framework/Variant.h | 7 ++++++- Framework/Core/include/Framework/VariantJSONHelpers.h | 3 +++ Framework/Core/src/BoostOptionsRetriever.cxx | 1 + Framework/Core/src/ConfigParamsHelper.cxx | 1 + Framework/Core/src/PropertyTreeHelpers.cxx | 11 +++++++++++ Framework/Core/src/WorkflowSerializationHelpers.cxx | 4 ++++ Framework/Core/src/runDataProcessing.cxx | 3 +++ Framework/Core/test/test_Variants.cxx | 6 ++++++ 8 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Framework/Core/include/Framework/Variant.h b/Framework/Core/include/Framework/Variant.h index f0664bcdc3bd4..0c055cfb84b12 100644 --- a/Framework/Core/include/Framework/Variant.h +++ b/Framework/Core/include/Framework/Variant.h @@ -50,6 +50,7 @@ enum class VariantType : int { Int = 0, UInt64, Int8, Int16, + LabeledArrayString, Empty, Dict, Unknown }; @@ -77,7 +78,8 @@ constexpr auto isLabeledArray() { return (V == VariantType::LabeledArrayInt || V == VariantType::LabeledArrayFloat || - V == VariantType::LabeledArrayDouble); + V == VariantType::LabeledArrayDouble || + V == VariantType::LabeledArrayString); } template @@ -146,6 +148,7 @@ DECLARE_VARIANT_TRAIT(Array2D, Array2DDouble); DECLARE_VARIANT_TRAIT(LabeledArray, LabeledArrayInt); DECLARE_VARIANT_TRAIT(LabeledArray, LabeledArrayFloat); DECLARE_VARIANT_TRAIT(LabeledArray, LabeledArrayDouble); +DECLARE_VARIANT_TRAIT(LabeledArray, LabeledArrayString); template struct variant_array_symbol { @@ -216,6 +219,7 @@ DECLARE_VARIANT_TYPE(Array2D, Array2DDouble); DECLARE_VARIANT_TYPE(LabeledArray, LabeledArrayInt); DECLARE_VARIANT_TYPE(LabeledArray, LabeledArrayFloat); DECLARE_VARIANT_TYPE(LabeledArray, LabeledArrayDouble); +DECLARE_VARIANT_TYPE(LabeledArray, LabeledArrayString); template struct variant_array_element_type { @@ -239,6 +243,7 @@ DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(std::string, ArrayString); DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(int, LabeledArrayInt); DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(float, LabeledArrayFloat); DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(double, LabeledArrayDouble); +DECLARE_VARIANT_ARRAY_ELEMENT_TYPE(std::string, LabeledArrayString); template using variant_array_element_type_t = typename variant_array_element_type::type; diff --git a/Framework/Core/include/Framework/VariantJSONHelpers.h b/Framework/Core/include/Framework/VariantJSONHelpers.h index a09192d9954e7..ce998275d26b3 100644 --- a/Framework/Core/include/Framework/VariantJSONHelpers.h +++ b/Framework/Core/include/Framework/VariantJSONHelpers.h @@ -437,6 +437,9 @@ struct VariantJSONHelpers { case VariantType::LabeledArrayDouble: writeVariant(o, v); break; + case VariantType::LabeledArrayString: + writeVariant(o, v); + break; case VariantType::Dict: writeVariant(o, v); default: diff --git a/Framework/Core/src/BoostOptionsRetriever.cxx b/Framework/Core/src/BoostOptionsRetriever.cxx index 5f9381da9f0b3..fbf56a312cf66 100644 --- a/Framework/Core/src/BoostOptionsRetriever.cxx +++ b/Framework/Core/src/BoostOptionsRetriever.cxx @@ -97,6 +97,7 @@ void BoostOptionsRetriever::update(std::vector const& specs, case VariantType::LabeledArrayInt: case VariantType::LabeledArrayFloat: case VariantType::LabeledArrayDouble: + case VariantType::LabeledArrayString: case VariantType::Unknown: case VariantType::Empty: break; diff --git a/Framework/Core/src/ConfigParamsHelper.cxx b/Framework/Core/src/ConfigParamsHelper.cxx index 2f0c75c131f48..a7b32c86e3eca 100644 --- a/Framework/Core/src/ConfigParamsHelper.cxx +++ b/Framework/Core/src/ConfigParamsHelper.cxx @@ -101,6 +101,7 @@ void ConfigParamsHelper::populateBoostProgramOptions( case VariantType::LabeledArrayInt: case VariantType::LabeledArrayFloat: case VariantType::LabeledArrayDouble: + case VariantType::LabeledArrayString: // FIXME: for Dict we should probably allow parsing stuff // provided on the command line case VariantType::Dict: diff --git a/Framework/Core/src/PropertyTreeHelpers.cxx b/Framework/Core/src/PropertyTreeHelpers.cxx index 48bb4803b18b4..cf862b78e77b5 100644 --- a/Framework/Core/src/PropertyTreeHelpers.cxx +++ b/Framework/Core/src/PropertyTreeHelpers.cxx @@ -106,6 +106,9 @@ void PropertyTreeHelpers::populateDefaults(std::vector const& s case VariantType::LabeledArrayDouble: pt.put_child(key, labeledArrayToBranch(spec.defaultValue.get>())); break; + case VariantType::LabeledArrayString: + pt.put_child(key, labeledArrayToBranch(spec.defaultValue.get>())); + break; case VariantType::Unknown: case VariantType::Empty: default: @@ -320,6 +323,14 @@ void PropertyTreeHelpers::populate(std::vector const& schema, pt.put_child(key, labeledArrayToBranch(std::move(v))); } }; break; + case VariantType::LabeledArrayString: { + auto v = labeledArrayFromBranch(it.value()); + if (!replaceLabels(v, spec.defaultValue.get>())) { + pt.put_child(key, *it); + } else { + pt.put_child(key, labeledArrayToBranch(std::move(v))); + } + }; break; case VariantType::Unknown: case VariantType::Empty: default: diff --git a/Framework/Core/src/WorkflowSerializationHelpers.cxx b/Framework/Core/src/WorkflowSerializationHelpers.cxx index 3a33d4a14a734..ac182a27a70c5 100644 --- a/Framework/Core/src/WorkflowSerializationHelpers.cxx +++ b/Framework/Core/src/WorkflowSerializationHelpers.cxx @@ -507,6 +507,9 @@ struct WorkflowImporter : public rapidjson::BaseReaderHandler, case VariantType::LabeledArrayDouble: opt = std::make_unique(optionName, optionType, VariantJSONHelpers::read(is), HelpString{optionHelp}, optionKind); break; + case VariantType::LabeledArrayString: + opt = std::make_unique(optionName, optionType, VariantJSONHelpers::read(is), HelpString{optionHelp}, optionKind); + break; case VariantType::Dict: opt = std::make_unique(optionName, optionType, emptyDict(), HelpString{optionHelp}, optionKind); break; @@ -1191,6 +1194,7 @@ void WorkflowSerializationHelpers::dump(std::ostream& out, case VariantType::LabeledArrayInt: case VariantType::LabeledArrayFloat: case VariantType::LabeledArrayDouble: + case VariantType::LabeledArrayString: case VariantType::Dict: VariantJSONHelpers::write(oss, option.defaultValue); break; diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index 8651d25829963..9f92f85038057 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -1800,6 +1800,9 @@ int runStateMachine(DataProcessorSpecs const& workflow, case VariantType::LabeledArrayDouble: option.defaultValue = reg->get>(name); break; + case VariantType::LabeledArrayString: + option.defaultValue = reg->get>(name); + break; default: break; } diff --git a/Framework/Core/test/test_Variants.cxx b/Framework/Core/test/test_Variants.cxx index a5753e26925b3..d774fe160885b 100644 --- a/Framework/Core/test/test_Variants.cxx +++ b/Framework/Core/test/test_Variants.cxx @@ -218,14 +218,20 @@ TEST_CASE("Array2DTest") TEST_CASE("LabeledArrayTest") { float m[3][4] = {{0.1, 0.2, 0.3, 0.4}, {0.5, 0.6, 0.7, 0.8}, {0.9, 1.0, 1.1, 1.2}}; + std::string mS[3][4] = {{"a", "b", "c", "d"}, {"e", "f", "g", "h"}, {"i", "l", "m", "n"}}; std::string xl[] = {"c1", "c2", "c3", "c4"}; std::string yl[] = {"r1", "r2", "r3"}; LabeledArray laf{&m[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}}; + LabeledArray las{&mS[0][0], 3, 4, {"r1", "r2", "r3"}, {"c1", "c2", "c3", "c4"}}; for (auto i = 0u; i < 3; ++i) { for (auto j = 0u; j < 4; ++j) { REQUIRE(laf.get(yl[i].c_str(), xl[j].c_str()) == laf.get(i, j)); REQUIRE(laf.get(i, xl[j].c_str()) == laf.get(i, j)); REQUIRE(laf.get(yl[i].c_str(), j) == laf.get(i, j)); + + REQUIRE(las.get(yl[i].c_str(), xl[j].c_str()) == las.get(i, j)); + REQUIRE(las.get(i, xl[j].c_str()) == las.get(i, j)); + REQUIRE(las.get(yl[i].c_str(), j) == las.get(i, j)); } } } From ef2e60043b908bbabee03d0832433fb5bcaa302a Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 22 Sep 2023 20:40:21 +0200 Subject: [PATCH 098/324] Fix TPC CTF in the linkdef --- DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h b/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h index 5a7ce1b18920b..676a4e0144be0 100644 --- a/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h +++ b/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h @@ -48,7 +48,7 @@ #pragma link C++ class o2::tpc::CompressedClustersROOT - ; #pragma link C++ class o2::tpc::CTF + ; #pragma link C++ class o2::tpc::CTFHeader + ; -#pragma link C++ class o2::ctf::EncodedBlocks < o2::tpc::CTFHeader, 23, uint32_t> + ; +#pragma link C++ class o2::ctf::EncodedBlocks < o2::tpc::CTFHeader, 26, uint32_t> + ; #pragma link C++ enum o2::tpc::StatisticsType; #pragma link C++ class o2::tpc::TrackCuts + ; #pragma link C++ class o2::tpc::KrCluster + ; From 3f0a200247eaa8570c66ff305233ccc6d02a08c1 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 21 Sep 2023 19:19:34 +0200 Subject: [PATCH 099/324] DPL: Shorten and downscale message when injecting missing data --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 6637309b3de1a..d18ce84e29147 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -290,7 +290,7 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve // we increment by 2. msgidx = getFinalIndex(*dh, msgidx) - 2; if (allFound) { - break; + return; } } for (size_t pi = 0; pi < present.size(); ++pi) { @@ -300,7 +300,6 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve } if (unmatchedDescriptions.size() > 0) { - LOGP(info, "Found {}/{} data specs", present.size() - unmatchedDescriptions.size(), present.size()); std::string missing = ""; for (auto mi : unmatchedDescriptions) { if (dph == nullptr) { @@ -310,13 +309,13 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve continue; } auto& spec = routes[mi].matcher; - missing += "\n " + DataSpecUtils::describe(spec); + missing += " " + DataSpecUtils::describe(spec); // If we have a ConcreteDataMatcher, we can create a message with the correct header. // If we have a ConcreteDataTypeMatcher, we use 0xdeadbeef as subSpecification. ConcreteDataTypeMatcher concrete = DataSpecUtils::asConcreteDataTypeMatcher(spec); auto subSpec = DataSpecUtils::getOptionalSubSpec(spec); if (subSpec == std::nullopt) { - *subSpec = 0xdeadbeef; + *subSpec = 0xDEADBEEF; } o2::header::DataHeader dh; dh.dataOrigin = concrete.origin; @@ -333,7 +332,11 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve // add empty payload message parts.AddPart(device.NewMessageFor(channelName, 0, 0)); } - LOGP(error, "Missing data specs: {}", missing); + static int maxWarn = 10; // Correct would be o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef, but Framework does not depend on CommonUtils..., but not so critical since receives will send correct number of DEADBEEF messages + static int contDeadBeef = 0; + if (++contDeadBeef <= maxWarn) { + LOGP(error, "Found {}/{} data specs, missing data specs: {}, injecting 0xDEADBEEF", present.size() - unmatchedDescriptions.size(), present.size(), missing); + } } } From c2c984f015742dabf81028e6948097913a314834 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 21 Sep 2023 19:21:30 +0200 Subject: [PATCH 100/324] Sync workflow: inject missing data at raw-proxy level, and don't expect optional data from TPC --- GPU/Workflow/src/GPUWorkflowSpec.cxx | 2 +- prodtests/full-system-test/dpl-workflow.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 35a5ba77dacd1..e7ece6089e748 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -1021,7 +1021,7 @@ Inputs GPURecoWorkflowSpec::inputs() if (mSpecConfig.zsDecoder) { // All ZS raw data is published with subspec 0 by the o2-raw-file-reader-workflow and DataDistribution // creates subspec fom CRU and endpoint id, we create one single input route subscribing to all TPC/RAWDATA - inputs.emplace_back(InputSpec{"zsraw", ConcreteDataTypeMatcher{"TPC", "RAWDATA"}, Lifetime::Optional}); + inputs.emplace_back(InputSpec{"zsraw", ConcreteDataTypeMatcher{"TPC", "RAWDATA"}, Lifetime::Timeframe}); if (mSpecConfig.askDISTSTF) { inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); } diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 5aa0a57281487..4e3a87a3ab2da 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -387,7 +387,7 @@ if [[ ! -z $INPUT_DETECTOR_LIST ]]; then done done [[ ! -z ${TIMEFRAME_RATE_LIMIT:-} ]] && [[ $TIMEFRAME_RATE_LIMIT != 0 ]] && PROXY_CHANNEL+=";name=metric-feedback,type=pull,method=connect,address=ipc://${UDS_PREFIX}metric-feedback-${O2JOBID:-$NUMAID},transport=shmem,rateLogging=0" - add_W o2-dpl-raw-proxy "--dataspec \"$PROXY_INSPEC\" --readout-proxy \"--channel-config \\\"$PROXY_CHANNEL\\\"\" ${TIMEFRAME_SHM_LIMIT+--timeframes-shm-limit} ${TIMEFRAME_SHM_LIMIT:-}" "" 0 + add_W o2-dpl-raw-proxy "--dataspec \"$PROXY_INSPEC\" --inject-missing-data --readout-proxy \"--channel-config \\\"$PROXY_CHANNEL\\\"\" ${TIMEFRAME_SHM_LIMIT+--timeframes-shm-limit} ${TIMEFRAME_SHM_LIMIT:-}" "" 0 elif [[ $DIGITINPUT == 1 ]]; then [[ $NTIMEFRAMES != 1 ]] && { echo "Digit input works only with NTIMEFRAMES=1" 1>&2; exit 1; } DISABLE_DIGIT_ROOT_INPUT= From 6b40ac456a9bef552f1316ec102524319f0b788c Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 22 Sep 2023 11:39:13 +0200 Subject: [PATCH 101/324] DPL / TPC: Fix printing 0xDEADBEEF alarm when using RawPageSequencer --- Framework/Utils/CMakeLists.txt | 2 +- .../Utils/include/DPLUtils/DPLRawPageSequencer.h | 8 +++++++- Framework/Utils/include/DPLUtils/RawParser.h | 5 +++++ Framework/Utils/src/RawParser.cxx | 11 +++++++++++ GPU/Workflow/src/GPUWorkflowITS.cxx | 2 -- GPU/Workflow/src/GPUWorkflowSpec.cxx | 11 ----------- GPU/Workflow/src/GPUWorkflowTPC.cxx | 2 -- 7 files changed, 24 insertions(+), 17 deletions(-) diff --git a/Framework/Utils/CMakeLists.txt b/Framework/Utils/CMakeLists.txt index 5f2d495339a18..db234537a0b6f 100644 --- a/Framework/Utils/CMakeLists.txt +++ b/Framework/Utils/CMakeLists.txt @@ -19,7 +19,7 @@ o2_add_library(DPLUtils test/DPLBroadcasterMerger.cxx test/DPLOutputTest.cxx test/RawPageTestData.cxx - PUBLIC_LINK_LIBRARIES O2::Framework ROOT::Tree ROOT::TreePlayer) + PUBLIC_LINK_LIBRARIES O2::Framework ROOT::Tree ROOT::TreePlayer O2::CommonUtils) o2_add_executable(raw-proxy COMPONENT_NAME dpl diff --git a/Framework/Utils/include/DPLUtils/DPLRawPageSequencer.h b/Framework/Utils/include/DPLUtils/DPLRawPageSequencer.h index 9f05a925a84bd..785dc9e04bd45 100644 --- a/Framework/Utils/include/DPLUtils/DPLRawPageSequencer.h +++ b/Framework/Utils/include/DPLUtils/DPLRawPageSequencer.h @@ -98,10 +98,16 @@ class DPLRawPageSequencer int retVal = 0; for (auto const& ref : mInput) { auto size = DataRefUtils::getPayloadSize(ref); + const auto dh = DataRefUtils::getHeader(ref); + if (dh == nullptr) { + continue; + } if (size == 0) { + if (dh->subSpecification == 0xDEADBEEF) { + raw_parser::RawParserHelper::warnDeadBeef(dh); + } continue; } - const auto dh = DataRefUtils::getHeader(ref); auto const pageSize = rawparser_type::max_size; auto nPages = size / pageSize + (size % pageSize ? 1 : 0); if (!preCheck(ref.payload, dh->subSpecification)) { diff --git a/Framework/Utils/include/DPLUtils/RawParser.h b/Framework/Utils/include/DPLUtils/RawParser.h index ec302629f7200..2c35c008983f0 100644 --- a/Framework/Utils/include/DPLUtils/RawParser.h +++ b/Framework/Utils/include/DPLUtils/RawParser.h @@ -25,6 +25,10 @@ #include #include #include +namespace o2::header +{ +struct DataHeader; +} // namespace o2::header // FIXME: probably moved somewhere else namespace o2::framework @@ -87,6 +91,7 @@ struct RawParserHelper { static unsigned long sErrorScale; // Exponentionally downscale verbosity. static bool checkPrintError(size_t& localCounter); + static void warnDeadBeef(const o2::header::DataHeader* dh); }; /// @class ConcreteRawParser diff --git a/Framework/Utils/src/RawParser.cxx b/Framework/Utils/src/RawParser.cxx index e216c2c560793..2ec48c7f93d36 100644 --- a/Framework/Utils/src/RawParser.cxx +++ b/Framework/Utils/src/RawParser.cxx @@ -15,6 +15,8 @@ /// @brief Generic parser for consecutive raw pages #include "DPLUtils/RawParser.h" +#include "CommonUtils/VerbosityConfig.h" +#include "Headers/DataHeader.h" #include "fmt/format.h" #include @@ -40,6 +42,15 @@ bool RawParserHelper::checkPrintError(size_t& localCounter) return sErrors % sErrorScale == 0; } +void RawParserHelper::warnDeadBeef(const o2::header::DataHeader* dh) +{ + static auto maxWarn = o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef; + static int contDeadBeef = 0; + if (++contDeadBeef <= maxWarn) { + LOGP(alarm, "Found input [{}/{}/0xDEADBEEF] assuming no payload for all links in this TF{}", dh->dataOrigin.as(), dh->dataDescription.as(), contDeadBeef == maxWarn ? fmt::format(". {} such inputs in row received, stopping reporting", contDeadBeef) : ""); + } +} + const char* RDHFormatter::sFormatString = "{:>5} {:>4} {:>4} {:>4} {:>4} {:>3} {:>3} {:>3} {:>1} {:>2}"; void RDHFormatter::apply(std::ostream& os, V7 const& header, FormatSpec choice, const char* delimiter) { diff --git a/GPU/Workflow/src/GPUWorkflowITS.cxx b/GPU/Workflow/src/GPUWorkflowITS.cxx index 99ebb67ee0b2d..71e204147f08e 100644 --- a/GPU/Workflow/src/GPUWorkflowITS.cxx +++ b/GPU/Workflow/src/GPUWorkflowITS.cxx @@ -37,8 +37,6 @@ #include "TPCReconstruction/TPCFastTransformHelperO2.h" #include "DataFormatsTPC/Digit.h" #include "TPCFastTransform.h" -#include "DPLUtils/DPLRawParser.h" -#include "DPLUtils/DPLRawPageSequencer.h" #include "DetectorsBase/MatLayerCylSet.h" #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index e7ece6089e748..54d8b02e61640 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -70,7 +70,6 @@ #include "TRDBase/Geometry.h" #include "TRDBase/GeometryFlat.h" #include "ITSBase/GeometryTGeo.h" -#include "CommonUtils/VerbosityConfig.h" #include "CommonUtils/DebugStreamer.h" #include "GPUReconstructionConvert.h" #include "DetectorsRaw/RDHUtils.h" @@ -413,14 +412,6 @@ void GPURecoWorkflowSpec::processInputs(ProcessingContext& pc, A& tpcZSmetaPoint (feeLinkID == o2::tpc::rdh_utils::DLBZSLinkID && (rdhLink == o2::tpc::rdh_utils::UserLogicLinkID || rdhLink == o2::tpc::rdh_utils::DLBZSLinkID || rdhLink == 0))); }; auto insertPages = [&tpcZSmetaPointers, &tpcZSmetaSizes, checkForZSData](const char* ptr, size_t count, uint32_t subSpec) -> void { - if (subSpec == 0xdeadbeef) { - auto maxWarn = o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef; - static int contDeadBeef = 0; - if (++contDeadBeef <= maxWarn) { - LOGP(alarm, "Found input [TPC/RAWDATA/0xdeadbeef] assuming no payload for all links in this TF{}", contDeadBeef == maxWarn ? fmt::format(". {} such inputs in row received, stopping reporting", contDeadBeef) : ""); - } - return; - } if (checkForZSData(ptr, subSpec)) { int rawcru = o2::tpc::rdh_utils::getCRU(ptr); int rawendpoint = o2::tpc::rdh_utils::getEndPoint(ptr); @@ -428,8 +419,6 @@ void GPURecoWorkflowSpec::processInputs(ProcessingContext& pc, A& tpcZSmetaPoint tpcZSmetaSizes[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(count); } }; - // the sequencer processes all inputs matching the filter and finds sequences of consecutive - // raw pages based on the matcher predicate, and calls the inserter for each sequence if (DPLRawPageSequencer(pc.inputs(), filter)(isSameRdh, insertPages, checkForZSData)) { debugTFDump = true; static unsigned int nErrors = 0; diff --git a/GPU/Workflow/src/GPUWorkflowTPC.cxx b/GPU/Workflow/src/GPUWorkflowTPC.cxx index 578d35a72258a..f41902021577a 100644 --- a/GPU/Workflow/src/GPUWorkflowTPC.cxx +++ b/GPU/Workflow/src/GPUWorkflowTPC.cxx @@ -37,8 +37,6 @@ #include "TPCReconstruction/TPCFastTransformHelperO2.h" #include "DataFormatsTPC/Digit.h" #include "TPCFastTransform.h" -#include "DPLUtils/DPLRawParser.h" -#include "DPLUtils/DPLRawPageSequencer.h" #include "DetectorsBase/MatLayerCylSet.h" #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GeometryManager.h" From 586fe6eb8293ce9f0529c919c082106b2f722141 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 22 Sep 2023 13:19:40 +0200 Subject: [PATCH 102/324] GPU: Fix initialization of the 2 GPUReconstruction instances for double-pipeline mode --- GPU/GPUTracking/Base/GPUReconstruction.cxx | 2 +- GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu | 6 ++++-- GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx | 4 ++-- GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx | 2 +- GPU/GPUTracking/Interface/GPUO2Interface.cxx | 5 ++++- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/GPU/GPUTracking/Base/GPUReconstruction.cxx b/GPU/GPUTracking/Base/GPUReconstruction.cxx index e27e43eb41134..8dafe36054794 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.cxx +++ b/GPU/GPUTracking/Base/GPUReconstruction.cxx @@ -1194,7 +1194,7 @@ GPUReconstruction* GPUReconstruction::CreateInstance(const GPUSettingsDeviceBack retVal = CreateInstance(cfg2); } } else { - GPUInfo("Created GPUReconstruction instance for device type %s (%u) %s", GPUDataTypes::DEVICE_TYPE_NAMES[type], type, cfg.master ? " (slave)" : ""); + GPUInfo("Created GPUReconstruction instance for device type %s (%u)%s", GPUDataTypes::DEVICE_TYPE_NAMES[type], type, cfg.master ? " (slave)" : ""); } return retVal; diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu index bcf3ec33b61d6..269b3452b7d94 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu @@ -335,8 +335,6 @@ int GPUReconstructionCUDA::InitDevice_Runtime() } dummyInitKernel<<>>(mDeviceMemoryBase); - GPUInfo("CUDA Initialisation successfull (Device %d: %s (Frequency %d, Cores %d), %lld / %lld bytes host / global memory, Stack frame %d, Constant memory %lld)", mDeviceId, cudaDeviceProp.name, cudaDeviceProp.clockRate, cudaDeviceProp.multiProcessorCount, (long long int)mHostMemorySize, - (long long int)mDeviceMemorySize, (int)GPUCA_GPU_STACK_SIZE, (long long int)gGPUConstantMemBufferSize); #ifndef GPUCA_ALIROOT_LIB if (mProcessingSettings.rtc.enable) { @@ -363,6 +361,8 @@ int GPUReconstructionCUDA::InitDevice_Runtime() } #endif mDeviceConstantMem = (GPUConstantMem*)devPtrConstantMem; + + GPUInfo("CUDA Initialisation successfull (Device %d: %s (Frequency %d, Cores %d), %lld / %lld bytes host / global memory, Stack frame %d, Constant memory %lld)", mDeviceId, cudaDeviceProp.name, cudaDeviceProp.clockRate, cudaDeviceProp.multiProcessorCount, (long long int)mHostMemorySize, (long long int)mDeviceMemorySize, (int)GPUCA_GPU_STACK_SIZE, (long long int)gGPUConstantMemBufferSize); } else { GPUReconstructionCUDA* master = dynamic_cast(mMaster); mDeviceId = master->mDeviceId; @@ -375,6 +375,8 @@ int GPUReconstructionCUDA::InitDevice_Runtime() std::copy(master->mDeviceConstantMemRTC.begin(), master->mDeviceConstantMemRTC.end(), mDeviceConstantMemRTC.begin()); mInternals = master->mInternals; GPUFailedMsg(cudaSetDevice(mDeviceId)); + + GPUInfo("CUDA Initialized from master"); } for (unsigned int i = 0; i < mEvents.size(); i++) { diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx b/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx index b84deaf28ed1a..999e96c9823a9 100644 --- a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx +++ b/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip.cxx @@ -437,8 +437,7 @@ int GPUReconstructionHIPBackend::InitDevice_Runtime() mDeviceConstantMem = (GPUConstantMem*)devPtrConstantMem; hipLaunchKernelGGL(HIP_KERNEL_NAME(dummyInitKernel), dim3(mBlockCount), dim3(256), 0, 0, mDeviceMemoryBase); - GPUInfo("HIP Initialisation successfull (Device %d: %s (Frequency %d, Cores %d), %lld / %lld bytes host / global memory, Stack frame %d, Constant memory %lld)", mDeviceId, hipDeviceProp.name, hipDeviceProp.clockRate, hipDeviceProp.multiProcessorCount, (long long int)mHostMemorySize, - (long long int)mDeviceMemorySize, (int)GPUCA_GPU_STACK_SIZE, (long long int)gGPUConstantMemBufferSize); + GPUInfo("HIP Initialisation successfull (Device %d: %s (Frequency %d, Cores %d), %lld / %lld bytes host / global memory, Stack frame %d, Constant memory %lld)", mDeviceId, hipDeviceProp.name, hipDeviceProp.clockRate, hipDeviceProp.multiProcessorCount, (long long int)mHostMemorySize, (long long int)mDeviceMemorySize, (int)GPUCA_GPU_STACK_SIZE, (long long int)gGPUConstantMemBufferSize); } else { GPUReconstructionHIPBackend* master = dynamic_cast(mMaster); mDeviceId = master->mDeviceId; @@ -449,6 +448,7 @@ int GPUReconstructionHIPBackend::InitDevice_Runtime() mDeviceConstantMem = master->mDeviceConstantMem; mInternals = master->mInternals; GPUFailedMsgI(hipSetDevice(mDeviceId)); + GPUInfo("HIP Initialized from master"); } for (unsigned int i = 0; i < mEvents.size(); i++) { hipEvent_t* events = (hipEvent_t*)mEvents[i].data(); diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index 2e64d91b62e05..3c193d21a65c6 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -199,7 +199,7 @@ std::pair GPUChainTracking::TPCClusterizerDecodeZSCo const TPCZSHDR* const hdr = (const TPCZSHDR*)(rdh_utils::getLink(o2::raw::RDHUtils::getFEEID(*rdh)) == rdh_utils::DLBZSLinkID ? (page + o2::raw::RDHUtils::getMemorySize(*rdh) - sizeof(TPCZSHDRV2)) : (page + sizeof(o2::header::RAWDataHeader))); if (mCFContext->zsVersion == -1) { mCFContext->zsVersion = hdr->version; - if (GetProcessingSettings().param.tpcTriggerHandling && mCFContext->zsVersion < ZSVersion::ZSVersionDenseLinkBased) { + if (GetProcessingSettings().param.tpcTriggerHandling && mCFContext->zsVersion < ZSVersion::ZSVersionDenseLinkBased) { // TODO: Move tpcTriggerHandling to recoSteps bitmask static bool errorShown = false; if (errorShown == false) { GPUAlarm("Trigger handling only possible with TPC Dense Link Based data, received version %d, disabling", mCFContext->zsVersion); diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index 27f5cf30d03f7..7d353f86577bd 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -77,6 +77,8 @@ int GPUO2Interface::Initialize(const GPUO2InterfaceConfiguration& config) mCtx.reset(nullptr); return 1; } + } + for (unsigned int i = 0; i < mNContexts; i++) { mCtx[i].mChain = mCtx[i].mRec->AddChain(mConfig->configInterface.maxTPCHits, mConfig->configInterface.maxTRDTracklets); mCtx[i].mChain->mConfigDisplay = &mConfig->configDisplay; mCtx[i].mChain->mConfigQA = &mConfig->configQA; @@ -96,7 +98,8 @@ int GPUO2Interface::Initialize(const GPUO2InterfaceConfiguration& config) dummy.set([](size_t size) -> void* {throw std::runtime_error("invalid output memory request, no common output buffer set"); return nullptr; }); mCtx[i].mRec->SetOutputControl(dummy); } - + } + for (unsigned int i = 0; i < mNContexts; i++) { if (i == 0 && mCtx[i].mRec->Init()) { mNContexts = 0; mCtx.reset(nullptr); From 42adc0b7409c62bce09b659b6c3cf219c0155c99 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 22 Sep 2023 14:17:31 +0200 Subject: [PATCH 103/324] GPU: Add gpu-reconstruction-prepare device, forwarding the pointers to gpu-reconstruction --- .../include/GPUWorkflow/GPUWorkflowSpec.h | 4 +- GPU/Workflow/src/GPUWorkflowITS.cxx | 2 +- GPU/Workflow/src/GPUWorkflowSpec.cxx | 445 ++++++++++-------- GPU/Workflow/src/gpu-reco-workflow.cxx | 22 +- prodtests/full-system-test/dpl-workflow.sh | 4 +- 5 files changed, 265 insertions(+), 212 deletions(-) diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index 347dc82eb9f06..f692e1952095a 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -88,6 +88,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task struct Config { int itsTriggerType = 0; int lumiScaleMode = 0; + int enableDoublePipeline = 0; bool decompressTPC = false; bool decompressTPCFromROOT = false; bool caClusterer = false; @@ -149,8 +150,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task int runITSTracking(o2::framework::ProcessingContext& pc); CompletionPolicyData* mPolicyData; - std::unique_ptr> mParser; - std::unique_ptr mTracker; + std::unique_ptr mGPUReco; std::unique_ptr mDisplayFrontend; std::unique_ptr mFastTransform; std::unique_ptr mFastTransformRef; diff --git a/GPU/Workflow/src/GPUWorkflowITS.cxx b/GPU/Workflow/src/GPUWorkflowITS.cxx index 71e204147f08e..3c621d4d9d66e 100644 --- a/GPU/Workflow/src/GPUWorkflowITS.cxx +++ b/GPU/Workflow/src/GPUWorkflowITS.cxx @@ -308,7 +308,7 @@ void GPURecoWorkflowSpec::initFunctionITS(InitContext& ic) std::transform(mITSMode.begin(), mITSMode.end(), mITSMode.begin(), [](unsigned char c) { return std::tolower(c); }); o2::its::VertexerTraits* vtxTraits = nullptr; o2::its::TrackerTraits* trkTraits = nullptr; - mTracker->GetITSTraits(trkTraits, vtxTraits, mITSTimeFrame); + mGPUReco->GetITSTraits(trkTraits, vtxTraits, mITSTimeFrame); mITSVertexer = std::make_unique(vtxTraits); mITSTracker = std::make_unique(trkTraits); mITSVertexer->adoptTimeFrame(*mITSTimeFrame); diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 54d8b02e61640..77688ac875790 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -122,119 +122,120 @@ void GPURecoWorkflowSpec::init(InitContext& ic) { GRPGeomHelper::instance().setRequest(mGGR); GPUO2InterfaceConfiguration& config = *mConfig.get(); - { - mParser = std::make_unique>(); - mTracker = std::make_unique(); - - // Create configuration object and fill settings - mConfig->configGRP.solenoidBz = 0; - mTFSettings->hasSimStartOrbit = 1; - auto& hbfu = o2::raw::HBFUtils::Instance(); - mTFSettings->simStartOrbit = hbfu.getFirstIRofTF(o2::InteractionRecord(0, hbfu.orbitFirstSampled)).orbit; - - *mConfParam = mConfig->ReadConfigurableParam(); - if (mConfParam->display) { - mDisplayFrontend.reset(GPUDisplayFrontendInterface::getFrontend(mConfig->configDisplay.displayFrontend.c_str())); - mConfig->configProcessing.eventDisplay = mDisplayFrontend.get(); - if (mConfig->configProcessing.eventDisplay != nullptr) { - LOG(info) << "Event display enabled"; - } else { - throw std::runtime_error("GPU Event Display frontend could not be created!"); - } - } - mAutoSolenoidBz = mConfParam->solenoidBz == -1e6f; - mAutoContinuousMaxTimeBin = mConfig->configGRP.continuousMaxTimeBin == -1; - if (mAutoContinuousMaxTimeBin) { - mConfig->configGRP.continuousMaxTimeBin = (256 * o2::constants::lhc::LHCMaxBunches + 2 * o2::tpc::constants::LHCBCPERTIMEBIN - 2) / o2::tpc::constants::LHCBCPERTIMEBIN; - } - if (mConfig->configProcessing.deviceNum == -2) { - int myId = ic.services().get().inputTimesliceId; - int idMax = ic.services().get().maxInputTimeslices; - mConfig->configProcessing.deviceNum = myId; - LOG(info) << "GPU device number selected from pipeline id: " << myId << " / " << idMax; - } - if (mConfig->configProcessing.debugLevel >= 3 && mVerbosity == 0) { - mVerbosity = 1; - } - mConfig->configProcessing.runMC = mSpecConfig.processMC; - if (mSpecConfig.outputQA) { - if (!mSpecConfig.processMC && !mConfig->configQA.clusterRejectionHistograms) { - throw std::runtime_error("Need MC information to create QA plots"); - } - if (!mSpecConfig.processMC) { - mConfig->configQA.noMC = true; - } - mConfig->configQA.shipToQC = true; - if (!mConfig->configProcessing.runQA) { - mConfig->configQA.enableLocalOutput = false; - mQATaskMask = (mSpecConfig.processMC ? 15 : 0) | (mConfig->configQA.clusterRejectionHistograms ? 32 : 0); - mConfig->configProcessing.runQA = -mQATaskMask; - } - } - mConfig->configReconstruction.tpc.nWaysOuter = true; - mConfig->configInterface.outputToExternalBuffers = true; - if (mConfParam->synchronousProcessing) { - mConfig->configReconstruction.useMatLUT = false; - } - - // Configure the "GPU workflow" i.e. which steps we run on the GPU (or CPU) - if (mSpecConfig.outputTracks || mSpecConfig.outputCompClusters || mSpecConfig.outputCompClustersFlat) { - mConfig->configWorkflow.steps.set(GPUDataTypes::RecoStep::TPCConversion, - GPUDataTypes::RecoStep::TPCSliceTracking, - GPUDataTypes::RecoStep::TPCMerging); - mConfig->configWorkflow.outputs.set(GPUDataTypes::InOutType::TPCMergedTracks); - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, mConfParam->rundEdx == -1 ? !mConfParam->synchronousProcessing : mConfParam->rundEdx); - } - if (mSpecConfig.outputCompClusters || mSpecConfig.outputCompClustersFlat) { - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, true); - mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, true); - } - mConfig->configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCClusters); - if (mSpecConfig.caClusterer) { // Override some settings if we have raw data as input - mConfig->configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCRaw); - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCClusterFinding, true); - mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, true); - } - if (mSpecConfig.decompressTPC) { - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, false); - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCDecompression, true); - mConfig->configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCCompressedClusters); - mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, true); - mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, false); - if (mTPCSectorMask != 0xFFFFFFFFF) { - throw std::invalid_argument("Cannot run TPC decompression with a sector mask"); - } + // Create configuration object and fill settings + mConfig->configGRP.solenoidBz = 0; + mTFSettings->hasSimStartOrbit = 1; + auto& hbfu = o2::raw::HBFUtils::Instance(); + mTFSettings->simStartOrbit = hbfu.getFirstIRofTF(o2::InteractionRecord(0, hbfu.orbitFirstSampled)).orbit; + + *mConfParam = mConfig->ReadConfigurableParam(); + if (mConfParam->display) { + mDisplayFrontend.reset(GPUDisplayFrontendInterface::getFrontend(mConfig->configDisplay.displayFrontend.c_str())); + mConfig->configProcessing.eventDisplay = mDisplayFrontend.get(); + if (mConfig->configProcessing.eventDisplay != nullptr) { + LOG(info) << "Event display enabled"; + } else { + throw std::runtime_error("GPU Event Display frontend could not be created!"); } - if (mSpecConfig.runTRDTracking) { - mConfig->configWorkflow.inputs.setBits(GPUDataTypes::InOutType::TRDTracklets, true); - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TRDTracking, true); + } + + mAutoSolenoidBz = mConfParam->solenoidBz == -1e6f; + mAutoContinuousMaxTimeBin = mConfig->configGRP.continuousMaxTimeBin == -1; + if (mAutoContinuousMaxTimeBin) { + mConfig->configGRP.continuousMaxTimeBin = (256 * o2::constants::lhc::LHCMaxBunches + 2 * o2::tpc::constants::LHCBCPERTIMEBIN - 2) / o2::tpc::constants::LHCBCPERTIMEBIN; + } + if (mConfig->configProcessing.deviceNum == -2) { + int myId = ic.services().get().inputTimesliceId; + int idMax = ic.services().get().maxInputTimeslices; + mConfig->configProcessing.deviceNum = myId; + LOG(info) << "GPU device number selected from pipeline id: " << myId << " / " << idMax; + } + if (mConfig->configProcessing.debugLevel >= 3 && mVerbosity == 0) { + mVerbosity = 1; + } + mConfig->configProcessing.runMC = mSpecConfig.processMC; + if (mSpecConfig.outputQA) { + if (!mSpecConfig.processMC && !mConfig->configQA.clusterRejectionHistograms) { + throw std::runtime_error("Need MC information to create QA plots"); } - if (mSpecConfig.runITSTracking) { - mConfig->configWorkflow.inputs.setBits(GPUDataTypes::InOutType::ITSClusters, true); - mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::ITSTracks, true); - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::ITSTracking, true); + if (!mSpecConfig.processMC) { + mConfig->configQA.noMC = true; } - if (mSpecConfig.outputSharedClusterMap) { - mConfig->configProcessing.outputSharedClusterMap = true; + mConfig->configQA.shipToQC = true; + if (!mConfig->configProcessing.runQA) { + mConfig->configQA.enableLocalOutput = false; + mQATaskMask = (mSpecConfig.processMC ? 15 : 0) | (mConfig->configQA.clusterRejectionHistograms ? 32 : 0); + mConfig->configProcessing.runQA = -mQATaskMask; } - mConfig->configProcessing.createO2Output = mSpecConfig.outputTracks ? 2 : 0; // Disable O2 TPC track format output if no track output requested - mConfig->configProcessing.param.tpcTriggerHandling = mSpecConfig.tpcTriggerHandling; + } + mConfig->configReconstruction.tpc.nWaysOuter = true; + mConfig->configInterface.outputToExternalBuffers = true; + if (mConfParam->synchronousProcessing) { + mConfig->configReconstruction.useMatLUT = false; + } - if (mConfParam->transformationFile.size() || mConfParam->transformationSCFile.size()) { - LOG(fatal) << "Deprecated configurable param options GPU_global.transformationFile or transformationSCFile used\n" - << "Instead, link the corresponding file as /TPC/Calib/CorrectionMap/snapshot.root and use it via\n" - << "--condition-remap file://=TPC/Calib/CorrectionMap option"; - } - /* if (config.configProcessing.doublePipeline && ic.services().get().poolSize != 2) { - throw std::runtime_error("double pipeline requires exactly 2 threads"); - } */ - if (config.configProcessing.doublePipeline && (mSpecConfig.readTRDtracklets || mSpecConfig.runITSTracking || !(mSpecConfig.zsOnTheFly || mSpecConfig.zsDecoder))) { - LOG(fatal) << "GPU two-threaded pipeline works only with TPC-only processing, and with ZS input"; + // Configure the "GPU workflow" i.e. which steps we run on the GPU (or CPU) + if (mSpecConfig.outputTracks || mSpecConfig.outputCompClusters || mSpecConfig.outputCompClustersFlat) { + mConfig->configWorkflow.steps.set(GPUDataTypes::RecoStep::TPCConversion, + GPUDataTypes::RecoStep::TPCSliceTracking, + GPUDataTypes::RecoStep::TPCMerging); + mConfig->configWorkflow.outputs.set(GPUDataTypes::InOutType::TPCMergedTracks); + mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, mConfParam->rundEdx == -1 ? !mConfParam->synchronousProcessing : mConfParam->rundEdx); + } + if (mSpecConfig.outputCompClusters || mSpecConfig.outputCompClustersFlat) { + mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, true); + mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, true); + } + mConfig->configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCClusters); + if (mSpecConfig.caClusterer) { // Override some settings if we have raw data as input + mConfig->configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCRaw); + mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCClusterFinding, true); + mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, true); + } + if (mSpecConfig.decompressTPC) { + mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, false); + mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCDecompression, true); + mConfig->configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCCompressedClusters); + mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, true); + mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, false); + if (mTPCSectorMask != 0xFFFFFFFFF) { + throw std::invalid_argument("Cannot run TPC decompression with a sector mask"); } + } + if (mSpecConfig.runTRDTracking) { + mConfig->configWorkflow.inputs.setBits(GPUDataTypes::InOutType::TRDTracklets, true); + mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TRDTracking, true); + } + if (mSpecConfig.runITSTracking) { + mConfig->configWorkflow.inputs.setBits(GPUDataTypes::InOutType::ITSClusters, true); + mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::ITSTracks, true); + mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::ITSTracking, true); + } + if (mSpecConfig.outputSharedClusterMap) { + mConfig->configProcessing.outputSharedClusterMap = true; + } + mConfig->configProcessing.createO2Output = mSpecConfig.outputTracks ? 2 : 0; // Disable O2 TPC track format output if no track output requested + mConfig->configProcessing.param.tpcTriggerHandling = mSpecConfig.tpcTriggerHandling; + + if (mConfParam->transformationFile.size() || mConfParam->transformationSCFile.size()) { + LOG(fatal) << "Deprecated configurable param options GPU_global.transformationFile or transformationSCFile used\n" + << "Instead, link the corresponding file as /TPC/Calib/CorrectionMap/snapshot.root and use it via\n" + << "--condition-remap file://=TPC/Calib/CorrectionMap option"; + } + /* if (config.configProcessing.doublePipeline && ic.services().get().poolSize != 2) { + throw std::runtime_error("double pipeline requires exactly 2 threads"); + } */ + if (config.configProcessing.doublePipeline && (mSpecConfig.readTRDtracklets || mSpecConfig.runITSTracking || !(mSpecConfig.zsOnTheFly || mSpecConfig.zsDecoder))) { + LOG(fatal) << "GPU two-threaded pipeline works only with TPC-only processing, and with ZS input"; + } + + if (mSpecConfig.enableDoublePipeline != 2) { + mGPUReco = std::make_unique(); // initialize TPC calib objects initFunctionTPCCalib(ic); + mConfig->configCalib.fastTransform = mFastTransformHelper->getCorrMap(); mConfig->configCalib.fastTransformRef = mFastTransformHelper->getCorrMapRef(); mConfig->configCalib.fastTransformHelper = mFastTransformHelper.get(); @@ -264,14 +265,14 @@ void GPURecoWorkflowSpec::init(InitContext& ic) } // Configuration is prepared, initialize the tracker. - if (mTracker->Initialize(config) != 0) { + if (mGPUReco->Initialize(config) != 0) { throw std::invalid_argument("GPU Reconstruction initialization failed"); } if (mSpecConfig.outputQA) { mQA = std::make_unique(mConfig.get()); } if (mSpecConfig.outputErrorQA) { - mTracker->setErrorCodeOutput(&mErrorQA); + mGPUReco->setErrorCodeOutput(&mErrorQA); } // initialize ITS @@ -279,49 +280,49 @@ void GPURecoWorkflowSpec::init(InitContext& ic) initFunctionITS(ic); } - mTimer->Stop(); - mTimer->Reset(); - } - - auto& callbacks = ic.services().get(); - callbacks.set([this](fair::mq::RegionInfo const& info) { - if (info.size == 0) { - return; - } - if (mConfParam->registerSelectedSegmentIds != -1 && info.managed && info.id != (unsigned int)mConfParam->registerSelectedSegmentIds) { - return; - } - int fd = 0; - if (mConfParam->mutexMemReg) { - mode_t mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - fd = open("/tmp/o2_gpu_memlock_mutex.lock", O_RDWR | O_CREAT | O_CLOEXEC, mask); - if (fd == -1) { - throw std::runtime_error("Error opening lock file"); + auto& callbacks = ic.services().get(); + callbacks.set([this](fair::mq::RegionInfo const& info) { + if (info.size == 0) { + return; } - fchmod(fd, mask); - if (lockf(fd, F_LOCK, 0)) { - throw std::runtime_error("Error locking file"); + if (mConfParam->registerSelectedSegmentIds != -1 && info.managed && info.id != (unsigned int)mConfParam->registerSelectedSegmentIds) { + return; } - } - std::chrono::time_point start, end; - if (mConfParam->benchmarkMemoryRegistration) { - start = std::chrono::high_resolution_clock::now(); - } - if (mTracker->registerMemoryForGPU(info.ptr, info.size)) { - throw std::runtime_error("Error registering memory for GPU"); - } - if (mConfParam->benchmarkMemoryRegistration) { - end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed_seconds = end - start; - LOG(info) << "Memory registration time (0x" << info.ptr << ", " << info.size << " bytes): " << elapsed_seconds.count() << " s"; - } - if (mConfParam->mutexMemReg) { - if (lockf(fd, F_ULOCK, 0)) { - throw std::runtime_error("Error unlocking file"); + int fd = 0; + if (mConfParam->mutexMemReg) { + mode_t mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + fd = open("/tmp/o2_gpu_memlock_mutex.lock", O_RDWR | O_CREAT | O_CLOEXEC, mask); + if (fd == -1) { + throw std::runtime_error("Error opening lock file"); + } + fchmod(fd, mask); + if (lockf(fd, F_LOCK, 0)) { + throw std::runtime_error("Error locking file"); + } } - close(fd); - } - }); + std::chrono::time_point start, end; + if (mConfParam->benchmarkMemoryRegistration) { + start = std::chrono::high_resolution_clock::now(); + } + if (mGPUReco->registerMemoryForGPU(info.ptr, info.size)) { + throw std::runtime_error("Error registering memory for GPU"); + } + if (mConfParam->benchmarkMemoryRegistration) { + end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + LOG(info) << "Memory registration time (0x" << info.ptr << ", " << info.size << " bytes): " << elapsed_seconds.count() << " s"; + } + if (mConfParam->mutexMemReg) { + if (lockf(fd, F_ULOCK, 0)) { + throw std::runtime_error("Error unlocking file"); + } + close(fd); + } + }); + } + + mTimer->Stop(); + mTimer->Reset(); } void GPURecoWorkflowSpec::stop() @@ -335,9 +336,11 @@ void GPURecoWorkflowSpec::endOfStream(EndOfStreamContext& ec) void GPURecoWorkflowSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) { - finaliseCCDBTPC(matcher, obj); - if (mSpecConfig.runITSTracking) { - finaliseCCDBITS(matcher, obj); + if (mSpecConfig.enableDoublePipeline != 2) { + finaliseCCDBTPC(matcher, obj); + if (mSpecConfig.runITSTracking) { + finaliseCCDBITS(matcher, obj); + } } if (GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { mGRPGeomUpdated = true; @@ -509,9 +512,51 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) LOG(fatal) << "configKeyValue tpcTriggeredMode does not match GRP isDetContinuousReadOut(TPC) setting"; } + // ------------------------------ Handle inputs ------------------------------ + + GPUTrackingInOutPointers ptrs; processInputs(pc, tpcZSmetaPointers, tpcZSmetaPointers2, tpcZSmetaSizes, tpcZSmetaSizes2, inputZS, tpcZS, tpcZSonTheFlySizes, debugTFDump, compClustersDummy, compClustersFlatDummy, pCompClustersFlat, tmpEmptyCompClusters); // Process non-digit / non-cluster inputs const auto& inputsClustersDigits = o2::tpc::getWorkflowTPCInput(pc, mVerbosity, getWorkflowTPCInput_mc, getWorkflowTPCInput_clusters, mTPCSectorMask, getWorkflowTPCInput_digits); // Process digit and cluster inputs - GPUTrackingInOutPointers ptrs; + + const auto& tinfo = pc.services().get(); + mTFSettings->tfStartOrbit = tinfo.firstTForbit; + mTFSettings->hasTfStartOrbit = 1; + mTFSettings->hasNHBFPerTF = 1; + mTFSettings->nHBFPerTF = GRPGeomHelper::instance().getGRPECS()->getNHBFPerTF(); + mTFSettings->hasRunStartOrbit = 0; + if (mVerbosity) { + LOG(info) << "TF firstTForbit " << mTFSettings->tfStartOrbit << " nHBF " << mTFSettings->nHBFPerTF << " runStartOrbit " << mTFSettings->runStartOrbit << " simStartOrbit " << mTFSettings->simStartOrbit; + } + ptrs.settingsTF = mTFSettings.get(); + + if (mConfParam->checkFirstTfOrbit) { + static uint32_t lastFirstTFOrbit = -1; + static uint32_t lastTFCounter = -1; + if (lastFirstTFOrbit != -1 && lastTFCounter != -1) { + int diffOrbit = tinfo.firstTForbit - lastFirstTFOrbit; + int diffCounter = tinfo.tfCounter - lastTFCounter; + if (diffOrbit != diffCounter * mTFSettings->nHBFPerTF) { + LOG(error) << "Time frame has mismatching firstTfOrbit - Last orbit/counter: " << lastFirstTFOrbit << " " << lastTFCounter << " - Current: " << tinfo.firstTForbit << " " << tinfo.tfCounter; + } + } + lastFirstTFOrbit = tinfo.firstTForbit; + lastTFCounter = tinfo.tfCounter; + } + + if (mTPCSectorMask != 0xFFFFFFFFF) { + // Clean out the unused sectors, such that if they were present by chance, they are not processed, and if the values are uninitialized, we should not crash + for (unsigned int i = 0; i < NSectors; i++) { + if (!(mTPCSectorMask & (1ul << i))) { + if (ptrs.tpcZS) { + for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + tpcZS.slice[i].zsPtr[j] = nullptr; + tpcZS.slice[i].nZSPtr[j] = nullptr; + tpcZS.slice[i].count[j] = 0; + } + } + } + } + } o2::globaltracking::RecoContainer inputTracksTRD; decltype(o2::trd::getRecoInputContainer(pc, &ptrs, &inputTracksTRD)) trdInputContainer; @@ -559,8 +604,6 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) } } - // a byte size resizable vector object, the DataAllocator returns reference to internal object - // initialize optional pointer to the vector object o2::tpc::TPCSectorHeader clusterOutputSectorHeader{0}; if (mClusterOutputIds.size() > 0) { clusterOutputSectorHeader.sectorBits = mTPCSectorMask; @@ -568,6 +611,18 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) clusterOutputSectorHeader.activeSectors = mTPCSectorMask; } + // ------------------------------ Prepare stage for double-pipeline before normal output preparation ------------------------------ + + if (mSpecConfig.enableDoublePipeline == 2) { + size_t prepareBufferSize = sizeof(*ptrs.settingsTF); + auto prepareBuffer = pc.outputs().make>(Output{gDataOriginGPU, "PIPELINEPREPARE", 0, Lifetime::Timeframe}, prepareBufferSize); + char* prepareBufferPtr = prepareBuffer.data(); + memcpy(prepareBufferPtr, ptrs.settingsTF, prepareBufferSize); + return; + } + + // ------------------------------ Prepare outputs ------------------------------ + GPUInterfaceOutputs outputRegions; using outputDataType = char; using outputBufferUninitializedVector = std::decay_t>(Output{"", "", 0}))>; @@ -645,45 +700,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) outputRegions.clusterLabels.allocator = [&clustersMCBuffer](size_t size) -> void* { return &clustersMCBuffer; }; } - const auto& tinfo = pc.services().get(); - mTFSettings->tfStartOrbit = tinfo.firstTForbit; - mTFSettings->hasTfStartOrbit = 1; - mTFSettings->hasNHBFPerTF = 1; - mTFSettings->nHBFPerTF = GRPGeomHelper::instance().getGRPECS()->getNHBFPerTF(); - mTFSettings->hasRunStartOrbit = 0; - if (mVerbosity) { - LOG(info) << "TF firstTForbit " << mTFSettings->tfStartOrbit << " nHBF " << mTFSettings->nHBFPerTF << " runStartOrbit " << mTFSettings->runStartOrbit << " simStartOrbit " << mTFSettings->simStartOrbit; - } - ptrs.settingsTF = mTFSettings.get(); - - if (mConfParam->checkFirstTfOrbit) { - static uint32_t lastFirstTFOrbit = -1; - static uint32_t lastTFCounter = -1; - if (lastFirstTFOrbit != -1 && lastTFCounter != -1) { - int diffOrbit = tinfo.firstTForbit - lastFirstTFOrbit; - int diffCounter = tinfo.tfCounter - lastTFCounter; - if (diffOrbit != diffCounter * mTFSettings->nHBFPerTF) { - LOG(error) << "Time frame has mismatching firstTfOrbit - Last orbit/counter: " << lastFirstTFOrbit << " " << lastTFCounter << " - Current: " << tinfo.firstTForbit << " " << tinfo.tfCounter; - } - } - lastFirstTFOrbit = tinfo.firstTForbit; - lastTFCounter = tinfo.tfCounter; - } - - if (mTPCSectorMask != 0xFFFFFFFFF) { - // Clean out the unused sectors, such that if they were present by chance, they are not processed, and if the values are uninitialized, we should not crash - for (unsigned int i = 0; i < NSectors; i++) { - if (!(mTPCSectorMask & (1ul << i))) { - if (ptrs.tpcZS) { - for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - tpcZS.slice[i].zsPtr[j] = nullptr; - tpcZS.slice[i].nZSPtr[j] = nullptr; - tpcZS.slice[i].count[j] = 0; - } - } - } - } - } + // ------------------------------ Actual processing ------------------------------ if ((int)(ptrs.tpcZS != nullptr) + (int)(ptrs.tpcPackedDigits != nullptr && (ptrs.tpcZS == nullptr || ptrs.tpcPackedDigits->tpcDigitsMC == nullptr)) + (int)(ptrs.clustersNative != nullptr) + (int)(ptrs.tpcCompressedClusters != nullptr) != 1) { throw std::runtime_error("Invalid input for gpu tracking"); @@ -697,9 +714,9 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) if (mConfParam->dump) { if (mNTFs == 1) { - mTracker->DumpSettings(); + mGPUReco->DumpSettings(); } - mTracker->DumpEvent(mNTFs - 1, &ptrs); + mGPUReco->DumpEvent(mNTFs - 1, &ptrs); } std::unique_ptr ptrsDump; if (mConfParam->dumpBadTFMode == 2) { @@ -709,7 +726,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) int retVal = 0; if (mConfParam->dump < 2) { - retVal = mTracker->RunTracking(&ptrs, &outputRegions, threadIndex); + retVal = mGPUReco->RunTracking(&ptrs, &outputRegions, threadIndex); if (retVal != 0) { debugTFDump = true; } @@ -722,7 +739,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) o2::utils::DebugStreamer::instance()->flush(); // flushing debug output to file cleanOldCalibsTPCPtrs(); // setting TPC calibration objects // if (!mTrackingCAO2Interface->getConfig().configInterface.outputToExternalBuffers) // TODO: Why was this needed for double-pipeline? - mTracker->Clear(false, threadIndex); // clean non-output memory used by GPU Reconstruction + mGPUReco->Clear(false, threadIndex); // clean non-output memory used by GPU Reconstruction if (debugTFDump && mNDebugDumps < mConfParam->dumpBadTFs) { mNDebugDumps++; @@ -740,13 +757,16 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) } fclose(fp); } else if (mConfParam->dumpBadTFMode == 2) { - mTracker->DumpEvent(mNDebugDumps - 1, ptrsDump.get()); + mGPUReco->DumpEvent(mNDebugDumps - 1, ptrsDump.get()); } } if (mConfParam->dump == 2) { return; } + + // ------------------------------ Varios postprocessing steps ------------------------------ + bool createEmptyOutput = false; if (retVal != 0) { if (retVal == 3 && mConfig->configProcessing.ignoreNonFatalGPUErrors) { @@ -951,13 +971,16 @@ void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc) } if (needCalibUpdate) { LOG(info) << "Updating GPUReconstruction calibration objects"; - mTracker->UpdateCalibration(newCalibObjects, newCalibValues); + mGPUReco->UpdateCalibration(newCalibObjects, newCalibValues); } } Options GPURecoWorkflowSpec::options() { Options opts; + if (mSpecConfig.enableDoublePipeline == 2) { + return opts; + } if (mSpecConfig.outputTracks) { o2::tpc::CorrectionMapsLoader::addOptions(opts); } @@ -967,6 +990,22 @@ Options GPURecoWorkflowSpec::options() Inputs GPURecoWorkflowSpec::inputs() { Inputs inputs; + if (mSpecConfig.zsDecoder) { + // All ZS raw data is published with subspec 0 by the o2-raw-file-reader-workflow and DataDistribution + // creates subspec fom CRU and endpoint id, we create one single input route subscribing to all TPC/RAWDATA + inputs.emplace_back(InputSpec{"zsraw", ConcreteDataTypeMatcher{"TPC", "RAWDATA"}, Lifetime::Timeframe}); + if (mSpecConfig.askDISTSTF) { + inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); + } + } + if (mSpecConfig.enableDoublePipeline == 2) { + if (!mSpecConfig.zsDecoder) { + LOG(fatal) << "Double pipeline mode can only work with zsraw input"; + } + return inputs; + } else if (mSpecConfig.enableDoublePipeline == 1) { + inputs.emplace_back("pipelineprepare", gDataOriginGPU, "PIPELINEPREPARE", 0, Lifetime::Timeframe); + } if (mSpecConfig.outputTracks) { // loading calibration objects from the CCDB inputs.emplace_back("tpcgain", gDataOriginTPC, "PADGAINFULL", 0, Lifetime::Condition, ccdbParamSpec(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalPadGainFull))); @@ -1007,14 +1046,6 @@ Inputs GPURecoWorkflowSpec::inputs() } } - if (mSpecConfig.zsDecoder) { - // All ZS raw data is published with subspec 0 by the o2-raw-file-reader-workflow and DataDistribution - // creates subspec fom CRU and endpoint id, we create one single input route subscribing to all TPC/RAWDATA - inputs.emplace_back(InputSpec{"zsraw", ConcreteDataTypeMatcher{"TPC", "RAWDATA"}, Lifetime::Timeframe}); - if (mSpecConfig.askDISTSTF) { - inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); - } - } if (mSpecConfig.zsOnTheFly) { inputs.emplace_back(InputSpec{"zsinput", ConcreteDataTypeMatcher{"TPC", "TPCZS"}, Lifetime::Timeframe}); inputs.emplace_back(InputSpec{"zsinputsizes", ConcreteDataTypeMatcher{"TPC", "ZSSIZES"}, Lifetime::Timeframe}); @@ -1054,6 +1085,10 @@ Outputs GPURecoWorkflowSpec::outputs() { constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR; std::vector outputSpecs; + if (mSpecConfig.enableDoublePipeline == 2) { + outputSpecs.emplace_back(gDataOriginGPU, "PIPELINEPREPARE", 0, Lifetime::Timeframe); + return outputSpecs; + } if (mSpecConfig.outputTracks) { outputSpecs.emplace_back(gDataOriginTPC, "TRACKS", 0, Lifetime::Timeframe); outputSpecs.emplace_back(gDataOriginTPC, "CLUSREFS", 0, Lifetime::Timeframe); @@ -1124,7 +1159,7 @@ void GPURecoWorkflowSpec::deinitialize() { mQA.reset(nullptr); mDisplayFrontend.reset(nullptr); - mTracker.reset(nullptr); + mGPUReco.reset(nullptr); } } // namespace o2::gpu diff --git a/GPU/Workflow/src/gpu-reco-workflow.cxx b/GPU/Workflow/src/gpu-reco-workflow.cxx index 9d0c481c2916d..4152f247c4ace 100644 --- a/GPU/Workflow/src/gpu-reco-workflow.cxx +++ b/GPU/Workflow/src/gpu-reco-workflow.cxx @@ -56,7 +56,8 @@ void customize(std::vector& workflowOptions) {"disable-mc", VariantType::Bool, false, {"disable sending of MC information"}}, {"ignore-dist-stf", VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCHwClusterer.peakChargeThreshold=4;...')"}}, - {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}}; + {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, + {"enableDoublePipeline", VariantType::Bool, false, {"enable GPU double pipeline mode"}}}; o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -172,13 +173,13 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) cfg.readTRDtracklets = isEnabled(inputTypes, ioType::TRDTracklets); cfg.runTRDTracking = isEnabled(outputTypes, ioType::TRDTracks); cfg.tpcTriggerHandling = isEnabled(outputTypes, ioType::TPCTriggers) || cfg.caClusterer; + cfg.enableDoublePipeline = cfgc.options().get("enableDoublePipeline"); Inputs ggInputs; auto ggRequest = std::make_shared(false, true, false, true, true, o2::base::GRPGeomRequest::Aligned, ggInputs, true); auto task = std::make_shared(&gPolicyData, cfg, tpcSectors, gTpcSectorMask, ggRequest); Inputs taskInputs = task->inputs(); - Options taskOptions = task->options(); std::move(ggInputs.begin(), ggInputs.end(), std::back_inserter(taskInputs)); gTask = task; @@ -187,7 +188,22 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) taskInputs, task->outputs(), AlgorithmSpec{adoptTask(task)}, - taskOptions}); + task->options()}); + + if (cfg.enableDoublePipeline) { + cfg.enableDoublePipeline = 2; + Inputs ggInputsPrepare; + auto ggRequestPrepare = std::make_shared(false, true, false, false, false, o2::base::GRPGeomRequest::None, ggInputsPrepare, true); + auto taskPrepare = std::make_shared(&gPolicyData, cfg, tpcSectors, gTpcSectorMask, ggRequestPrepare); + Inputs taskInputsPrepare = taskPrepare->inputs(); + std::move(ggInputsPrepare.begin(), ggInputsPrepare.end(), std::back_inserter(taskInputsPrepare)); + specs.emplace_back(DataProcessorSpec{ + "gpu-reconstruction-prepare", + taskInputsPrepare, + taskPrepare->outputs(), + AlgorithmSpec{adoptTask(taskPrepare)}, + taskPrepare->options()}); + } if (!cfgc.options().get("ignore-dist-stf")) { GlobalTrackID::mask_t srcTrk = GlobalTrackID::getSourcesMask("none"); diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 4e3a87a3ab2da..6c286ff7d1d3d 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -277,6 +277,8 @@ if has_detector_calib PHS && workflow_has_parameter CALIB; then PHS_CONFIG+=" --fullclu-output" fi +[[ ${O2_GPU_DOUBLE_PIPELINE:-0} == 1 ]] && GPU_CONFIG+=" --enableDoublePipeline" + ( workflow_has_parameter AOD || [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output o2-emcal-cell-writer-workflow ) && has_detector EMC && RAW_EMC_SUBSPEC=" --subspecification 1 " has_detector_reco MID && has_detector_matching MCHMID && MFTMCHConf="FwdMatching.useMIDMatch=true;" || MFTMCHConf="FwdMatching.useMIDMatch=false;" @@ -438,7 +440,7 @@ fi # --------------------------------------------------------------------------------------------------------------------- # Common reconstruction workflows -(has_detector_reco TPC || has_detector_ctf TPC) && ! has_detector_from_global_reader TPC && add_W o2-gpu-reco-workflow "--gpu-reconstruction \"$GPU_CONFIG_SELF\" $ASK_CTP_LUMI_GPU --input-type=$GPU_INPUT $DISABLE_MC --output-type $GPU_OUTPUT --pipeline gpu-reconstruction:${N_TPCTRK:-1} $GPU_CONFIG" "GPU_global.deviceType=$GPUTYPE;GPU_proc.debugLevel=0;$GPU_CONFIG_KEY;$TRACKTUNETPCINNER" +(has_detector_reco TPC || has_detector_ctf TPC) && ! has_detector_from_global_reader TPC && add_W o2-gpu-reco-workflow "--gpu-reconstruction \"$GPU_CONFIG_SELF\" $ASK_CTP_LUMI_GPU --input-type=$GPU_INPUT $DISABLE_MC --output-type $GPU_OUTPUT --pipeline gpu-reconstruction:${N_TPCTRK:-1},gpu-reconstruction-prepare:${N_TPCTRK:-1} $GPU_CONFIG" "GPU_global.deviceType=$GPUTYPE;GPU_proc.debugLevel=0;$GPU_CONFIG_KEY;$TRACKTUNETPCINNER" (has_detector_reco TOF || has_detector_ctf TOF) && ! has_detector_from_global_reader TOF && add_W o2-tof-reco-workflow "$TOF_CONFIG --input-type $TOF_INPUT --output-type $TOF_OUTPUT $DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC --pipeline $(get_N tof-compressed-decoder TOF RAW 1),$(get_N TOFClusterer TOF REST 1)" has_detector_reco ITS && ! has_detector_from_global_reader ITS && add_W o2-its-reco-workflow "--trackerCA $ITS_CONFIG $DISABLE_MC $DISABLE_DIGIT_CLUSTER_INPUT $DISABLE_ROOT_OUTPUT --pipeline $(get_N its-tracker ITS REST 1 ITSTRK)" "$ITS_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" has_detector_reco FT0 && ! has_detector_from_global_reader FT0 && add_W o2-ft0-reco-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC --pipeline $(get_N ft0-reconstructor FT0 REST 1)" From 4987c982784f6acf67b5f5d36091fbb52daa6f18 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 22 Sep 2023 19:41:21 +0200 Subject: [PATCH 104/324] GPU: Implement out-of-band message from prepare device to GPU device transfering ptrs to input data --- GPU/Workflow/CMakeLists.txt | 1 + .../include/GPUWorkflow/GPUWorkflowSpec.h | 13 +- GPU/Workflow/src/GPUWorkflowInternal.h | 32 ++++ GPU/Workflow/src/GPUWorkflowPipeline.cxx | 169 ++++++++++++++++++ GPU/Workflow/src/GPUWorkflowSpec.cxx | 137 +++++++------- 5 files changed, 288 insertions(+), 64 deletions(-) create mode 100644 GPU/Workflow/src/GPUWorkflowInternal.h create mode 100644 GPU/Workflow/src/GPUWorkflowPipeline.cxx diff --git a/GPU/Workflow/CMakeLists.txt b/GPU/Workflow/CMakeLists.txt index e27b6a52deb93..51494b1a1703e 100644 --- a/GPU/Workflow/CMakeLists.txt +++ b/GPU/Workflow/CMakeLists.txt @@ -13,6 +13,7 @@ o2_add_library(GPUWorkflow SOURCES src/GPUWorkflowSpec.cxx src/GPUWorkflowTPC.cxx src/GPUWorkflowITS.cxx + src/GPUWorkflowPipeline.cxx TARGETVARNAME targetName PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsTPC diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index f692e1952095a..1b09f2189b6ed 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -30,6 +30,10 @@ #include class TStopwatch; +namespace fair::mq +{ +struct RegionInfo; +} // namespace fair::mq namespace o2 { namespace base @@ -79,6 +83,8 @@ struct TPCZSLinkMapping; struct GPUSettingsO2; class GPUO2InterfaceQA; struct GPUTrackingInOutPointers; +struct GPUTrackingInOutZS; +struct GPURecoWorkflowSpec_TPCZSBuffers; class GPURecoWorkflowSpec : public o2::framework::Task { @@ -144,11 +150,13 @@ class GPURecoWorkflowSpec : public o2::framework::Task void doTrackTuneTPC(GPUTrackingInOutPointers& ptrs, char* buffout); - template - void processInputs(o2::framework::ProcessingContext&, A&, B&, C&, D&, E&, F&, G&, bool&, H&, I&, J&, K&); + template + void processInputs(o2::framework::ProcessingContext&, D&, E&, F&, G&, bool&, H&, I&, J&, K&); int runITSTracking(o2::framework::ProcessingContext& pc); + int handlePipeline(o2::framework::ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS); + CompletionPolicyData* mPolicyData; std::unique_ptr mGPUReco; std::unique_ptr mDisplayFrontend; @@ -178,6 +186,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task std::unique_ptr mITSVertexer; std::mutex mMutexDecodeInput; o2::its::TimeFrame* mITSTimeFrame = nullptr; + std::vector mRegionInfos; const o2::itsmft::TopologyDictionary* mITSDict = nullptr; const o2::dataformats::MeanVertexObject* mMeanVertex; unsigned long mTPCSectorMask = 0; diff --git a/GPU/Workflow/src/GPUWorkflowInternal.h b/GPU/Workflow/src/GPUWorkflowInternal.h new file mode 100644 index 0000000000000..c3be7f8016ee5 --- /dev/null +++ b/GPU/Workflow/src/GPUWorkflowInternal.h @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GPUWorkflowInternal.h +/// @author David Rohr + +#ifndef O2_GPU_GPUWORKFLOWINTERNAL_H +#define O2_GPU_GPUWORKFLOWINTERNAL_H + +#include "GPUDataTypes.h" + +namespace o2::gpu +{ + +struct GPURecoWorkflowSpec_TPCZSBuffers { + std::vector Pointers[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + std::vector Sizes[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + const void** Pointers2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + const unsigned int* Sizes2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; +}; + +} // namespace o2::gpu + +#endif diff --git a/GPU/Workflow/src/GPUWorkflowPipeline.cxx b/GPU/Workflow/src/GPUWorkflowPipeline.cxx new file mode 100644 index 0000000000000..bdeffc7bed69d --- /dev/null +++ b/GPU/Workflow/src/GPUWorkflowPipeline.cxx @@ -0,0 +1,169 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file GPUWorkflowPipeline.cxx +/// @author David Rohr + +#include "GPUWorkflow/GPUWorkflowSpec.h" +#include "GPUO2InterfaceConfiguration.h" +#include "GPUO2Interface.h" +#include "GPUDataTypes.h" +#include "GPUSettings.h" +#include "GPUWorkflowInternal.h" + +#include "Framework/WorkflowSpec.h" // o2::framework::mergeInputs +#include "Framework/DataRefUtils.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/SerializationMethods.h" +#include "Framework/Logger.h" +#include "Framework/CallbackService.h" +#include "Framework/DataProcessingContext.h" +#include "Framework/RawDeviceService.h" + +#include +#include + +using namespace o2::framework; +using namespace o2::header; +using namespace o2::gpu; +using namespace o2::base; +using namespace o2::dataformats; + +namespace o2::gpu +{ + +struct pipelinePrepareMessage { + static constexpr size_t MAGIC_WORD = 0X8473957353424134; + size_t magicWord = MAGIC_WORD; + DataProcessingHeader::StartTime timeSliceId; + GPUSettingsTF tfSettings; + fair::mq::RegionInfo regionInfo; + size_t pointerCounts[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + size_t pointersTotal; +}; + +int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS) +{ + auto device = pc.services().get().device(); + const auto& tinfo = pc.services().get(); + if (mSpecConfig.enableDoublePipeline == 1) { + auto msg = device->NewMessageFor("gpu-prepare-channel", 0, 0); + bool received = false; + int recvTimeot = 1000; + do { + LOG(info) << "Waiting for out of band message"; + received = device->Receive(msg, "gpu-prepare-channel", 0, recvTimeot); + } while (!received && !device->NewStatePending()); + if (!received) { + return 1; + } + if (msg->GetSize() < sizeof(pipelinePrepareMessage)) { + LOG(fatal) << "Received prepare message of invalid size"; + } + const pipelinePrepareMessage* m = (const pipelinePrepareMessage*)msg->GetData(); + if (m->magicWord != m->MAGIC_WORD) { + LOG(fatal) << "Prepare message corrupted, invalid magic word"; + } + if (m->timeSliceId != tinfo.timeslice) { + LOG(fatal) << "Prepare message for incorrect time frame received, time frames seem out of sync"; + } + size_t regionOffset = 0; + if (m->pointersTotal) { + bool regionFound = false; + for (unsigned int i = 0; i < mRegionInfos.size(); i++) { + if (mRegionInfos[i].managed == m->regionInfo.managed && mRegionInfos[i].id == m->regionInfo.id) { + regionFound = true; + regionOffset = (size_t)mRegionInfos[i].ptr; + break; + } + } + } + size_t ptrsCopied = 0; + size_t* ptrBuffer = (size_t*)msg->GetData() + sizeof(pipelinePrepareMessage) / sizeof(size_t); + tpcZSmeta.Pointers[0][0].resize(m->pointersTotal); + tpcZSmeta.Sizes[0][0].resize(m->pointersTotal); + for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { + for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + tpcZS.slice[i].count[j] = m->pointerCounts[i][j]; + for (unsigned int k = 0; k < tpcZS.slice[i].count[j]; k++) { + tpcZSmeta.Pointers[0][0][ptrsCopied + k] = (void*)(ptrBuffer[ptrsCopied + k] + regionOffset); + tpcZSmeta.Sizes[0][0][ptrsCopied + k] = ptrBuffer[m->pointersTotal + ptrsCopied + k]; + } + tpcZS.slice[i].zsPtr[j] = tpcZSmeta.Pointers[0][0].data() + ptrsCopied; + tpcZS.slice[i].nZSPtr[j] = tpcZSmeta.Sizes[0][0].data() + ptrsCopied; + ptrsCopied += tpcZS.slice[i].count[j]; + } + } + ptrs.tpcZS = &tpcZS; + } + if (mSpecConfig.enableDoublePipeline == 2) { + auto prepareBuffer = pc.outputs().make>(Output{gDataOriginGPU, "PIPELINEPREPARE", 0, Lifetime::Timeframe}, 0u); + + size_t ptrsTotal = 0; + const void* firstPtr = nullptr; + for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { + for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + if (firstPtr == nullptr && ptrs.tpcZS->slice[i].count[j]) { + firstPtr = ptrs.tpcZS->slice[i].zsPtr[j][0]; + } + ptrsTotal += ptrs.tpcZS->slice[i].count[j]; + } + } + + size_t prepareBufferSize = sizeof(pipelinePrepareMessage) + ptrsTotal * sizeof(size_t) * 2; + std::vector messageBuffer(prepareBufferSize / sizeof(size_t)); + pipelinePrepareMessage& preMessage = *(pipelinePrepareMessage*)messageBuffer.data(); + preMessage.magicWord = preMessage.MAGIC_WORD; + preMessage.timeSliceId = tinfo.timeslice; + preMessage.pointersTotal = ptrsTotal; + memcpy((void*)&preMessage.tfSettings, (const void*)ptrs.settingsTF, sizeof(preMessage.tfSettings)); + + if (ptrsTotal) { + bool regionFound = false; + for (unsigned int i = 0; i < mRegionInfos.size(); i++) { + if ((size_t)firstPtr >= (size_t)mRegionInfos[i].ptr && (size_t)firstPtr < (size_t)mRegionInfos[i].ptr + mRegionInfos[i].size) { + preMessage.regionInfo = mRegionInfos[i]; + regionFound = true; + break; + } + } + if (!regionFound) { + LOG(fatal) << "Found a TPC ZS pointer outside of shared memory"; + } + } + + size_t* ptrBuffer = messageBuffer.data() + sizeof(preMessage) / sizeof(size_t); + size_t ptrsCopied = 0; + for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { + for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + preMessage.pointerCounts[i][j] = ptrs.tpcZS->slice[i].count[j]; + for (unsigned int k = 0; k < ptrs.tpcZS->slice[i].count[j]; k++) { + ptrBuffer[ptrsCopied + k] = (size_t)ptrs.tpcZS->slice[i].zsPtr[j][k] - (size_t)preMessage.regionInfo.ptr; + ptrBuffer[ptrsTotal + ptrsCopied + k] = ptrs.tpcZS->slice[i].nZSPtr[j][k]; + } + ptrsCopied += ptrs.tpcZS->slice[i].count[j]; + } + } + + auto channel = device->GetChannels().find("gpu-prepare-channel"); + fair::mq::MessagePtr payload(device->NewMessage()); + payload->Rebuild(messageBuffer.data(), prepareBufferSize, nullptr, nullptr); + channel->second[0].Send(payload); + return 2; + } + return 0; +} + +} // namespace o2::gpu diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 77688ac875790..302aba2b78ebb 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -75,6 +75,7 @@ #include "DetectorsRaw/RDHUtils.h" #include "ITStracking/Tracker.h" #include "ITStracking/Vertexer.h" +#include "GPUWorkflowInternal.h" // #include "Framework/ThreadPool.h" #include @@ -279,47 +280,53 @@ void GPURecoWorkflowSpec::init(InitContext& ic) if (mSpecConfig.runITSTracking) { initFunctionITS(ic); } + } - auto& callbacks = ic.services().get(); - callbacks.set([this](fair::mq::RegionInfo const& info) { - if (info.size == 0) { - return; - } - if (mConfParam->registerSelectedSegmentIds != -1 && info.managed && info.id != (unsigned int)mConfParam->registerSelectedSegmentIds) { - return; - } - int fd = 0; - if (mConfParam->mutexMemReg) { - mode_t mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - fd = open("/tmp/o2_gpu_memlock_mutex.lock", O_RDWR | O_CREAT | O_CLOEXEC, mask); - if (fd == -1) { - throw std::runtime_error("Error opening lock file"); - } - fchmod(fd, mask); - if (lockf(fd, F_LOCK, 0)) { - throw std::runtime_error("Error locking file"); - } - } - std::chrono::time_point start, end; - if (mConfParam->benchmarkMemoryRegistration) { - start = std::chrono::high_resolution_clock::now(); - } - if (mGPUReco->registerMemoryForGPU(info.ptr, info.size)) { - throw std::runtime_error("Error registering memory for GPU"); + auto& callbacks = ic.services().get(); + callbacks.set([this](fair::mq::RegionInfo const& info) { + if (info.size == 0) { + return; + } + if (mSpecConfig.enableDoublePipeline) { + mRegionInfos.emplace_back(info); + } + if (mSpecConfig.enableDoublePipeline == 2) { + return; + } + if (mConfParam->registerSelectedSegmentIds != -1 && info.managed && info.id != (unsigned int)mConfParam->registerSelectedSegmentIds) { + return; + } + int fd = 0; + if (mConfParam->mutexMemReg) { + mode_t mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + fd = open("/tmp/o2_gpu_memlock_mutex.lock", O_RDWR | O_CREAT | O_CLOEXEC, mask); + if (fd == -1) { + throw std::runtime_error("Error opening lock file"); } - if (mConfParam->benchmarkMemoryRegistration) { - end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed_seconds = end - start; - LOG(info) << "Memory registration time (0x" << info.ptr << ", " << info.size << " bytes): " << elapsed_seconds.count() << " s"; + fchmod(fd, mask); + if (lockf(fd, F_LOCK, 0)) { + throw std::runtime_error("Error locking file"); } - if (mConfParam->mutexMemReg) { - if (lockf(fd, F_ULOCK, 0)) { - throw std::runtime_error("Error unlocking file"); - } - close(fd); + } + std::chrono::time_point start, end; + if (mConfParam->benchmarkMemoryRegistration) { + start = std::chrono::high_resolution_clock::now(); + } + if (mGPUReco->registerMemoryForGPU(info.ptr, info.size)) { + throw std::runtime_error("Error registering memory for GPU"); + } + if (mConfParam->benchmarkMemoryRegistration) { + end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + LOG(info) << "Memory registration time (0x" << info.ptr << ", " << info.size << " bytes): " << elapsed_seconds.count() << " s"; + } + if (mConfParam->mutexMemReg) { + if (lockf(fd, F_ULOCK, 0)) { + throw std::runtime_error("Error unlocking file"); } - }); - } + close(fd); + } + }); mTimer->Stop(); mTimer->Reset(); @@ -348,17 +355,20 @@ void GPURecoWorkflowSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& match } } -template -void GPURecoWorkflowSpec::processInputs(ProcessingContext& pc, A& tpcZSmetaPointers, B& tpcZSmetaPointers2, C& tpcZSmetaSizes, D& tpcZSmetaSizes2, E& inputZS, F& tpcZS, G& tpcZSonTheFlySizes, bool& debugTFDump, H& compClustersDummy, I& compClustersFlatDummy, J& pCompClustersFlat, K& tmpEmptyCompClusters) +template +void GPURecoWorkflowSpec::processInputs(ProcessingContext& pc, D& tpcZSmeta, E& inputZS, F& tpcZS, G& tpcZSonTheFlySizes, bool& debugTFDump, H& compClustersDummy, I& compClustersFlatDummy, J& pCompClustersFlat, K& tmpEmptyCompClusters) { + if (mSpecConfig.enableDoublePipeline == 1) { + return; + } constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR; constexpr static size_t NEndpoints = o2::gpu::GPUTrackingInOutZS::NENDPOINTS; if (mSpecConfig.zsOnTheFly || mSpecConfig.zsDecoder) { for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - tpcZSmetaPointers[i][j].clear(); - tpcZSmetaSizes[i][j].clear(); + tpcZSmeta.Pointers[i][j].clear(); + tpcZSmeta.Sizes[i][j].clear(); } } } @@ -414,12 +424,12 @@ void GPURecoWorkflowSpec::processInputs(ProcessingContext& pc, A& tpcZSmetaPoint (feeLinkID == o2::tpc::rdh_utils::ILBZSLinkID && (rdhLink == o2::tpc::rdh_utils::UserLogicLinkID || rdhLink == o2::tpc::rdh_utils::ILBZSLinkID || rdhLink == 0)) || (feeLinkID == o2::tpc::rdh_utils::DLBZSLinkID && (rdhLink == o2::tpc::rdh_utils::UserLogicLinkID || rdhLink == o2::tpc::rdh_utils::DLBZSLinkID || rdhLink == 0))); }; - auto insertPages = [&tpcZSmetaPointers, &tpcZSmetaSizes, checkForZSData](const char* ptr, size_t count, uint32_t subSpec) -> void { + auto insertPages = [&tpcZSmeta, checkForZSData](const char* ptr, size_t count, uint32_t subSpec) -> void { if (checkForZSData(ptr, subSpec)) { int rawcru = o2::tpc::rdh_utils::getCRU(ptr); int rawendpoint = o2::tpc::rdh_utils::getEndPoint(ptr); - tpcZSmetaPointers[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(ptr); - tpcZSmetaSizes[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(count); + tpcZSmeta.Pointers[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(ptr); + tpcZSmeta.Sizes[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(count); } }; if (DPLRawPageSequencer(pc.inputs(), filter)(isSameRdh, insertPages, checkForZSData)) { @@ -434,12 +444,12 @@ void GPURecoWorkflowSpec::processInputs(ProcessingContext& pc, A& tpcZSmetaPoint int totalCount = 0; for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - tpcZSmetaPointers2[i][j] = tpcZSmetaPointers[i][j].data(); - tpcZSmetaSizes2[i][j] = tpcZSmetaSizes[i][j].data(); - tpcZS.slice[i].zsPtr[j] = tpcZSmetaPointers2[i][j]; - tpcZS.slice[i].nZSPtr[j] = tpcZSmetaSizes2[i][j]; - tpcZS.slice[i].count[j] = tpcZSmetaPointers[i][j].size(); - totalCount += tpcZSmetaPointers[i][j].size(); + tpcZSmeta.Pointers2[i][j] = tpcZSmeta.Pointers[i][j].data(); + tpcZSmeta.Sizes2[i][j] = tpcZSmeta.Sizes[i][j].data(); + tpcZS.slice[i].zsPtr[j] = tpcZSmeta.Pointers2[i][j]; + tpcZS.slice[i].nZSPtr[j] = tpcZSmeta.Sizes2[i][j]; + tpcZS.slice[i].count[j] = tpcZSmeta.Pointers[i][j].size(); + totalCount += tpcZSmeta.Pointers[i][j].size(); } } } else if (mSpecConfig.decompressTPC) { @@ -479,10 +489,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) o2::tpc::CompressedClustersFlat& compClustersFlatDummy = reinterpret_cast(compClustersFlatDummyMemory); o2::tpc::CompressedClusters compClustersDummy; o2::gpu::GPUTrackingInOutZS tpcZS; - std::vector tpcZSmetaPointers[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; - std::vector tpcZSmetaSizes[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; - const void** tpcZSmetaPointers2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; - const unsigned int* tpcZSmetaSizes2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; + GPURecoWorkflowSpec_TPCZSBuffers tpcZSmeta; std::array tpcZSonTheFlySizes; gsl::span inputZS; std::unique_ptr tmpEmptyCompClusters; @@ -515,8 +522,8 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) // ------------------------------ Handle inputs ------------------------------ GPUTrackingInOutPointers ptrs; - processInputs(pc, tpcZSmetaPointers, tpcZSmetaPointers2, tpcZSmetaSizes, tpcZSmetaSizes2, inputZS, tpcZS, tpcZSonTheFlySizes, debugTFDump, compClustersDummy, compClustersFlatDummy, pCompClustersFlat, tmpEmptyCompClusters); // Process non-digit / non-cluster inputs - const auto& inputsClustersDigits = o2::tpc::getWorkflowTPCInput(pc, mVerbosity, getWorkflowTPCInput_mc, getWorkflowTPCInput_clusters, mTPCSectorMask, getWorkflowTPCInput_digits); // Process digit and cluster inputs + processInputs(pc, tpcZSmeta, inputZS, tpcZS, tpcZSonTheFlySizes, debugTFDump, compClustersDummy, compClustersFlatDummy, pCompClustersFlat, tmpEmptyCompClusters); // Process non-digit / non-cluster inputs + const auto& inputsClustersDigits = o2::tpc::getWorkflowTPCInput(pc, mVerbosity, getWorkflowTPCInput_mc, getWorkflowTPCInput_clusters, mTPCSectorMask, getWorkflowTPCInput_digits); // Process digit and cluster inputs const auto& tinfo = pc.services().get(); mTFSettings->tfStartOrbit = tinfo.firstTForbit; @@ -613,12 +620,10 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) // ------------------------------ Prepare stage for double-pipeline before normal output preparation ------------------------------ - if (mSpecConfig.enableDoublePipeline == 2) { - size_t prepareBufferSize = sizeof(*ptrs.settingsTF); - auto prepareBuffer = pc.outputs().make>(Output{gDataOriginGPU, "PIPELINEPREPARE", 0, Lifetime::Timeframe}, prepareBufferSize); - char* prepareBufferPtr = prepareBuffer.data(); - memcpy(prepareBufferPtr, ptrs.settingsTF, prepareBufferSize); - return; + if (mSpecConfig.enableDoublePipeline) { + if (handlePipeline(pc, ptrs, tpcZSmeta, tpcZS)) { + return; + } } // ------------------------------ Prepare outputs ------------------------------ @@ -978,6 +983,14 @@ void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc) Options GPURecoWorkflowSpec::options() { Options opts; + if (mSpecConfig.enableDoublePipeline) { + bool send = mSpecConfig.enableDoublePipeline == 2; + char* o2jobid = getenv("O2JOBID"); + char* numaid = getenv("NUMAID"); + int chanid = o2jobid ? atoi(o2jobid) : (numaid ? atoi(numaid) : 0); + std::string chan = std::string("name=gpu-prepare-channel,type=") + (send ? "push" : "pull") + ",method=" + (send ? "connect" : "bind") + ",address=ipc://@gpu-prepare-channel-" + std::to_string(chanid) + ",transport=shmem,rateLogging=0"; + opts.emplace_back(o2::framework::ConfigParamSpec{"channel-config", o2::framework::VariantType::String, chan, {"Out-of-band channel config"}}); + } if (mSpecConfig.enableDoublePipeline == 2) { return opts; } From 605b2e7032e48c8ee609c7490dc96127e47de499 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sat, 23 Sep 2023 09:40:21 +0200 Subject: [PATCH 105/324] GPU: Make receiving from out-of-band channel asynchronous --- .../include/GPUWorkflow/GPUWorkflowSpec.h | 10 +- GPU/Workflow/src/GPUWorkflowInternal.h | 31 ++++ GPU/Workflow/src/GPUWorkflowPipeline.cxx | 139 ++++++++++++------ GPU/Workflow/src/GPUWorkflowSpec.cxx | 30 +++- 4 files changed, 154 insertions(+), 56 deletions(-) diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index 1b09f2189b6ed..91050d1cd9d9d 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -84,7 +84,11 @@ struct GPUSettingsO2; class GPUO2InterfaceQA; struct GPUTrackingInOutPointers; struct GPUTrackingInOutZS; +namespace gpurecoworkflow_internals +{ struct GPURecoWorkflowSpec_TPCZSBuffers; +struct GPURecoWorkflowSpec_PipelineInternals; +} // namespace gpurecoworkflow_internals class GPURecoWorkflowSpec : public o2::framework::Task { @@ -155,7 +159,9 @@ class GPURecoWorkflowSpec : public o2::framework::Task int runITSTracking(o2::framework::ProcessingContext& pc); - int handlePipeline(o2::framework::ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS); + int handlePipeline(o2::framework::ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, gpurecoworkflow_internals::GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS); + void RunReceiveThread(); + void TerminateReceiveThread(); CompletionPolicyData* mPolicyData; std::unique_ptr mGPUReco; @@ -184,7 +190,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task std::vector mTPCSectors; std::unique_ptr mITSTracker; std::unique_ptr mITSVertexer; - std::mutex mMutexDecodeInput; + std::unique_ptr mPipeline; o2::its::TimeFrame* mITSTimeFrame = nullptr; std::vector mRegionInfos; const o2::itsmft::TopologyDictionary* mITSDict = nullptr; diff --git a/GPU/Workflow/src/GPUWorkflowInternal.h b/GPU/Workflow/src/GPUWorkflowInternal.h index c3be7f8016ee5..152a94c8ef0c1 100644 --- a/GPU/Workflow/src/GPUWorkflowInternal.h +++ b/GPU/Workflow/src/GPUWorkflowInternal.h @@ -16,9 +16,15 @@ #define O2_GPU_GPUWORKFLOWINTERNAL_H #include "GPUDataTypes.h" +#include +#include +#include +#include namespace o2::gpu { +namespace gpurecoworkflow_internals +{ struct GPURecoWorkflowSpec_TPCZSBuffers { std::vector Pointers[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; @@ -27,6 +33,31 @@ struct GPURecoWorkflowSpec_TPCZSBuffers { const unsigned int* Sizes2[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; }; +struct GPURecoWorkflow_QueueObject { + GPURecoWorkflowSpec_TPCZSBuffers tpcZSmeta; + GPUTrackingInOutZS tpcZS; + GPUSettingsTF tfSettings; + GPUTrackingInOutPointers ptrs; + o2::framework::DataProcessingHeader::StartTime timeSliceId; +}; + +struct GPURecoWorkflowSpec_PipelineInternals { + std::mutex mutexDecodeInput; + + fair::mq::Device* fmqDevice; + + std::thread receiveThread; + std::condition_variable notifyThread; + std::mutex threadMutex; + volatile bool mayReceive = false; + volatile bool shouldTerminate = false; + + std::queue> pipelineQueue; + std::mutex queueMutex; + std::condition_variable queueNotify; +}; + +} // namespace gpurecoworkflow_internals } // namespace o2::gpu #endif diff --git a/GPU/Workflow/src/GPUWorkflowPipeline.cxx b/GPU/Workflow/src/GPUWorkflowPipeline.cxx index bdeffc7bed69d..b4286ca275a54 100644 --- a/GPU/Workflow/src/GPUWorkflowPipeline.cxx +++ b/GPU/Workflow/src/GPUWorkflowPipeline.cxx @@ -40,6 +40,7 @@ using namespace o2::header; using namespace o2::gpu; using namespace o2::base; using namespace o2::dataformats; +using namespace o2::gpu::gpurecoworkflow_internals; namespace o2::gpu { @@ -56,56 +57,21 @@ struct pipelinePrepareMessage { int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS) { - auto device = pc.services().get().device(); + auto* device = pc.services().get().device(); const auto& tinfo = pc.services().get(); if (mSpecConfig.enableDoublePipeline == 1) { - auto msg = device->NewMessageFor("gpu-prepare-channel", 0, 0); - bool received = false; - int recvTimeot = 1000; - do { - LOG(info) << "Waiting for out of band message"; - received = device->Receive(msg, "gpu-prepare-channel", 0, recvTimeot); - } while (!received && !device->NewStatePending()); - if (!received) { - return 1; - } - if (msg->GetSize() < sizeof(pipelinePrepareMessage)) { - LOG(fatal) << "Received prepare message of invalid size"; - } - const pipelinePrepareMessage* m = (const pipelinePrepareMessage*)msg->GetData(); - if (m->magicWord != m->MAGIC_WORD) { - LOG(fatal) << "Prepare message corrupted, invalid magic word"; - } - if (m->timeSliceId != tinfo.timeslice) { + std::unique_lock lk(mPipeline->queueMutex); + mPipeline->queueNotify.wait(lk, [this] { return !mPipeline->pipelineQueue.empty(); }); + auto o = std::move(mPipeline->pipelineQueue.front()); + mPipeline->pipelineQueue.pop(); + lk.unlock(); + + if (o->timeSliceId != tinfo.timeslice) { LOG(fatal) << "Prepare message for incorrect time frame received, time frames seem out of sync"; } - size_t regionOffset = 0; - if (m->pointersTotal) { - bool regionFound = false; - for (unsigned int i = 0; i < mRegionInfos.size(); i++) { - if (mRegionInfos[i].managed == m->regionInfo.managed && mRegionInfos[i].id == m->regionInfo.id) { - regionFound = true; - regionOffset = (size_t)mRegionInfos[i].ptr; - break; - } - } - } - size_t ptrsCopied = 0; - size_t* ptrBuffer = (size_t*)msg->GetData() + sizeof(pipelinePrepareMessage) / sizeof(size_t); - tpcZSmeta.Pointers[0][0].resize(m->pointersTotal); - tpcZSmeta.Sizes[0][0].resize(m->pointersTotal); - for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { - for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - tpcZS.slice[i].count[j] = m->pointerCounts[i][j]; - for (unsigned int k = 0; k < tpcZS.slice[i].count[j]; k++) { - tpcZSmeta.Pointers[0][0][ptrsCopied + k] = (void*)(ptrBuffer[ptrsCopied + k] + regionOffset); - tpcZSmeta.Sizes[0][0][ptrsCopied + k] = ptrBuffer[m->pointersTotal + ptrsCopied + k]; - } - tpcZS.slice[i].zsPtr[j] = tpcZSmeta.Pointers[0][0].data() + ptrsCopied; - tpcZS.slice[i].nZSPtr[j] = tpcZSmeta.Sizes[0][0].data() + ptrsCopied; - ptrsCopied += tpcZS.slice[i].count[j]; - } - } + + tpcZSmeta = std::move(o->tpcZSmeta); + tpcZS = o->tpcZS; ptrs.tpcZS = &tpcZS; } if (mSpecConfig.enableDoublePipeline == 2) { @@ -159,6 +125,7 @@ int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutP auto channel = device->GetChannels().find("gpu-prepare-channel"); fair::mq::MessagePtr payload(device->NewMessage()); + LOG(info) << "Sending gpu-reco-workflow prepare message of size " << prepareBufferSize; payload->Rebuild(messageBuffer.data(), prepareBufferSize, nullptr, nullptr); channel->second[0].Send(payload); return 2; @@ -166,4 +133,84 @@ int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutP return 0; } +void GPURecoWorkflowSpec::RunReceiveThread() +{ + std::unique_lock lk(mPipeline->threadMutex); + mPipeline->notifyThread.wait(lk, [this]() { return mPipeline->shouldTerminate || mPipeline->mayReceive; }); + lk.unlock(); + while (!mPipeline->shouldTerminate) { + auto* device = mPipeline->fmqDevice; + bool received = false; + int recvTimeot = 1000; + fair::mq::MessagePtr msg; + LOG(info) << "Waiting for out of band message"; + do { + try { + msg = device->NewMessageFor("gpu-prepare-channel", 0, 0); + do { + received = device->Receive(msg, "gpu-prepare-channel", 0, recvTimeot) > 0; + } while (!received && !mPipeline->shouldTerminate); + } catch (...) { + usleep(1000000); + } + } while (!received && !mPipeline->shouldTerminate); + if (mPipeline->shouldTerminate) { + break; + } + if (msg->GetSize() < sizeof(pipelinePrepareMessage)) { + LOG(fatal) << "Received prepare message of invalid size " << msg->GetSize() << " < " << sizeof(pipelinePrepareMessage); + } + const pipelinePrepareMessage* m = (const pipelinePrepareMessage*)msg->GetData(); + if (m->magicWord != m->MAGIC_WORD) { + LOG(fatal) << "Prepare message corrupted, invalid magic word"; + } + + auto o = std::make_unique(); + o->timeSliceId = m->timeSliceId; + o->tfSettings = m->tfSettings; + + size_t regionOffset = 0; + if (m->pointersTotal) { + bool regionFound = false; + for (unsigned int i = 0; i < mRegionInfos.size(); i++) { + if (mRegionInfos[i].managed == m->regionInfo.managed && mRegionInfos[i].id == m->regionInfo.id) { + regionFound = true; + regionOffset = (size_t)mRegionInfos[i].ptr; + break; + } + } + } + size_t ptrsCopied = 0; + size_t* ptrBuffer = (size_t*)msg->GetData() + sizeof(pipelinePrepareMessage) / sizeof(size_t); + o->tpcZSmeta.Pointers[0][0].resize(m->pointersTotal); + o->tpcZSmeta.Sizes[0][0].resize(m->pointersTotal); + for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { + for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + o->tpcZS.slice[i].count[j] = m->pointerCounts[i][j]; + for (unsigned int k = 0; k < o->tpcZS.slice[i].count[j]; k++) { + o->tpcZSmeta.Pointers[0][0][ptrsCopied + k] = (void*)(ptrBuffer[ptrsCopied + k] + regionOffset); + o->tpcZSmeta.Sizes[0][0][ptrsCopied + k] = ptrBuffer[m->pointersTotal + ptrsCopied + k]; + } + o->tpcZS.slice[i].zsPtr[j] = o->tpcZSmeta.Pointers[0][0].data() + ptrsCopied; + o->tpcZS.slice[i].nZSPtr[j] = o->tpcZSmeta.Sizes[0][0].data() + ptrsCopied; + ptrsCopied += o->tpcZS.slice[i].count[j]; + } + } + o->ptrs.tpcZS = &o->tpcZS; + { + std::lock_guard lk(mPipeline->queueMutex); + mPipeline->pipelineQueue.emplace(std::move(o)); + } + mPipeline->queueNotify.notify_one(); + } +} + +void GPURecoWorkflowSpec::TerminateReceiveThread() +{ + if (mPipeline->receiveThread.joinable()) { + mPipeline->shouldTerminate = true; + mPipeline->receiveThread.join(); + } +} + } // namespace o2::gpu diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 302aba2b78ebb..84d9284febfda 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -27,6 +27,7 @@ #include "Framework/Logger.h" #include "Framework/CallbackService.h" #include "Framework/CCDBParamSpec.h" +#include "Framework/RawDeviceService.h" #include "DataFormatsTPC/TPCSectorHeader.h" #include "DataFormatsTPC/ClusterNative.h" #include "DataFormatsTPC/CompressedClusters.h" @@ -101,6 +102,7 @@ using namespace o2::header; using namespace o2::gpu; using namespace o2::base; using namespace o2::dataformats; +using namespace o2::gpu::gpurecoworkflow_internals; namespace o2::gpu { @@ -115,6 +117,7 @@ GPURecoWorkflowSpec::GPURecoWorkflowSpec(GPURecoWorkflowSpec::CompletionPolicyDa mConfParam.reset(new GPUSettingsO2); mTFSettings.reset(new GPUSettingsTF); mTimer.reset(new TStopwatch); + mPipeline.reset(new GPURecoWorkflowSpec_PipelineInternals); } GPURecoWorkflowSpec::~GPURecoWorkflowSpec() = default; @@ -282,6 +285,11 @@ void GPURecoWorkflowSpec::init(InitContext& ic) } } + if (mSpecConfig.enableDoublePipeline == 1) { + mPipeline->fmqDevice = ic.services().get().device(); + mPipeline->receiveThread = std::thread([this]() { RunReceiveThread(); }); + } + auto& callbacks = ic.services().get(); callbacks.set([this](fair::mq::RegionInfo const& info) { if (info.size == 0) { @@ -339,6 +347,7 @@ void GPURecoWorkflowSpec::stop() void GPURecoWorkflowSpec::endOfStream(EndOfStreamContext& ec) { + TerminateReceiveThread(); // TODO: Apparently breaks START / STOP / START } void GPURecoWorkflowSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) @@ -507,20 +516,15 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) getWorkflowTPCInput_digits = true; } - auto lockDecodeInput = std::make_unique>(mMutexDecodeInput); - // unsigned int threadIndex = pc.services().get().threadIndex; - unsigned int threadIndex = mNextThreadIndex; - if (mConfig->configProcessing.doublePipeline) { - mNextThreadIndex = (mNextThreadIndex + 1) % 2; - } + // ------------------------------ Handle inputs ------------------------------ + + auto lockDecodeInput = std::make_unique>(mPipeline->mutexDecodeInput); GRPGeomHelper::instance().checkUpdates(pc); if (GRPGeomHelper::instance().getGRPECS()->isDetReadOut(o2::detectors::DetID::TPC) && mConfParam->tpcTriggeredMode ^ !GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::TPC)) { LOG(fatal) << "configKeyValue tpcTriggeredMode does not match GRP isDetContinuousReadOut(TPC) setting"; } - // ------------------------------ Handle inputs ------------------------------ - GPUTrackingInOutPointers ptrs; processInputs(pc, tpcZSmeta, inputZS, tpcZS, tpcZSonTheFlySizes, debugTFDump, compClustersDummy, compClustersFlatDummy, pCompClustersFlat, tmpEmptyCompClusters); // Process non-digit / non-cluster inputs const auto& inputsClustersDigits = o2::tpc::getWorkflowTPCInput(pc, mVerbosity, getWorkflowTPCInput_mc, getWorkflowTPCInput_clusters, mTPCSectorMask, getWorkflowTPCInput_digits); // Process digit and cluster inputs @@ -620,6 +624,15 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) // ------------------------------ Prepare stage for double-pipeline before normal output preparation ------------------------------ + // unsigned int threadIndex = pc.services().get().threadIndex; + unsigned int threadIndex = mNextThreadIndex; + if (mConfig->configProcessing.doublePipeline) { + mNextThreadIndex = (mNextThreadIndex + 1) % 2; + std::lock_guard lk(mPipeline->threadMutex); + mPipeline->mayReceive = true; + mPipeline->notifyThread.notify_one(); + } + if (mSpecConfig.enableDoublePipeline) { if (handlePipeline(pc, ptrs, tpcZSmeta, tpcZS)) { return; @@ -1170,6 +1183,7 @@ Outputs GPURecoWorkflowSpec::outputs() void GPURecoWorkflowSpec::deinitialize() { + TerminateReceiveThread(); mQA.reset(nullptr); mDisplayFrontend.reset(nullptr); mGPUReco.reset(nullptr); From aa2a7836cf99e4526c89c2e28c808d9791cd3674 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sat, 23 Sep 2023 12:50:12 +0200 Subject: [PATCH 106/324] GPU Standalone multi-threading: handle end-of-stream over out-of-band channel --- .../include/GPUWorkflow/GPUWorkflowSpec.h | 2 +- GPU/Workflow/src/GPUWorkflowInternal.h | 1 - GPU/Workflow/src/GPUWorkflowPipeline.cxx | 31 ++++++++++++++++--- GPU/Workflow/src/GPUWorkflowSpec.cxx | 5 +-- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index 91050d1cd9d9d..c8e9e0ce71657 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -21,7 +21,6 @@ #include "Framework/Task.h" #include "Framework/ConcreteDataMatcher.h" #include "Framework/InitContext.h" -#include "Framework/ProcessingContext.h" #include "Framework/CompletionPolicy.h" #include "Algorithm/Parser.h" #include @@ -162,6 +161,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task int handlePipeline(o2::framework::ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, gpurecoworkflow_internals::GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS); void RunReceiveThread(); void TerminateReceiveThread(); + void handlePipelineEndOfStream(o2::framework::EndOfStreamContext& ec); CompletionPolicyData* mPolicyData; std::unique_ptr mGPUReco; diff --git a/GPU/Workflow/src/GPUWorkflowInternal.h b/GPU/Workflow/src/GPUWorkflowInternal.h index 152a94c8ef0c1..4e3197ac74a28 100644 --- a/GPU/Workflow/src/GPUWorkflowInternal.h +++ b/GPU/Workflow/src/GPUWorkflowInternal.h @@ -49,7 +49,6 @@ struct GPURecoWorkflowSpec_PipelineInternals { std::thread receiveThread; std::condition_variable notifyThread; std::mutex threadMutex; - volatile bool mayReceive = false; volatile bool shouldTerminate = false; std::queue> pipelineQueue; diff --git a/GPU/Workflow/src/GPUWorkflowPipeline.cxx b/GPU/Workflow/src/GPUWorkflowPipeline.cxx index b4286ca275a54..728bda6306881 100644 --- a/GPU/Workflow/src/GPUWorkflowPipeline.cxx +++ b/GPU/Workflow/src/GPUWorkflowPipeline.cxx @@ -53,6 +53,7 @@ struct pipelinePrepareMessage { fair::mq::RegionInfo regionInfo; size_t pointerCounts[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; size_t pointersTotal; + bool flagEndOfStream; }; int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS) @@ -94,6 +95,7 @@ int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutP preMessage.magicWord = preMessage.MAGIC_WORD; preMessage.timeSliceId = tinfo.timeslice; preMessage.pointersTotal = ptrsTotal; + preMessage.flagEndOfStream = false; memcpy((void*)&preMessage.tfSettings, (const void*)ptrs.settingsTF, sizeof(preMessage.tfSettings)); if (ptrsTotal) { @@ -133,13 +135,30 @@ int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutP return 0; } +void GPURecoWorkflowSpec::handlePipelineEndOfStream(EndOfStreamContext& ec) +{ + if (mSpecConfig.enableDoublePipeline == 1) { + TerminateReceiveThread(); // TODO: Apparently breaks START / STOP / START + } + if (mSpecConfig.enableDoublePipeline == 2) { + auto* device = ec.services().get().device(); + pipelinePrepareMessage preMessage; + preMessage.flagEndOfStream = true; + auto channel = device->GetChannels().find("gpu-prepare-channel"); + fair::mq::MessagePtr payload(device->NewMessage()); + LOG(info) << "Sending end-of-stream message over out-of-bands channel"; + payload->Rebuild(&preMessage, sizeof(preMessage), nullptr, nullptr); + channel->second[0].Send(payload); + } +} + void GPURecoWorkflowSpec::RunReceiveThread() { - std::unique_lock lk(mPipeline->threadMutex); - mPipeline->notifyThread.wait(lk, [this]() { return mPipeline->shouldTerminate || mPipeline->mayReceive; }); - lk.unlock(); + auto* device = mPipeline->fmqDevice; + while (device->GetCurrentState() != fair::mq::State::Running) { + usleep(300000); + } while (!mPipeline->shouldTerminate) { - auto* device = mPipeline->fmqDevice; bool received = false; int recvTimeot = 1000; fair::mq::MessagePtr msg; @@ -164,6 +183,10 @@ void GPURecoWorkflowSpec::RunReceiveThread() if (m->magicWord != m->MAGIC_WORD) { LOG(fatal) << "Prepare message corrupted, invalid magic word"; } + if (m->flagEndOfStream) { + LOG(info) << "Received end-of-stream from out-of-band channel"; + continue; + } auto o = std::make_unique(); o->timeSliceId = m->timeSliceId; diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 84d9284febfda..265971e83b6d0 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -347,7 +347,7 @@ void GPURecoWorkflowSpec::stop() void GPURecoWorkflowSpec::endOfStream(EndOfStreamContext& ec) { - TerminateReceiveThread(); // TODO: Apparently breaks START / STOP / START + handlePipelineEndOfStream(ec); } void GPURecoWorkflowSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) @@ -628,9 +628,6 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) unsigned int threadIndex = mNextThreadIndex; if (mConfig->configProcessing.doublePipeline) { mNextThreadIndex = (mNextThreadIndex + 1) % 2; - std::lock_guard lk(mPipeline->threadMutex); - mPipeline->mayReceive = true; - mPipeline->notifyThread.notify_one(); } if (mSpecConfig.enableDoublePipeline) { From c2ef83c5c5b554d82329521d719a3ee7b7456fcc Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sat, 23 Sep 2023 15:11:45 +0200 Subject: [PATCH 107/324] TPC: Support callback in SectorCompletionPolicy that defines an ordering --- .../TPCSectorCompletionPolicy.h | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h index bb321eaa7bbd5..99bb5bc6513d7 100644 --- a/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h +++ b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h @@ -20,6 +20,7 @@ #include "Framework/InputSpec.h" #include "Framework/InputSpan.h" #include "Framework/DeviceSpec.h" +#include "Framework/DataProcessingHeader.h" #include "DataFormatsTPC/TPCSectorHeader.h" #include "Headers/DataHeaderHelpers.h" #include "TPCBase/Sector.h" @@ -29,6 +30,7 @@ #include #include #include +#include namespace o2 { @@ -89,7 +91,7 @@ class TPCSectorCompletionPolicy return std::regex_match(device.name.begin(), device.name.end(), std::regex(expression.c_str())); }; - auto callback = [bRequireAll = mRequireAll, inputMatchers = mInputMatchers, externalInputMatchers = mExternalInputMatchers, pTpcSectorMask = mTpcSectorMask](framework::InputSpan const& inputs) -> framework::CompletionPolicy::CompletionOp { + auto callback = [bRequireAll = mRequireAll, inputMatchers = mInputMatchers, externalInputMatchers = mExternalInputMatchers, pTpcSectorMask = mTpcSectorMask, orderCheck = mOrderCheck](framework::InputSpan const& inputs) -> framework::CompletionPolicy::CompletionOp { unsigned long tpcSectorMask = pTpcSectorMask ? *pTpcSectorMask : 0xFFFFFFFFF; std::bitset validSectors = 0; bool haveMatchedInput = false; @@ -165,6 +167,7 @@ class TPCSectorCompletionPolicy } } + o2::framework::CompletionPolicy::CompletionOp retVal = framework::CompletionPolicy::CompletionOp::Wait; // If the flag Config::RequireAll is set in the constructor arguments we require // data from all inputs in addition to the sector matching condition // To be fully correct we would need to require data from all inputs not going @@ -175,7 +178,7 @@ class TPCSectorCompletionPolicy (!bRequireAll || nActiveInputRoutes == inputs.size())) { // we can process if there is input for all sectors, the required sectors are // transported as part of the sector header - return framework::CompletionPolicy::CompletionOp::Consume; + retVal = framework::CompletionPolicy::CompletionOp::Consume; } else if (activeSectors == 0 && nActiveInputRoutes == inputs.size()) { // no sector header is transmitted, this is the case for e.g. the ZS raw data // we simply require input on all routes, this is also the default of DPL DataRelayer @@ -184,13 +187,25 @@ class TPCSectorCompletionPolicy // Currently, the workflow has multiple O2 messages per input route, but they all come in // a single multipart message. So it works fine, and we disable the warning below, but there // is a potential problem. Need to fix this on the level of the workflow. - //if (nMaxPartsPerRoute > 1) { + // if (nMaxPartsPerRoute ) { // LOG(warning) << "No sector information is provided with the data, data set is complete with data on all input routes. But there are multiple parts on at least one route and this policy might not be complete, no check possible if other parts on some routes are still missing. It is adviced to add a custom policy."; //} - return framework::CompletionPolicy::CompletionOp::Consume; + retVal = framework::CompletionPolicy::CompletionOp::Consume; } - return framework::CompletionPolicy::CompletionOp::Wait; + if (retVal != framework::CompletionPolicy::CompletionOp::Wait && orderCheck && *orderCheck && **orderCheck) { + for (auto& input : inputs) { + auto* dph = framework::DataRefUtils::getHeader(input); + if (!dph) { + continue; + } + if (!(**orderCheck)(dph->startTime)) { + retVal = framework::CompletionPolicy::CompletionOp::Wait; + } + break; + } + } + return retVal; }; return framework::CompletionPolicy{"TPCSectorCompletionPolicy", matcher, callback}; } @@ -211,6 +226,8 @@ class TPCSectorCompletionPolicy } } else if constexpr (std::is_same_v*>) { mExternalInputMatchers = arg; + } else if constexpr (std::is_same_v**>) { + mOrderCheck = arg; } else if constexpr (std::is_same_v || std::is_same_v) { mTpcSectorMask = arg; } else { @@ -223,6 +240,7 @@ class TPCSectorCompletionPolicy std::string mProcessorName; std::vector mInputMatchers; + std::function** mOrderCheck = nullptr; // The external input matchers behave as the internal ones with the following differences: // - They are controlled externally and the external entity can modify them, e.g. after parsing command line arguments. // - They are all matched independently, it is not sufficient that one of them is present for all sectors From a595585e83d32f31e5da09ed38820168ecc26e45 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sat, 23 Sep 2023 15:12:18 +0200 Subject: [PATCH 108/324] GPU: Ensure that gpu-prepare-workflow and gpu-workflow process time frames in the same order via completion policy --- .../include/GPUWorkflow/GPUWorkflowSpec.h | 5 ++- GPU/Workflow/src/GPUWorkflowInternal.h | 6 +++- GPU/Workflow/src/GPUWorkflowPipeline.cxx | 31 +++++++++++++++++-- GPU/Workflow/src/GPUWorkflowSpec.cxx | 11 ++++--- GPU/Workflow/src/gpu-reco-workflow.cxx | 3 +- 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index c8e9e0ce71657..d61bdcbcf2cc4 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -27,6 +27,7 @@ #include #include #include +#include class TStopwatch; namespace fair::mq @@ -122,7 +123,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task bool tpcTriggerHandling = false; }; - GPURecoWorkflowSpec(CompletionPolicyData* policyData, Config const& specconfig, std::vector const& tpcsectors, unsigned long tpcSectorMask, std::shared_ptr& ggr); + GPURecoWorkflowSpec(CompletionPolicyData* policyData, Config const& specconfig, std::vector const& tpcsectors, unsigned long tpcSectorMask, std::shared_ptr& ggr, std::function** gPolicyOrder = nullptr); ~GPURecoWorkflowSpec() override; void init(o2::framework::InitContext& ic) final; void run(o2::framework::ProcessingContext& pc) final; @@ -162,8 +163,10 @@ class GPURecoWorkflowSpec : public o2::framework::Task void RunReceiveThread(); void TerminateReceiveThread(); void handlePipelineEndOfStream(o2::framework::EndOfStreamContext& ec); + void initPipeline(o2::framework::InitContext& ic); CompletionPolicyData* mPolicyData; + std::function mPolicyOrder; std::unique_ptr mGPUReco; std::unique_ptr mDisplayFrontend; std::unique_ptr mFastTransform; diff --git a/GPU/Workflow/src/GPUWorkflowInternal.h b/GPU/Workflow/src/GPUWorkflowInternal.h index 4e3197ac74a28..7a739d30a8f3d 100644 --- a/GPU/Workflow/src/GPUWorkflowInternal.h +++ b/GPU/Workflow/src/GPUWorkflowInternal.h @@ -47,13 +47,17 @@ struct GPURecoWorkflowSpec_PipelineInternals { fair::mq::Device* fmqDevice; std::thread receiveThread; - std::condition_variable notifyThread; std::mutex threadMutex; volatile bool shouldTerminate = false; std::queue> pipelineQueue; std::mutex queueMutex; std::condition_variable queueNotify; + + std::queue completionPolicyQueue; + bool pipelineSenderTerminating = false; + std::mutex completionPolicyMutex; + std::condition_variable completionPolicyNotify; }; } // namespace gpurecoworkflow_internals diff --git a/GPU/Workflow/src/GPUWorkflowPipeline.cxx b/GPU/Workflow/src/GPUWorkflowPipeline.cxx index 728bda6306881..c43269f6c8233 100644 --- a/GPU/Workflow/src/GPUWorkflowPipeline.cxx +++ b/GPU/Workflow/src/GPUWorkflowPipeline.cxx @@ -56,6 +56,23 @@ struct pipelinePrepareMessage { bool flagEndOfStream; }; +void GPURecoWorkflowSpec::initPipeline(o2::framework::InitContext& ic) +{ + if (mSpecConfig.enableDoublePipeline == 1) { + mPipeline->fmqDevice = ic.services().get().device(); + mPolicyOrder = [this](o2::framework::DataProcessingHeader::StartTime timeslice) { + std::unique_lock lk(mPipeline->completionPolicyMutex); + mPipeline->completionPolicyNotify.wait(lk, [pipeline = mPipeline.get()] { return pipeline->pipelineSenderTerminating || !pipeline->completionPolicyQueue.empty(); }); + if (mPipeline->completionPolicyQueue.front() == timeslice) { + mPipeline->completionPolicyQueue.pop(); + return true; + } + return false; + }; + mPipeline->receiveThread = std::thread([this]() { RunReceiveThread(); }); + } +} + int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS) { auto* device = pc.services().get().device(); @@ -184,8 +201,8 @@ void GPURecoWorkflowSpec::RunReceiveThread() LOG(fatal) << "Prepare message corrupted, invalid magic word"; } if (m->flagEndOfStream) { - LOG(info) << "Received end-of-stream from out-of-band channel"; - continue; + LOG(info) << "Received end-of-stream from out-of-band channel, terminating receive thread"; // TODO: Breaks START / STOP / START + break; } auto o = std::make_unique(); @@ -220,12 +237,22 @@ void GPURecoWorkflowSpec::RunReceiveThread() } } o->ptrs.tpcZS = &o->tpcZS; + { + std::lock_guard lk(mPipeline->completionPolicyMutex); + mPipeline->completionPolicyQueue.emplace(m->timeSliceId); + } + mPipeline->completionPolicyNotify.notify_one(); { std::lock_guard lk(mPipeline->queueMutex); mPipeline->pipelineQueue.emplace(std::move(o)); } mPipeline->queueNotify.notify_one(); } + { + std::lock_guard lk(mPipeline->completionPolicyMutex); + mPipeline->pipelineSenderTerminating = true; + } + mPipeline->completionPolicyNotify.notify_one(); } void GPURecoWorkflowSpec::TerminateReceiveThread() diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 265971e83b6d0..883c0e26606fb 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -107,7 +107,7 @@ using namespace o2::gpu::gpurecoworkflow_internals; namespace o2::gpu { -GPURecoWorkflowSpec::GPURecoWorkflowSpec(GPURecoWorkflowSpec::CompletionPolicyData* policyData, Config const& specconfig, std::vector const& tpcsectors, unsigned long tpcSectorMask, std::shared_ptr& ggr) : o2::framework::Task(), mPolicyData(policyData), mTPCSectorMask(tpcSectorMask), mTPCSectors(tpcsectors), mSpecConfig(specconfig), mGGR(ggr) +GPURecoWorkflowSpec::GPURecoWorkflowSpec(GPURecoWorkflowSpec::CompletionPolicyData* policyData, Config const& specconfig, std::vector const& tpcsectors, unsigned long tpcSectorMask, std::shared_ptr& ggr, std::function** gPolicyOrder) : o2::framework::Task(), mPolicyData(policyData), mTPCSectorMask(tpcSectorMask), mTPCSectors(tpcsectors), mSpecConfig(specconfig), mGGR(ggr) { if (mSpecConfig.outputCAClusters && !mSpecConfig.caClusterer && !mSpecConfig.decompressTPC) { throw std::runtime_error("inconsistent configuration: cluster output is only possible if CA clusterer is activated"); @@ -118,6 +118,10 @@ GPURecoWorkflowSpec::GPURecoWorkflowSpec(GPURecoWorkflowSpec::CompletionPolicyDa mTFSettings.reset(new GPUSettingsTF); mTimer.reset(new TStopwatch); mPipeline.reset(new GPURecoWorkflowSpec_PipelineInternals); + + if (mSpecConfig.enableDoublePipeline == 1 && gPolicyOrder) { + *gPolicyOrder = &mPolicyOrder; + } } GPURecoWorkflowSpec::~GPURecoWorkflowSpec() = default; @@ -285,9 +289,8 @@ void GPURecoWorkflowSpec::init(InitContext& ic) } } - if (mSpecConfig.enableDoublePipeline == 1) { - mPipeline->fmqDevice = ic.services().get().device(); - mPipeline->receiveThread = std::thread([this]() { RunReceiveThread(); }); + if (mSpecConfig.enableDoublePipeline) { + initPipeline(ic); } auto& callbacks = ic.services().get(); diff --git a/GPU/Workflow/src/gpu-reco-workflow.cxx b/GPU/Workflow/src/gpu-reco-workflow.cxx index 4152f247c4ace..1150212451f1b 100644 --- a/GPU/Workflow/src/gpu-reco-workflow.cxx +++ b/GPU/Workflow/src/gpu-reco-workflow.cxx @@ -38,6 +38,7 @@ using namespace o2::gpu; using CompletionPolicyData = std::vector; static CompletionPolicyData gPolicyData; static constexpr unsigned long gTpcSectorMask = 0xFFFFFFFFF; +static std::function* gPolicyOrderCheck; static std::shared_ptr gTask; void customize(std::vector& policies) @@ -71,7 +72,7 @@ void customize(std::vector& policies) void customize(std::vector& policies) { - policies.push_back(o2::tpc::TPCSectorCompletionPolicy("gpu-reconstruction.*", o2::tpc::TPCSectorCompletionPolicy::Config::RequireAll, &gPolicyData, &gTpcSectorMask)()); + policies.push_back(o2::tpc::TPCSectorCompletionPolicy("gpu-reconstruction.*", o2::tpc::TPCSectorCompletionPolicy::Config::RequireAll, &gPolicyData, &gTpcSectorMask, &gPolicyOrderCheck)()); } void customize(o2::framework::OnWorkflowTerminationHook& hook) From cd9d179f17ac1c7aaf214b3fa17649f12f9a8c79 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 24 Sep 2023 11:47:24 +0200 Subject: [PATCH 109/324] GPU: Make setting updated calib objects / applying them thread-safe --- GPU/GPUTracking/Global/GPUChainTracking.cxx | 12 ++++++++---- GPU/GPUTracking/Global/GPUChainTracking.h | 6 ++++-- .../Global/GPUChainTrackingSliceTracker.cxx | 5 ++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 01ee9f9d013a1..78fa1370bac7a 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -611,10 +611,11 @@ void GPUChainTracking::DoQueuedUpdates(int stream) { std::unique_ptr grp; const GPUSettingsProcessing* p = nullptr; + std::lock_guard lk(mMutexUpdateCalib); if (mUpdateNewCalibObjects) { - void** pSrc = (void**)&mNewCalibObjects; + void** pSrc = (void**)mNewCalibObjects.get(); void** pDst = (void**)&processors()->calibObjects; - for (unsigned int i = 0; i < sizeof(mNewCalibObjects) / sizeof(void*); i++) { + for (unsigned int i = 0; i < sizeof(processors()->calibObjects) / sizeof(void*); i++) { if (pSrc[i]) { pDst[i] = pSrc[i]; } @@ -628,7 +629,7 @@ void GPUChainTracking::DoQueuedUpdates(int stream) if (ptrsChanged) { GPUInfo("Updating all calib objects since pointers changed"); } - UpdateGPUCalibObjects(stream, ptrsChanged ? nullptr : &mNewCalibObjects); + UpdateGPUCalibObjects(stream, ptrsChanged ? nullptr : mNewCalibObjects.get()); } if (mNewCalibValues->newSolenoidField || mNewCalibValues->newContinuousMaxTimeBin) { grp = std::make_unique(mRec->GetGRPSettings()); @@ -650,6 +651,8 @@ void GPUChainTracking::DoQueuedUpdates(int stream) if ((mUpdateNewCalibObjects || mRec->slavesExist()) && mRec->IsGPU()) { UpdateGPUCalibObjectsPtrs(stream); // Reinitialize } + mNewCalibObjects.reset(nullptr); + mNewCalibValues.reset(nullptr); mUpdateNewCalibObjects = false; } @@ -964,7 +967,8 @@ void GPUChainTracking::SetDefaultInternalO2Propagator(bool useGPUField) void GPUChainTracking::SetUpdateCalibObjects(const GPUCalibObjectsConst& obj, const GPUNewCalibValues& vals) { - mNewCalibObjects = obj; + std::lock_guard lk(mMutexUpdateCalib); + mNewCalibObjects.reset(new GPUCalibObjectsConst(obj)); mNewCalibValues.reset(new GPUNewCalibValues(vals)); mUpdateNewCalibObjects = true; } diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index a81fee89f8c67..98a6ab9421649 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -19,6 +19,7 @@ #include "GPUReconstructionHelpers.h" #include "GPUDataTypes.h" #include +#include #include #include #include @@ -272,7 +273,7 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega // (Ptrs to) configuration objects std::unique_ptr mCFContext; bool mTPCSliceScratchOnStack = false; - GPUCalibObjectsConst mNewCalibObjects; + std::unique_ptr mNewCalibObjects; bool mUpdateNewCalibObjects = false; std::unique_ptr mNewCalibValues; @@ -305,7 +306,8 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega void RunTPCTrackingMerger_MergeBorderTracks(char withinSlice, char mergeMode, GPUReconstruction::krnlDeviceType deviceType); void RunTPCTrackingMerger_Resolve(char useOrigTrackParam, char mergeAll, GPUReconstruction::krnlDeviceType deviceType); - std::atomic_flag mLockAtomic = ATOMIC_FLAG_INIT; + std::atomic_flag mLockAtomicOutputBuffer = ATOMIC_FLAG_INIT; + std::mutex mMutexUpdateCalib; std::unique_ptr mPipelineFinalizationCtx; GPUChainTrackingFinalContext* mPipelineNotifyCtx = nullptr; diff --git a/GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx b/GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx index c976af9738b59..4d023cc8bca22 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx @@ -482,13 +482,12 @@ void GPUChainTracking::WriteOutput(int iSlice, int threadId) GPUInfo("Running WriteOutput for slice %d on thread %d\n", iSlice, threadId); } if (GetProcessingSettings().nDeviceHelperThreads) { - while (mLockAtomic.test_and_set(std::memory_order_acquire)) { - ; + while (mLockAtomicOutputBuffer.test_and_set(std::memory_order_acquire)) { } } processors()->tpcTrackers[iSlice].WriteOutputPrepare(); if (GetProcessingSettings().nDeviceHelperThreads) { - mLockAtomic.clear(); + mLockAtomicOutputBuffer.clear(); } processors()->tpcTrackers[iSlice].WriteOutput(); if (GetProcessingSettings().debugLevel >= 5) { From 594bb3266d72480bac83157ed4fa9f41341240f3 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 24 Sep 2023 11:18:20 +0200 Subject: [PATCH 110/324] GPU Workflow: Run 2 threads for the async pipelines, and dispatch the jobs via them --- .../include/GPUWorkflow/GPUWorkflowSpec.h | 9 ++- GPU/Workflow/src/GPUWorkflowInternal.h | 17 +++++ GPU/Workflow/src/GPUWorkflowPipeline.cxx | 65 ++++++++++++++++--- GPU/Workflow/src/GPUWorkflowSpec.cxx | 57 +++++++++++----- 4 files changed, 120 insertions(+), 28 deletions(-) diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index d61bdcbcf2cc4..0098a3c456193 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -84,10 +84,12 @@ struct GPUSettingsO2; class GPUO2InterfaceQA; struct GPUTrackingInOutPointers; struct GPUTrackingInOutZS; +struct GPUInterfaceOutputs; namespace gpurecoworkflow_internals { struct GPURecoWorkflowSpec_TPCZSBuffers; struct GPURecoWorkflowSpec_PipelineInternals; +struct GPURecoWorkflow_QueueObject; } // namespace gpurecoworkflow_internals class GPURecoWorkflowSpec : public o2::framework::Task @@ -159,11 +161,14 @@ class GPURecoWorkflowSpec : public o2::framework::Task int runITSTracking(o2::framework::ProcessingContext& pc); - int handlePipeline(o2::framework::ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, gpurecoworkflow_internals::GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS); + int handlePipeline(o2::framework::ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, gpurecoworkflow_internals::GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS, std::unique_ptr& context); void RunReceiveThread(); - void TerminateReceiveThread(); + void RunWorkerThread(int id); + void TerminateThreads(); void handlePipelineEndOfStream(o2::framework::EndOfStreamContext& ec); void initPipeline(o2::framework::InitContext& ic); + void enqueuePipelinedJob(GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, gpurecoworkflow_internals::GPURecoWorkflow_QueueObject* context); + int runMain(o2::framework::ProcessingContext* pc, GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, int threadIndex); CompletionPolicyData* mPolicyData; std::function mPolicyOrder; diff --git a/GPU/Workflow/src/GPUWorkflowInternal.h b/GPU/Workflow/src/GPUWorkflowInternal.h index 7a739d30a8f3d..ac24c0b9e99b4 100644 --- a/GPU/Workflow/src/GPUWorkflowInternal.h +++ b/GPU/Workflow/src/GPUWorkflowInternal.h @@ -20,6 +20,7 @@ #include #include #include +#include namespace o2::gpu { @@ -39,6 +40,14 @@ struct GPURecoWorkflow_QueueObject { GPUSettingsTF tfSettings; GPUTrackingInOutPointers ptrs; o2::framework::DataProcessingHeader::StartTime timeSliceId; + + bool jobSubmitted = false; + bool jobFinished = false; + int jobReturnValue = 0; + std::mutex jobFinishedMutex; + std::condition_variable jobFinishedNotify; + GPUTrackingInOutPointers* jobPtrs; + GPUInterfaceOutputs* jobOutputRegions; }; struct GPURecoWorkflowSpec_PipelineInternals { @@ -50,6 +59,14 @@ struct GPURecoWorkflowSpec_PipelineInternals { std::mutex threadMutex; volatile bool shouldTerminate = false; + struct pipelineWorkerStruct { + std::thread thread; + std::queue inputQueue; + std::mutex inputQueueMutex; + std::condition_variable inputQueueNotify; + }; + std::array workers; + std::queue> pipelineQueue; std::mutex queueMutex; std::condition_variable queueNotify; diff --git a/GPU/Workflow/src/GPUWorkflowPipeline.cxx b/GPU/Workflow/src/GPUWorkflowPipeline.cxx index c43269f6c8233..6ed80f4cfc9bd 100644 --- a/GPU/Workflow/src/GPUWorkflowPipeline.cxx +++ b/GPU/Workflow/src/GPUWorkflowPipeline.cxx @@ -70,26 +70,67 @@ void GPURecoWorkflowSpec::initPipeline(o2::framework::InitContext& ic) return false; }; mPipeline->receiveThread = std::thread([this]() { RunReceiveThread(); }); + for (unsigned int i = 0; i < mPipeline->workers.size(); i++) { + mPipeline->workers[i].thread = std::thread([this, i]() { RunWorkerThread(i); }); + } + } +} + +void GPURecoWorkflowSpec::RunWorkerThread(int id) +{ + LOG(info) << "Running pipeline worker " << id; + auto& workerContext = mPipeline->workers[id]; + while (!mPipeline->shouldTerminate) { + GPURecoWorkflow_QueueObject* context; + { + std::unique_lock lk(workerContext.inputQueueMutex); + workerContext.inputQueueNotify.wait(lk, [this, &workerContext]() { return mPipeline->shouldTerminate || !workerContext.inputQueue.empty(); }); + if (workerContext.inputQueue.empty()) { + break; + } + context = workerContext.inputQueue.front(); + workerContext.inputQueue.pop(); + } + context->jobReturnValue = runMain(nullptr, context->jobPtrs, context->jobOutputRegions, id); + { + std::lock_guard lk(context->jobFinishedMutex); + context->jobFinished = true; + } + context->jobFinishedNotify.notify_one(); + } +} + +void GPURecoWorkflowSpec::enqueuePipelinedJob(GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, GPURecoWorkflow_QueueObject* context) +{ + context->jobSubmitted = true; + context->jobPtrs = ptrs; + context->jobOutputRegions = outputRegions; + mNextThreadIndex = (mNextThreadIndex + 1) % 2; + + { + std::lock_guard lk(mPipeline->workers[mNextThreadIndex].inputQueueMutex); + mPipeline->workers[mNextThreadIndex].inputQueue.emplace(context); } + mPipeline->workers[mNextThreadIndex].inputQueueNotify.notify_one(); } -int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS) +int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS, std::unique_ptr& context) { auto* device = pc.services().get().device(); const auto& tinfo = pc.services().get(); if (mSpecConfig.enableDoublePipeline == 1) { std::unique_lock lk(mPipeline->queueMutex); mPipeline->queueNotify.wait(lk, [this] { return !mPipeline->pipelineQueue.empty(); }); - auto o = std::move(mPipeline->pipelineQueue.front()); + context = std::move(mPipeline->pipelineQueue.front()); mPipeline->pipelineQueue.pop(); lk.unlock(); - if (o->timeSliceId != tinfo.timeslice) { + if (context->timeSliceId != tinfo.timeslice) { LOG(fatal) << "Prepare message for incorrect time frame received, time frames seem out of sync"; } - tpcZSmeta = std::move(o->tpcZSmeta); - tpcZS = o->tpcZS; + tpcZSmeta = std::move(context->tpcZSmeta); + tpcZS = context->tpcZS; ptrs.tpcZS = &tpcZS; } if (mSpecConfig.enableDoublePipeline == 2) { @@ -155,7 +196,7 @@ int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutP void GPURecoWorkflowSpec::handlePipelineEndOfStream(EndOfStreamContext& ec) { if (mSpecConfig.enableDoublePipeline == 1) { - TerminateReceiveThread(); // TODO: Apparently breaks START / STOP / START + TerminateThreads(); // TODO: Apparently breaks START / STOP / START } if (mSpecConfig.enableDoublePipeline == 2) { auto* device = ec.services().get().device(); @@ -255,12 +296,20 @@ void GPURecoWorkflowSpec::RunReceiveThread() mPipeline->completionPolicyNotify.notify_one(); } -void GPURecoWorkflowSpec::TerminateReceiveThread() +void GPURecoWorkflowSpec::TerminateThreads() { + mPipeline->shouldTerminate = true; + for (unsigned int i = 0; i < mPipeline->workers.size(); i++) { + mPipeline->workers[i].inputQueueNotify.notify_one(); + } if (mPipeline->receiveThread.joinable()) { - mPipeline->shouldTerminate = true; mPipeline->receiveThread.join(); } + for (unsigned int i = 0; i < mPipeline->workers.size(); i++) { + if (mPipeline->workers[i].thread.joinable()) { + mPipeline->workers[i].thread.join(); + } + } } } // namespace o2::gpu diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 883c0e26606fb..d7d203507d55e 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -291,6 +291,9 @@ void GPURecoWorkflowSpec::init(InitContext& ic) if (mSpecConfig.enableDoublePipeline) { initPipeline(ic); + if (mConfParam->dump >= 2) { + LOG(fatal) << "Cannot use dump-only mode with multi-threaded pipeline"; + } } auto& callbacks = ic.services().get(); @@ -484,6 +487,23 @@ void GPURecoWorkflowSpec::processInputs(ProcessingContext& pc, D& tpcZSmeta, E& } } +int GPURecoWorkflowSpec::runMain(o2::framework::ProcessingContext* pc, GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, int threadIndex) +{ + int retVal = 0; + if (mConfParam->dump < 2) { + retVal = mGPUReco->RunTracking(ptrs, outputRegions, threadIndex); + + if (retVal == 0 && mSpecConfig.runITSTracking) { + retVal = runITSTracking(*pc); + } + } + + cleanOldCalibsTPCPtrs(); // setting TPC calibration objects + // if (!mTrackingCAO2Interface->getConfig().configInterface.outputToExternalBuffers) // TODO: Why was this needed for double-pipeline? + mGPUReco->Clear(false, threadIndex); // clean non-output memory used by GPU Reconstruction + return retVal; +} + void GPURecoWorkflowSpec::run(ProcessingContext& pc) { constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR; @@ -627,14 +647,9 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) // ------------------------------ Prepare stage for double-pipeline before normal output preparation ------------------------------ - // unsigned int threadIndex = pc.services().get().threadIndex; - unsigned int threadIndex = mNextThreadIndex; - if (mConfig->configProcessing.doublePipeline) { - mNextThreadIndex = (mNextThreadIndex + 1) % 2; - } - + std::unique_ptr pipelineContext; if (mSpecConfig.enableDoublePipeline) { - if (handlePipeline(pc, ptrs, tpcZSmeta, tpcZS)) { + if (handlePipeline(pc, ptrs, tpcZSmeta, tpcZS, pipelineContext)) { return; } } @@ -743,21 +758,27 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) } int retVal = 0; - if (mConfParam->dump < 2) { - retVal = mGPUReco->RunTracking(&ptrs, &outputRegions, threadIndex); - if (retVal != 0) { - debugTFDump = true; + if (mSpecConfig.enableDoublePipeline) { + if (!pipelineContext->jobSubmitted) { + enqueuePipelinedJob(&ptrs, &outputRegions, pipelineContext.get()); } - - if (retVal == 0 && mSpecConfig.runITSTracking) { - retVal = runITSTracking(pc); + std::unique_lock lk(pipelineContext->jobFinishedMutex); + pipelineContext->jobFinishedNotify.wait(lk, [context = pipelineContext.get()]() { return context->jobFinished; }); + retVal = pipelineContext->jobReturnValue; + } else { + // unsigned int threadIndex = pc.services().get().threadIndex; + unsigned int threadIndex = mNextThreadIndex; + if (mConfig->configProcessing.doublePipeline) { + mNextThreadIndex = (mNextThreadIndex + 1) % 2; } + + retVal = runMain(&pc, &ptrs, &outputRegions, threadIndex); + } + if (retVal != 0) { + debugTFDump = true; } o2::utils::DebugStreamer::instance()->flush(); // flushing debug output to file - cleanOldCalibsTPCPtrs(); // setting TPC calibration objects - // if (!mTrackingCAO2Interface->getConfig().configInterface.outputToExternalBuffers) // TODO: Why was this needed for double-pipeline? - mGPUReco->Clear(false, threadIndex); // clean non-output memory used by GPU Reconstruction if (debugTFDump && mNDebugDumps < mConfParam->dumpBadTFs) { mNDebugDumps++; @@ -1183,7 +1204,7 @@ Outputs GPURecoWorkflowSpec::outputs() void GPURecoWorkflowSpec::deinitialize() { - TerminateReceiveThread(); + TerminateThreads(); mQA.reset(nullptr); mDisplayFrontend.reset(nullptr); mGPUReco.reset(nullptr); From 909ff1be16871a582a69c98186b617eb86029ca2 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 24 Sep 2023 13:31:14 +0200 Subject: [PATCH 111/324] GPU: Combine consecutive calib updates if not applied meanwhile --- GPU/GPUTracking/CMakeLists.txt | 2 +- .../DataTypes/GPUNewCalibValues.cxx | 27 +++++++++++++++++++ GPU/GPUTracking/DataTypes/GPUNewCalibValues.h | 2 ++ GPU/GPUTracking/Global/GPUChainTracking.cxx | 20 +++++++++++--- 4 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 GPU/GPUTracking/DataTypes/GPUNewCalibValues.cxx diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index c01aa66519903..ac150fc19b9d1 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -89,6 +89,7 @@ set(HDRS_CINT_O2_ADDITIONAL DataTypes/GPUSettings.h Definitions/GPUSettingsList. set(SRCS_NO_CINT DataTypes/GPUMemorySizeScalers.cxx + DataTypes/GPUNewCalibValues.cxx Base/GPUReconstruction.cxx Base/GPUReconstructionCPU.cxx Base/GPUProcessor.cxx @@ -157,7 +158,6 @@ set(HDRS_INSTALL DataTypes/GPUO2DataTypes.h DataTypes/GPUHostDataTypes.h DataTypes/GPUdEdxInfo.h - DataTypes/GPUNewCalibValues.h DataTypes/GPUTRDInterfaceO2Track.h Base/GPUParam.inc DataCompression/TPCClusterDecompressor.inc diff --git a/GPU/GPUTracking/DataTypes/GPUNewCalibValues.cxx b/GPU/GPUTracking/DataTypes/GPUNewCalibValues.cxx new file mode 100644 index 0000000000000..f443809d15ef5 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUNewCalibValues.cxx @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUNewCalibValues.cxx +/// \author David Rohr + +#include "GPUNewCalibValues.h" + +using namespace GPUCA_NAMESPACE::gpu; + +void GPUNewCalibValues::updateFrom(const GPUNewCalibValues* from) +{ + if (from->newSolenoidField) { + solenoidField = from->newSolenoidField; + } + if (from->newContinuousMaxTimeBin) { + continuousMaxTimeBin = from->continuousMaxTimeBin; + } +} diff --git a/GPU/GPUTracking/DataTypes/GPUNewCalibValues.h b/GPU/GPUTracking/DataTypes/GPUNewCalibValues.h index 3e1280dec81bf..5c5a770f81be3 100644 --- a/GPU/GPUTracking/DataTypes/GPUNewCalibValues.h +++ b/GPU/GPUTracking/DataTypes/GPUNewCalibValues.h @@ -27,6 +27,8 @@ struct GPUNewCalibValues { bool newContinuousMaxTimeBin = false; float solenoidField = 0.f; unsigned int continuousMaxTimeBin = 0; + + void updateFrom(const GPUNewCalibValues* from); }; } // namespace gpu diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 78fa1370bac7a..1d30f4d8baa01 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -613,7 +613,7 @@ void GPUChainTracking::DoQueuedUpdates(int stream) const GPUSettingsProcessing* p = nullptr; std::lock_guard lk(mMutexUpdateCalib); if (mUpdateNewCalibObjects) { - void** pSrc = (void**)mNewCalibObjects.get(); + void* const* pSrc = (void* const*)mNewCalibObjects.get(); void** pDst = (void**)&processors()->calibObjects; for (unsigned int i = 0; i < sizeof(processors()->calibObjects) / sizeof(void*); i++) { if (pSrc[i]) { @@ -968,7 +968,21 @@ void GPUChainTracking::SetDefaultInternalO2Propagator(bool useGPUField) void GPUChainTracking::SetUpdateCalibObjects(const GPUCalibObjectsConst& obj, const GPUNewCalibValues& vals) { std::lock_guard lk(mMutexUpdateCalib); - mNewCalibObjects.reset(new GPUCalibObjectsConst(obj)); - mNewCalibValues.reset(new GPUNewCalibValues(vals)); + if (mNewCalibObjects) { + void* const* pSrc = (void* const*)&vals; + void** pDst = (void**)mNewCalibObjects.get(); + for (unsigned int i = 0; i < sizeof(*mNewCalibObjects) / sizeof(void*); i++) { + if (pSrc[i]) { + pDst[i] = pSrc[i]; + } + } + } else { + mNewCalibObjects.reset(new GPUCalibObjectsConst(obj)); + } + if (mNewCalibValues) { + mNewCalibValues->updateFrom(&vals); + } else { + mNewCalibValues.reset(new GPUNewCalibValues(vals)); + } mUpdateNewCalibObjects = true; } From a08adda81d5c10ca2fd43d66b8c495d8294c4698 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 24 Sep 2023 14:36:18 +0200 Subject: [PATCH 112/324] GPU TPC: Cache TPC triggers internally for some time, and output them only when outputting clusters, allowing for late receival of outputRegions in case of multi-threaded pipeline --- .../Global/GPUChainTrackingClusterizer.cxx | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index 3c193d21a65c6..8ed2b0d74d2f8 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -530,15 +530,7 @@ int GPUChainTracking::RunTPCClusterizer_prepare(bool restorePointers) processors()->tpcClusterer[iSlice].SetNMaxDigits(nDigits, mCFContext->nPagesFragmentMax, nDigits, 0); } } - if (GetProcessingSettings().param.tpcTriggerHandling) { - GPUOutputControl* triggerOutput = mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTriggerWords)]; - if (triggerOutput && triggerOutput->allocator) { - GPUInfo("Storing %lu trigger words", mTriggerBuffer->triggers.size()); - auto* outputBuffer = (decltype(mTriggerBuffer->triggers)::value_type*)triggerOutput->allocator(mTriggerBuffer->triggers.size() * sizeof(decltype(mTriggerBuffer->triggers)::value_type)); - std::copy(mTriggerBuffer->triggers.begin(), mTriggerBuffer->triggers.end(), outputBuffer); - } - mTriggerBuffer->triggers.clear(); - } + if (mIOPtrs.tpcZS) { GPUInfo("Event has %u 8kb TPC ZS pages (version %d), %lld digits", mCFContext->nPagesTotal, mCFContext->zsVersion, (long long int)mRec->MemoryScalers()->nTPCdigits); } else { @@ -935,6 +927,16 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) } } + if (GetProcessingSettings().param.tpcTriggerHandling) { + GPUOutputControl* triggerOutput = mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTriggerWords)]; + if (triggerOutput && triggerOutput->allocator) { + GPUInfo("Storing %lu trigger words", mTriggerBuffer->triggers.size()); + auto* outputBuffer = (decltype(mTriggerBuffer->triggers)::value_type*)triggerOutput->allocator(mTriggerBuffer->triggers.size() * sizeof(decltype(mTriggerBuffer->triggers)::value_type)); + std::copy(mTriggerBuffer->triggers.begin(), mTriggerBuffer->triggers.end(), outputBuffer); + } + mTriggerBuffer->triggers.clear(); + } + ClusterNativeAccess::ConstMCLabelContainerView* mcLabelsConstView = nullptr; if (propagateMCLabels) { // TODO: write to buffer directly From 966b5fbd5f32cd6ba95ef6c005bfb3d45201b85c Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 24 Sep 2023 15:14:34 +0200 Subject: [PATCH 113/324] GPU: Add optional callback to wait for update of inputs (and outputs) before clusterization output --- GPU/GPUTracking/Global/GPUChainTracking.h | 3 +++ GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index 98a6ab9421649..c575c8ed5eb2f 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -20,6 +20,7 @@ #include "GPUDataTypes.h" #include #include +#include #include #include #include @@ -192,6 +193,7 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega void SetDefaultInternalO2Propagator(bool useGPUField); void LoadClusterErrors(); void SetSubOutputControl(int i, GPUOutputControl* v) { mSubOutputControls[i] = v; } + void SetFinalInputCallback(std::function v) { mWaitForFinalInputs = v; } const GPUSettingsDisplay* mConfigDisplay = nullptr; // Abstract pointer to Standalone Display Configuration Structure const GPUSettingsQA* mConfigQA = nullptr; // Abstract pointer to Standalone QA Configuration Structure @@ -310,6 +312,7 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega std::mutex mMutexUpdateCalib; std::unique_ptr mPipelineFinalizationCtx; GPUChainTrackingFinalContext* mPipelineNotifyCtx = nullptr; + std::function mWaitForFinalInputs; int HelperReadEvent(int iSlice, int threadId, GPUReconstructionHelpers::helperParam* par); int HelperOutput(int iSlice, int threadId, GPUReconstructionHelpers::helperParam* par); diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index 8ed2b0d74d2f8..f7eb5e09848e6 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -632,6 +632,9 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeBuffer); } if (buildNativeHost && !(buildNativeGPU && GetProcessingSettings().delayedOutput)) { + if (mWaitForFinalInputs) { + GPUFatal("Cannot use waitForFinalInput callback without delayed output"); + } AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeOutput, mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clustersNative)]); } @@ -927,6 +930,10 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) } } + if (mWaitForFinalInputs) { + mWaitForFinalInputs(); + } + if (GetProcessingSettings().param.tpcTriggerHandling) { GPUOutputControl* triggerOutput = mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTriggerWords)]; if (triggerOutput && triggerOutput->allocator) { From 64e93d4f61b00f8ca66a1d343025028832e67f8b Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 24 Sep 2023 17:49:13 +0200 Subject: [PATCH 114/324] GPU: Finalize double-pipeline processing earlier, to prevent deadlock when waiting for late inputs --- GPU/GPUTracking/Base/GPUReconstruction.cxx | 6 ++++-- .../Global/GPUChainTrackingClusterizer.cxx | 16 +++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/GPU/GPUTracking/Base/GPUReconstruction.cxx b/GPU/GPUTracking/Base/GPUReconstruction.cxx index 8dafe36054794..35c03916feb1b 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.cxx +++ b/GPU/GPUTracking/Base/GPUReconstruction.cxx @@ -972,8 +972,10 @@ void GPUReconstruction::RunPipelineWorker() } else { q->retVal = q->chain->RunChain(); } - std::lock_guard lk(q->m); - q->done = true; + { + std::lock_guard lk(q->m); + q->done = true; + } q->c.notify_one(); } if (mProcessingSettings.debugLevel >= 3) { diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index f7eb5e09848e6..36461025c526d 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -930,6 +930,15 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) } } + if (mPipelineNotifyCtx) { + SynchronizeStream(mRec->NStreams() - 2); // Must finish before updating ioPtrs in (global) constant memory + { + std::lock_guard lock(mPipelineNotifyCtx->mutex); + mPipelineNotifyCtx->ready = true; + } + mPipelineNotifyCtx->cond.notify_one(); + } + if (mWaitForFinalInputs) { mWaitForFinalInputs(); } @@ -986,13 +995,6 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) mIOPtrs.clustersNative = tmpNative; } - if (mPipelineNotifyCtx) { - SynchronizeStream(mRec->NStreams() - 2); // Must finish before updating ioPtrs in (global) constant memory - std::lock_guard lock(mPipelineNotifyCtx->mutex); - mPipelineNotifyCtx->ready = true; - mPipelineNotifyCtx->cond.notify_one(); - } - if (buildNativeGPU) { processorsShadow()->ioPtrs.clustersNative = mInputsShadow->mPclusterNativeAccess; WriteToConstantMemory(RecoStep::TPCClusterFinding, (char*)&processors()->ioPtrs - (char*)processors(), &processorsShadow()->ioPtrs, sizeof(processorsShadow()->ioPtrs), 0); From b716c75c8e2009d46febb6a0f393ac640238aa8e Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 24 Sep 2023 19:45:33 +0200 Subject: [PATCH 115/324] dpl-workflow: do not event display on MI100 nodes in online operation --- prodtests/full-system-test/dpl-workflow.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 6c286ff7d1d3d..31f3f6785e87f 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -545,7 +545,7 @@ workflow_has_parameters CALIB CALIB_LOCAL_INTEGRATED_AGGREGATOR && { source ${CA # RS this is a temporary setting : ${ED_TRACKS:=$TRACK_SOURCES} : ${ED_CLUSTERS:=$TRACK_SOURCES} -workflow_has_parameter EVENT_DISPLAY && [[ $NUMAID == 0 ]] && [[ ! -z "$ED_TRACKS" ]] && [[ ! -z "$ED_CLUSTERS" ]] && add_W o2-eve-export-workflow "--display-tracks $ED_TRACKS --display-clusters $ED_CLUSTERS --skipOnEmptyInput $DISABLE_ROOT_INPUT --number-of_tracks 50000 $EVE_CONFIG $DISABLE_MC" "$ITSMFT_STROBES" +workflow_has_parameter EVENT_DISPLAY && [[ $NUMAID == 0 ]] && [[ ! -z "$ED_TRACKS" ]] && [[ ! -z "$ED_CLUSTERS" ]] && [[ $EPNSYNCMODE == 0 || ${EPN_NODE_MI100:-0} == 0 ]] && add_W o2-eve-export-workflow "--display-tracks $ED_TRACKS --display-clusters $ED_CLUSTERS --skipOnEmptyInput $DISABLE_ROOT_INPUT --number-of_tracks 50000 $EVE_CONFIG $DISABLE_MC" "$ITSMFT_STROBES" workflow_has_parameter GPU_DISPLAY && [[ $NUMAID == 0 ]] && add_W o2-gpu-display "${ED_TRACKS+--display-tracks} $ED_TRACKS ${ED_CLUSTERS+--display-clusters} $ED_CLUSTERS" From f665780355077071ac9ada67b806281b68a89c68 Mon Sep 17 00:00:00 2001 From: shahoian Date: Sun, 24 Sep 2023 23:29:04 +0200 Subject: [PATCH 116/324] Revert TOF CTF precompressed timeTDCInc to uint16_t To be compatible with existing dictionary --- DataFormats/Detectors/TOF/include/DataFormatsTOF/CTF.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CTF.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CTF.h index a31ece315d408..881f87ff88971 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/CTF.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/CTF.h @@ -64,7 +64,7 @@ struct CompressedInfos { // Hit data std::vector timeFrameInc; /// time increment with respect of previous digit in TimeFrame units - std::vector timeTDCInc; /// time increment with respect of previous digit in TDC channel (about 24.4 ps) within timeframe + std::vector timeTDCInc; /// time increment with respect of previous digit in TDC channel (about 24.4 ps) within timeframe std::vector stripID; /// increment of stripID wrt that of prev. strip std::vector chanInStrip; /// channel in strip 0-95 (ordered in time) std::vector tot; /// Time-Over-Threshold in TOF channel (about 48.8 ps) From 199a1db35e9a9d6f3f4186426cf1b67d20ceee35 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 25 Sep 2023 00:16:21 +0200 Subject: [PATCH 117/324] DPL: Rename reworkEnv to reworkTimeslicePlaceholder and apply it also to channel-config --- Framework/Core/src/DDSConfigHelpers.cxx | 2 +- Framework/Core/src/DeviceSpecHelpers.cxx | 6 +++--- Framework/Core/src/DeviceSpecHelpers.h | 2 +- Framework/Core/src/runDataProcessing.cxx | 2 +- Framework/Core/test/test_DeviceSpecHelpers.cxx | 14 +++++++------- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Framework/Core/src/DDSConfigHelpers.cxx b/Framework/Core/src/DDSConfigHelpers.cxx index 272a5cf36ea03..e56afe34bc511 100644 --- a/Framework/Core/src/DDSConfigHelpers.cxx +++ b/Framework/Core/src/DDSConfigHelpers.cxx @@ -202,7 +202,7 @@ void DDSConfigHelpers::dumpDeviceSpec2DDS(std::ostream& out, << R"()"; out << fmt::format("cat ${{DDS_LOCATION}}/dpl_json{}.asset | ", workflowSuffix); for (auto ei : execution.environ) { - out << DeviceSpecHelpers::reworkEnv(ei, spec) << " "; + out << DeviceSpecHelpers::reworkTimeslicePlaceholder(ei, spec) << " "; } std::string accumulatedChannelPrefix; char* s = strdup(execution.args[0]); diff --git a/Framework/Core/src/DeviceSpecHelpers.cxx b/Framework/Core/src/DeviceSpecHelpers.cxx index 2041dc5a38a09..f11f60171e451 100644 --- a/Framework/Core/src/DeviceSpecHelpers.cxx +++ b/Framework/Core/src/DeviceSpecHelpers.cxx @@ -1482,8 +1482,8 @@ void DeviceSpecHelpers::prepareArguments(bool defaultQuiet, bool defaultStopped, haveSessionArg = haveSessionArg || varmap.count("session") != 0; useDefaultWS = useDefaultWS && ((varmap.count("driver-client-backend") == 0) || varmap["driver-client-backend"].as() == "ws://"); - auto processRawChannelConfig = [&tmpArgs](const std::string& conf) { - std::stringstream ss(conf); + auto processRawChannelConfig = [&tmpArgs, &spec](const std::string& conf) { + std::stringstream ss(reworkTimeslicePlaceholder(conf, spec)); std::string token; while (std::getline(ss, token, ';')) { // split to tokens, trim spaces and add each non-empty one with channel-config options token.erase(token.begin(), std::find_if(token.begin(), token.end(), [](int ch) { return !std::isspace(ch); })); @@ -1667,7 +1667,7 @@ bool DeviceSpecHelpers::hasLabel(DeviceSpec const& spec, char const* label) return std::find_if(spec.labels.begin(), spec.labels.end(), sameLabel) != spec.labels.end(); } -std::string DeviceSpecHelpers::reworkEnv(std::string const& str, DeviceSpec const& spec) +std::string DeviceSpecHelpers::reworkTimeslicePlaceholder(std::string const& str, DeviceSpec const& spec) { // find all the possible timeslice variables, extract N and replace // the variable with the value of spec.inputTimesliceId + N. diff --git a/Framework/Core/src/DeviceSpecHelpers.h b/Framework/Core/src/DeviceSpecHelpers.h index 5a036db50618c..1fb1866ae2dc3 100644 --- a/Framework/Core/src/DeviceSpecHelpers.h +++ b/Framework/Core/src/DeviceSpecHelpers.h @@ -131,7 +131,7 @@ struct DeviceSpecHelpers { /// Rework the environment string /// * Substitute {timeslice} with the actual value of the timeslice. - static std::string reworkEnv(std::string const& str, DeviceSpec const& spec); + static std::string reworkTimeslicePlaceholder(std::string const& str, DeviceSpec const& spec); /// This takes the list of preprocessed edges of a graph /// and creates Devices and Channels which are related diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index 9f92f85038057..1d9619112d08b 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -681,7 +681,7 @@ void spawnDevice(uv_loop_t* loop, } } for (auto& env : execution.environ) { - putenv(strdup(DeviceSpecHelpers::reworkEnv(env, spec).data())); + putenv(strdup(DeviceSpecHelpers::reworkTimeslicePlaceholder(env, spec).data())); } execvp(execution.args[0], execution.args.data()); } diff --git a/Framework/Core/test/test_DeviceSpecHelpers.cxx b/Framework/Core/test/test_DeviceSpecHelpers.cxx index 982536879b18c..762c2df6f82aa 100644 --- a/Framework/Core/test/test_DeviceSpecHelpers.cxx +++ b/Framework/Core/test/test_DeviceSpecHelpers.cxx @@ -356,19 +356,19 @@ TEST_CASE("CheckReworkingEnv") { DeviceSpec spec{.inputTimesliceId = 1}; std::string env = "FOO={timeslice0}"; - REQUIRE(DeviceSpecHelpers::reworkEnv(env, spec) == "FOO=1"); + REQUIRE(DeviceSpecHelpers::reworkTimeslicePlaceholder(env, spec) == "FOO=1"); env = "FOO={timeslice0} BAR={timeslice4}"; - REQUIRE(DeviceSpecHelpers::reworkEnv(env, spec) == "FOO=1 BAR=5"); + REQUIRE(DeviceSpecHelpers::reworkTimeslicePlaceholder(env, spec) == "FOO=1 BAR=5"); env = "FOO={timeslice0} BAR={timeslice4} BAZ={timeslice5}"; - REQUIRE(DeviceSpecHelpers::reworkEnv(env, spec) == "FOO=1 BAR=5 BAZ=6"); + REQUIRE(DeviceSpecHelpers::reworkTimeslicePlaceholder(env, spec) == "FOO=1 BAR=5 BAZ=6"); env = ""; - REQUIRE(DeviceSpecHelpers::reworkEnv(env, spec) == ""); + REQUIRE(DeviceSpecHelpers::reworkTimeslicePlaceholder(env, spec) == ""); env = "Plottigat"; - REQUIRE(DeviceSpecHelpers::reworkEnv(env, spec) == "Plottigat"); + REQUIRE(DeviceSpecHelpers::reworkTimeslicePlaceholder(env, spec) == "Plottigat"); env = "{timeslice}"; - REQUIRE(DeviceSpecHelpers::reworkEnv(env, spec) == "{timeslice}"); + REQUIRE(DeviceSpecHelpers::reworkTimeslicePlaceholder(env, spec) == "{timeslice}"); env = "{timeslicepluto"; - REQUIRE(DeviceSpecHelpers::reworkEnv(env, spec) == "{timeslicepluto"); + REQUIRE(DeviceSpecHelpers::reworkTimeslicePlaceholder(env, spec) == "{timeslicepluto"); } } // namespace o2::framework From c4d7bbdbdcb0ee73364eccdf5c544c9a223f3e22 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 25 Sep 2023 00:16:44 +0200 Subject: [PATCH 118/324] GPU: Support standalone multi-threading with more than 1 GPU per workflow --- GPU/Workflow/src/GPUWorkflowSpec.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index d7d203507d55e..42281d932141a 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -1022,7 +1022,7 @@ Options GPURecoWorkflowSpec::options() char* o2jobid = getenv("O2JOBID"); char* numaid = getenv("NUMAID"); int chanid = o2jobid ? atoi(o2jobid) : (numaid ? atoi(numaid) : 0); - std::string chan = std::string("name=gpu-prepare-channel,type=") + (send ? "push" : "pull") + ",method=" + (send ? "connect" : "bind") + ",address=ipc://@gpu-prepare-channel-" + std::to_string(chanid) + ",transport=shmem,rateLogging=0"; + std::string chan = std::string("name=gpu-prepare-channel,type=") + (send ? "push" : "pull") + ",method=" + (send ? "connect" : "bind") + ",address=ipc://@gpu-prepare-channel-" + std::to_string(chanid) + "-{timeslice0},transport=shmem,rateLogging=0"; opts.emplace_back(o2::framework::ConfigParamSpec{"channel-config", o2::framework::VariantType::String, chan, {"Out-of-band channel config"}}); } if (mSpecConfig.enableDoublePipeline == 2) { From c0a075ed3907bebbb00e4279e56ff106887003ca Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 24 Sep 2023 19:38:50 +0200 Subject: [PATCH 119/324] GPU Interface: Support a callback for providing final set of inputs and output buffer late, to be propagated to GPUReconstruciton only after running TPC Clusterization --- GPU/GPUTracking/Interface/GPUO2Interface.cxx | 45 +++++++++++++++---- GPU/GPUTracking/Interface/GPUO2Interface.h | 3 +- .../Interface/GPUO2InterfaceConfiguration.h | 5 +++ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index 7d353f86577bd..46c12d6b5219d 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -163,23 +163,50 @@ void GPUO2Interface::DumpSettings() mCtx[0].mRec->DumpSettings(); } -int GPUO2Interface::RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs, unsigned int iThread) +int GPUO2Interface::RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs, unsigned int iThread, GPUInterfaceInputUpdate* inputUpdateCallback) { if (mNContexts <= iThread) { return (1); } mCtx[iThread].mChain->mIOPtrs = *data; - if (mConfig->configInterface.outputToExternalBuffers) { - for (unsigned int i = 0; i < mCtx[iThread].mOutputRegions->count(); i++) { - if (outputs->asArray()[i].allocator) { - mCtx[iThread].mOutputRegions->asArray()[i].set(outputs->asArray()[i].allocator); - } else if (outputs->asArray()[i].ptrBase) { - mCtx[iThread].mOutputRegions->asArray()[i].set(outputs->asArray()[i].ptrBase, outputs->asArray()[i].size); - } else { - mCtx[iThread].mOutputRegions->asArray()[i].reset(); + + auto setOutputs = [this, iThread](GPUInterfaceOutputs* outputs) { + if (mConfig->configInterface.outputToExternalBuffers) { + for (unsigned int i = 0; i < mCtx[iThread].mOutputRegions->count(); i++) { + if (outputs->asArray()[i].allocator) { + mCtx[iThread].mOutputRegions->asArray()[i].set(outputs->asArray()[i].allocator); + } else if (outputs->asArray()[i].ptrBase) { + mCtx[iThread].mOutputRegions->asArray()[i].set(outputs->asArray()[i].ptrBase, outputs->asArray()[i].size); + } else { + mCtx[iThread].mOutputRegions->asArray()[i].reset(); + } } } + }; + + auto inputWaitCallback = [this, iThread, inputUpdateCallback, &data, &outputs, &setOutputs]() { + GPUTrackingInOutPointers* updatedData; + GPUInterfaceOutputs* updatedOutputs; + if (inputUpdateCallback->callback) { + inputUpdateCallback->callback(updatedData, updatedOutputs); + mCtx[iThread].mChain->mIOPtrs = *updatedData; + outputs = updatedOutputs; + data = updatedData; + setOutputs(outputs); + } + if (inputUpdateCallback->notifyCallback) { + inputUpdateCallback->notifyCallback(); + } + }; + + if (inputUpdateCallback) { + mCtx[iThread].mChain->SetFinalInputCallback(inputWaitCallback); + } else { + mCtx[iThread].mChain->SetFinalInputCallback(nullptr); + } + if (!inputUpdateCallback || !inputUpdateCallback->callback) { + setOutputs(outputs); } int retVal = mCtx[iThread].mRec->RunChains(); diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.h b/GPU/GPUTracking/Interface/GPUO2Interface.h index fe3c6d4c11586..d227b8c7a92e6 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.h +++ b/GPU/GPUTracking/Interface/GPUO2Interface.h @@ -54,6 +54,7 @@ class GPUChainTracking; class GPUChainITS; struct GPUO2InterfaceConfiguration; struct GPUInterfaceOutputs; +struct GPUInterfaceInputUpdate; struct GPUTrackingOutputs; struct GPUConstantMem; struct GPUNewCalibValues; @@ -70,7 +71,7 @@ class GPUO2Interface int Initialize(const GPUO2InterfaceConfiguration& config); void Deinitialize(); - int RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs = nullptr, unsigned int iThread = 0); + int RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs = nullptr, unsigned int iThread = 0, GPUInterfaceInputUpdate* inputUpdateCallback = nullptr); void Clear(bool clearOutputs, unsigned int iThread = 0); void DumpEvent(int nEvent, GPUTrackingInOutPointers* data); void DumpSettings(); diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h index 981ac4797355f..2d062c1422c40 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h @@ -66,6 +66,11 @@ struct GPUInterfaceOutputs : public GPUTrackingOutputs { GPUInterfaceQAOutputs qa; }; +struct GPUInterfaceInputUpdate { + std::function callback; // Callback which provides final data ptrs / outputRegions after Clusterization stage + std::function notifyCallback; // Callback called to notify that Clusterization state has finished without update +}; + // Full configuration structure with all available settings of GPU... struct GPUO2InterfaceConfiguration { GPUO2InterfaceConfiguration() = default; From b3e4aae9af3de3f999d58ff86a16cb0423756cf4 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 24 Sep 2023 21:03:29 +0200 Subject: [PATCH 120/324] GPU Interface: meanwhile we should be able to dump events in double-pipeline mode --- GPU/GPUTracking/Interface/GPUO2Interface.cxx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index 46c12d6b5219d..f2e91b633c7bf 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -135,9 +135,6 @@ void GPUO2Interface::Deinitialize() void GPUO2Interface::DumpEvent(int nEvent, GPUTrackingInOutPointers* data) { - if (mConfig->configProcessing.doublePipeline) { - throw std::runtime_error("Cannot dump events in double pipeline mode"); - } mCtx[0].mChain->ClearIOPointers(); mCtx[0].mChain->mIOPtrs = *data; char fname[1024]; @@ -156,9 +153,6 @@ void GPUO2Interface::DumpEvent(int nEvent, GPUTrackingInOutPointers* data) void GPUO2Interface::DumpSettings() { - if (mConfig->configProcessing.doublePipeline) { - throw std::runtime_error("Cannot dump events in double pipeline mode"); - } mCtx[0].mChain->DoQueuedUpdates(-1); mCtx[0].mRec->DumpSettings(); } From abea107746040a0842348899806cbc75caad16c6 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 24 Sep 2023 21:07:28 +0200 Subject: [PATCH 121/324] GPU Benchmark: Improve error message, since I had forgotten how it works myself... --- GPU/GPUTracking/Benchmark/standalone.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUTracking/Benchmark/standalone.cxx b/GPU/GPUTracking/Benchmark/standalone.cxx index 6bff74b1d4705..ad0ac17b83565 100644 --- a/GPU/GPUTracking/Benchmark/standalone.cxx +++ b/GPU/GPUTracking/Benchmark/standalone.cxx @@ -188,7 +188,7 @@ int ReadConfiguration(int argc, char** argv) return 1; } if (configStandalone.proc.doublePipeline && (configStandalone.runs < 4 || !configStandalone.outputcontrolmem)) { - printf("Double pipeline mode needs at least 3 runs per event and external output\n"); + printf("Double pipeline mode needs at least 3 runs per event and external output. To cycle though multiple events, use --preloadEvents and --runs n for n iterations round-robin\n"); return 1; } if (configStandalone.TF.bunchSim && configStandalone.TF.nMerge) { From e1bc6910ba25398b247677c4031a3b80d410cd1b Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 24 Sep 2023 21:13:28 +0200 Subject: [PATCH 122/324] GPU: Relaxed delayedOutput constraints --- GPU/GPUTracking/Base/GPUReconstruction.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUTracking/Base/GPUReconstruction.cxx b/GPU/GPUTracking/Base/GPUReconstruction.cxx index 35c03916feb1b..676ab0f6cf004 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.cxx +++ b/GPU/GPUTracking/Base/GPUReconstruction.cxx @@ -279,7 +279,7 @@ int GPUReconstruction::InitPhaseBeforeDevice() if (!(mRecoStepsGPU & RecoStep::TPCMerging) || !param().rec.tpc.mergerReadFromTrackerDirectly) { mProcessingSettings.fullMergerOnGPU = false; } - if (mProcessingSettings.debugLevel || !mProcessingSettings.fullMergerOnGPU) { + if (mProcessingSettings.debugLevel > 3 || !mProcessingSettings.fullMergerOnGPU) { mProcessingSettings.delayedOutput = false; } if (!mProcessingSettings.fullMergerOnGPU && GetRecoStepsGPU() & RecoStep::TPCMerging) { From db6adf3d7b8cd2efcee0e67472284777be7bb9d6 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 24 Sep 2023 15:16:27 +0200 Subject: [PATCH 123/324] GPU Workflow: start processing early asynchronously if possible, update inputs and outputcallback when DPL context of TF is available, wait for end of async processing, and ship data out via DPL --- .../include/GPUWorkflow/GPUWorkflowSpec.h | 6 +- GPU/Workflow/src/GPUWorkflowInternal.h | 17 ++++- GPU/Workflow/src/GPUWorkflowPipeline.cxx | 74 +++++++++++++++---- GPU/Workflow/src/GPUWorkflowSpec.cxx | 17 +++-- 4 files changed, 89 insertions(+), 25 deletions(-) diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index 0098a3c456193..d77a2c63462eb 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -85,6 +85,7 @@ class GPUO2InterfaceQA; struct GPUTrackingInOutPointers; struct GPUTrackingInOutZS; struct GPUInterfaceOutputs; +struct GPUInterfaceInputUpdate; namespace gpurecoworkflow_internals { struct GPURecoWorkflowSpec_TPCZSBuffers; @@ -167,8 +168,9 @@ class GPURecoWorkflowSpec : public o2::framework::Task void TerminateThreads(); void handlePipelineEndOfStream(o2::framework::EndOfStreamContext& ec); void initPipeline(o2::framework::InitContext& ic); - void enqueuePipelinedJob(GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, gpurecoworkflow_internals::GPURecoWorkflow_QueueObject* context); - int runMain(o2::framework::ProcessingContext* pc, GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, int threadIndex); + void enqueuePipelinedJob(GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, gpurecoworkflow_internals::GPURecoWorkflow_QueueObject* context, bool inputFinal); + void finalizeInputPipelinedJob(GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, gpurecoworkflow_internals::GPURecoWorkflow_QueueObject* context); + int runMain(o2::framework::ProcessingContext* pc, GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, int threadIndex = 0, GPUInterfaceInputUpdate* inputUpdateCallback = nullptr); CompletionPolicyData* mPolicyData; std::function mPolicyOrder; diff --git a/GPU/Workflow/src/GPUWorkflowInternal.h b/GPU/Workflow/src/GPUWorkflowInternal.h index ac24c0b9e99b4..a6e94008c20ee 100644 --- a/GPU/Workflow/src/GPUWorkflowInternal.h +++ b/GPU/Workflow/src/GPUWorkflowInternal.h @@ -41,13 +41,19 @@ struct GPURecoWorkflow_QueueObject { GPUTrackingInOutPointers ptrs; o2::framework::DataProcessingHeader::StartTime timeSliceId; + unsigned long mTFId; + bool jobSubmitted = false; bool jobFinished = false; int jobReturnValue = 0; std::mutex jobFinishedMutex; std::condition_variable jobFinishedNotify; - GPUTrackingInOutPointers* jobPtrs; - GPUInterfaceOutputs* jobOutputRegions; + bool jobInputFinal = false; + std::mutex jobInputFinalMutex; + std::condition_variable jobInputFinalNotify; + GPUTrackingInOutPointers* jobPtrs = nullptr; + GPUInterfaceOutputs* jobOutputRegions = nullptr; + std::unique_ptr jobInputUpdateCallback = nullptr; }; struct GPURecoWorkflowSpec_PipelineInternals { @@ -75,6 +81,13 @@ struct GPURecoWorkflowSpec_PipelineInternals { bool pipelineSenderTerminating = false; std::mutex completionPolicyMutex; std::condition_variable completionPolicyNotify; + + unsigned long mNTFReceived = 0; + + bool mayInject = true; + unsigned long mayInjectTFId = 0; + std::mutex mayInjectMutex; + std::condition_variable mayInjectCondition; }; } // namespace gpurecoworkflow_internals diff --git a/GPU/Workflow/src/GPUWorkflowPipeline.cxx b/GPU/Workflow/src/GPUWorkflowPipeline.cxx index 6ed80f4cfc9bd..3803fe2c96744 100644 --- a/GPU/Workflow/src/GPUWorkflowPipeline.cxx +++ b/GPU/Workflow/src/GPUWorkflowPipeline.cxx @@ -91,7 +91,7 @@ void GPURecoWorkflowSpec::RunWorkerThread(int id) context = workerContext.inputQueue.front(); workerContext.inputQueue.pop(); } - context->jobReturnValue = runMain(nullptr, context->jobPtrs, context->jobOutputRegions, id); + context->jobReturnValue = runMain(nullptr, context->jobPtrs, context->jobOutputRegions, id, context->jobInputUpdateCallback.get()); { std::lock_guard lk(context->jobFinishedMutex); context->jobFinished = true; @@ -100,11 +100,37 @@ void GPURecoWorkflowSpec::RunWorkerThread(int id) } } -void GPURecoWorkflowSpec::enqueuePipelinedJob(GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, GPURecoWorkflow_QueueObject* context) +void GPURecoWorkflowSpec::enqueuePipelinedJob(GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, GPURecoWorkflow_QueueObject* context, bool inputFinal) { + { + std::unique_lock lk(mPipeline->mayInjectMutex); + mPipeline->mayInjectCondition.wait(lk, [this, context]() { return mPipeline->mayInject && mPipeline->mayInjectTFId == context->mTFId; }); + mPipeline->mayInjectTFId++; + mPipeline->mayInject = false; + } context->jobSubmitted = true; + context->jobInputFinal = inputFinal; context->jobPtrs = ptrs; context->jobOutputRegions = outputRegions; + + context->jobInputUpdateCallback = std::make_unique(); + + if (!inputFinal) { + context->jobInputUpdateCallback->callback = [context](GPUTrackingInOutPointers*& data, GPUInterfaceOutputs*& outputs) { + std::unique_lock lk(context->jobInputFinalMutex); + context->jobInputFinalNotify.wait(lk, [context]() { return context->jobInputFinal; }); + data = context->jobPtrs; + outputs = context->jobOutputRegions; + }; + } + context->jobInputUpdateCallback->notifyCallback = [this]() { + { + std::lock_guard lk(mPipeline->mayInjectMutex); + mPipeline->mayInject = true; + } + mPipeline->mayInjectCondition.notify_one(); + }; + mNextThreadIndex = (mNextThreadIndex + 1) % 2; { @@ -114,6 +140,17 @@ void GPURecoWorkflowSpec::enqueuePipelinedJob(GPUTrackingInOutPointers* ptrs, GP mPipeline->workers[mNextThreadIndex].inputQueueNotify.notify_one(); } +void GPURecoWorkflowSpec::finalizeInputPipelinedJob(GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, GPURecoWorkflow_QueueObject* context) +{ + { + std::lock_guard lk(context->jobInputFinalMutex); + context->jobPtrs = ptrs; + context->jobOutputRegions = outputRegions; + context->jobInputFinal = true; + } + context->jobInputFinalNotify.notify_one(); +} + int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS, std::unique_ptr& context) { auto* device = pc.services().get().device(); @@ -246,9 +283,9 @@ void GPURecoWorkflowSpec::RunReceiveThread() break; } - auto o = std::make_unique(); - o->timeSliceId = m->timeSliceId; - o->tfSettings = m->tfSettings; + auto context = std::make_unique(); + context->timeSliceId = m->timeSliceId; + context->tfSettings = m->tfSettings; size_t regionOffset = 0; if (m->pointersTotal) { @@ -263,21 +300,26 @@ void GPURecoWorkflowSpec::RunReceiveThread() } size_t ptrsCopied = 0; size_t* ptrBuffer = (size_t*)msg->GetData() + sizeof(pipelinePrepareMessage) / sizeof(size_t); - o->tpcZSmeta.Pointers[0][0].resize(m->pointersTotal); - o->tpcZSmeta.Sizes[0][0].resize(m->pointersTotal); + context->tpcZSmeta.Pointers[0][0].resize(m->pointersTotal); + context->tpcZSmeta.Sizes[0][0].resize(m->pointersTotal); for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - o->tpcZS.slice[i].count[j] = m->pointerCounts[i][j]; - for (unsigned int k = 0; k < o->tpcZS.slice[i].count[j]; k++) { - o->tpcZSmeta.Pointers[0][0][ptrsCopied + k] = (void*)(ptrBuffer[ptrsCopied + k] + regionOffset); - o->tpcZSmeta.Sizes[0][0][ptrsCopied + k] = ptrBuffer[m->pointersTotal + ptrsCopied + k]; + context->tpcZS.slice[i].count[j] = m->pointerCounts[i][j]; + for (unsigned int k = 0; k < context->tpcZS.slice[i].count[j]; k++) { + context->tpcZSmeta.Pointers[0][0][ptrsCopied + k] = (void*)(ptrBuffer[ptrsCopied + k] + regionOffset); + context->tpcZSmeta.Sizes[0][0][ptrsCopied + k] = ptrBuffer[m->pointersTotal + ptrsCopied + k]; } - o->tpcZS.slice[i].zsPtr[j] = o->tpcZSmeta.Pointers[0][0].data() + ptrsCopied; - o->tpcZS.slice[i].nZSPtr[j] = o->tpcZSmeta.Sizes[0][0].data() + ptrsCopied; - ptrsCopied += o->tpcZS.slice[i].count[j]; + context->tpcZS.slice[i].zsPtr[j] = context->tpcZSmeta.Pointers[0][0].data() + ptrsCopied; + context->tpcZS.slice[i].nZSPtr[j] = context->tpcZSmeta.Sizes[0][0].data() + ptrsCopied; + ptrsCopied += context->tpcZS.slice[i].count[j]; } } - o->ptrs.tpcZS = &o->tpcZS; + context->ptrs.tpcZS = &context->tpcZS; + context->ptrs.settingsTF = &context->tfSettings; + context->mTFId = mPipeline->mNTFReceived; + if (mPipeline->mNTFReceived++ >= mPipeline->workers.size()) { // Do not inject the first 2 TF, since we need a first round of calib updates from DPL before starting + enqueuePipelinedJob(&context->ptrs, nullptr, context.get(), false); + } { std::lock_guard lk(mPipeline->completionPolicyMutex); mPipeline->completionPolicyQueue.emplace(m->timeSliceId); @@ -285,7 +327,7 @@ void GPURecoWorkflowSpec::RunReceiveThread() mPipeline->completionPolicyNotify.notify_one(); { std::lock_guard lk(mPipeline->queueMutex); - mPipeline->pipelineQueue.emplace(std::move(o)); + mPipeline->pipelineQueue.emplace(std::move(context)); } mPipeline->queueNotify.notify_one(); } diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 42281d932141a..9834f81ed5266 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -147,6 +147,9 @@ void GPURecoWorkflowSpec::init(InitContext& ic) throw std::runtime_error("GPU Event Display frontend could not be created!"); } } + if (mSpecConfig.enableDoublePipeline) { + mConfig->configProcessing.doublePipeline = 1; + } mAutoSolenoidBz = mConfParam->solenoidBz == -1e6f; mAutoContinuousMaxTimeBin = mConfig->configGRP.continuousMaxTimeBin == -1; @@ -487,11 +490,11 @@ void GPURecoWorkflowSpec::processInputs(ProcessingContext& pc, D& tpcZSmeta, E& } } -int GPURecoWorkflowSpec::runMain(o2::framework::ProcessingContext* pc, GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, int threadIndex) +int GPURecoWorkflowSpec::runMain(o2::framework::ProcessingContext* pc, GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, int threadIndex, GPUInterfaceInputUpdate* inputUpdateCallback) { int retVal = 0; if (mConfParam->dump < 2) { - retVal = mGPUReco->RunTracking(ptrs, outputRegions, threadIndex); + retVal = mGPUReco->RunTracking(ptrs, outputRegions, threadIndex, inputUpdateCallback); if (retVal == 0 && mSpecConfig.runITSTracking) { retVal = runITSTracking(*pc); @@ -499,8 +502,10 @@ int GPURecoWorkflowSpec::runMain(o2::framework::ProcessingContext* pc, GPUTracki } cleanOldCalibsTPCPtrs(); // setting TPC calibration objects - // if (!mTrackingCAO2Interface->getConfig().configInterface.outputToExternalBuffers) // TODO: Why was this needed for double-pipeline? - mGPUReco->Clear(false, threadIndex); // clean non-output memory used by GPU Reconstruction + + if (!mSpecConfig.enableDoublePipeline) { // TODO: Why is this needed for double-pipeline? + mGPUReco->Clear(false, threadIndex); // clean non-output memory used by GPU Reconstruction + } return retVal; } @@ -760,7 +765,9 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) int retVal = 0; if (mSpecConfig.enableDoublePipeline) { if (!pipelineContext->jobSubmitted) { - enqueuePipelinedJob(&ptrs, &outputRegions, pipelineContext.get()); + enqueuePipelinedJob(&ptrs, &outputRegions, pipelineContext.get(), true); + } else { + finalizeInputPipelinedJob(&ptrs, &outputRegions, pipelineContext.get()); } std::unique_lock lk(pipelineContext->jobFinishedMutex); pipelineContext->jobFinishedNotify.wait(lk, [context = pipelineContext.get()]() { return context->jobFinished; }); From 0dbaaadeb62969103be1217936336217e9d3b741 Mon Sep 17 00:00:00 2001 From: lietava Date: Wed, 13 Sep 2023 11:23:14 +0200 Subject: [PATCH 124/324] dev: get lhc filling from LHC IF --- Detectors/CTP/macro/GetBunchFillingForRun.C | 41 +++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Detectors/CTP/macro/GetBunchFillingForRun.C diff --git a/Detectors/CTP/macro/GetBunchFillingForRun.C b/Detectors/CTP/macro/GetBunchFillingForRun.C new file mode 100644 index 0000000000000..82eef0eb08c54 --- /dev/null +++ b/Detectors/CTP/macro/GetBunchFillingForRun.C @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include +#endif +using namespace o2::ctp; + +void GetBunchFillingForRun(bool test = 1) +{ + if (test == 0) { + return; + } + o2::ccdb::CcdbApi api; + api.init("http://alice-ccdb.cern.ch"); // alice-ccdb.cern.ch + auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); + int runNumber = 526926; + std::string fillNumber = "8238"; + auto soreor = ccdbMgr.getRunDuration(runNumber); + uint64_t timeStamp = (soreor.second - soreor.first) / 2 + soreor.first; + std::cout << "Timestamp:" << timeStamp << std::endl; + std::string srun = std::to_string(runNumber); + map metadata; // can be empty + //metadata["runNumber"] = srun; + metadata["fillNumber"] = fillNumber; + auto lhcifdata = ccdbMgr.getSpecific("GLO/Config/GRPLHCIF", timeStamp, metadata); + auto bfilling = lhcifdata->getBunchFilling(); + std::vector bcs = bfilling.getFilledBCs(); + for(auto const& bc: bcs) { + std::cout << bc << std::endl; + } +} From f8e9bb2426c71a329b4fa082603171c6cd31363a Mon Sep 17 00:00:00 2001 From: lietava Date: Wed, 13 Sep 2023 11:23:44 +0200 Subject: [PATCH 125/324] clang --- Detectors/CTP/macro/GetBunchFillingForRun.C | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Detectors/CTP/macro/GetBunchFillingForRun.C b/Detectors/CTP/macro/GetBunchFillingForRun.C index 82eef0eb08c54..b610ac5932b9f 100644 --- a/Detectors/CTP/macro/GetBunchFillingForRun.C +++ b/Detectors/CTP/macro/GetBunchFillingForRun.C @@ -30,12 +30,12 @@ void GetBunchFillingForRun(bool test = 1) std::cout << "Timestamp:" << timeStamp << std::endl; std::string srun = std::to_string(runNumber); map metadata; // can be empty - //metadata["runNumber"] = srun; + // metadata["runNumber"] = srun; metadata["fillNumber"] = fillNumber; auto lhcifdata = ccdbMgr.getSpecific("GLO/Config/GRPLHCIF", timeStamp, metadata); - auto bfilling = lhcifdata->getBunchFilling(); + auto bfilling = lhcifdata->getBunchFilling(); std::vector bcs = bfilling.getFilledBCs(); - for(auto const& bc: bcs) { + for (auto const& bc : bcs) { std::cout << bc << std::endl; } } From 13b0b42af562a0c90517f2a09337e789bb135c8d Mon Sep 17 00:00:00 2001 From: lietava Date: Sun, 24 Sep 2023 16:12:49 +0200 Subject: [PATCH 126/324] fix: in CTPsaclers det counts are replaced by input counts needed for lumi (det counts were not used) --- .../CTP/include/DataFormatsCTP/Scalers.h | 6 ++- DataFormats/Detectors/CTP/src/RunManager.cxx | 9 ++++ DataFormats/Detectors/CTP/src/Scalers.cxx | 4 +- Detectors/CTP/macro/GetBunchFillingForRun.C | 41 ------------------- 4 files changed, 15 insertions(+), 45 deletions(-) delete mode 100644 Detectors/CTP/macro/GetBunchFillingForRun.C diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h index f71799edceac7..e230b2494a85e 100644 --- a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h @@ -67,7 +67,8 @@ struct CTPScalerRecordRaw { o2::InteractionRecord intRecord; double_t epochTime; std::vector scalers; - std::vector scalersDets; + //std::vector scalersDets; + std::vector scalersInps; void printStream(std::ostream& stream) const; ClassDefNV(CTPScalerRecordRaw, 3); }; @@ -76,7 +77,8 @@ struct CTPScalerRecordO2 { o2::InteractionRecord intRecord; double_t epochTime; std::vector scalers; - std::vector scalersDets; + //std::vector scalersDets; + std::vector scalersInps; void printStream(std::ostream& stream) const; void printFromZero(std::ostream& stream, CTPScalerRecordO2& record0) const; ClassDefNV(CTPScalerRecordO2, 3); diff --git a/DataFormats/Detectors/CTP/src/RunManager.cxx b/DataFormats/Detectors/CTP/src/RunManager.cxx index 8ed0b51bef3df..8ba37695be5f7 100644 --- a/DataFormats/Detectors/CTP/src/RunManager.cxx +++ b/DataFormats/Detectors/CTP/src/RunManager.cxx @@ -122,6 +122,7 @@ int CTPRunManager::addScalers(uint32_t irun, std::time_t time) } // detectors // std::vector detlist = mActiveRuns[irun]->cfg.getDetectorList(); + /* o2::detectors::DetID::mask_t detmask = mActiveRuns[irun]->cfg.getDetectorMask(); for (uint32_t i = 0; i < 32; i++) { o2::detectors::DetID::mask_t deti = 1ul << i; @@ -134,6 +135,14 @@ int CTPRunManager::addScalers(uint32_t irun, std::time_t time) // LOG(info) << "Scaler for detector:" << countername << ":" << detcount; } } + */ + int NINPS = 48; + int offset = 599; + for (uint32_t i = 0; i < NINPS; i++) { + uint32_t inpcount = mCounters[offset+i]; + scalrec.scalersInps.push_back(inpcount); + //LOG(info) << "Scaler for input:" << CTPRunScalers::scalerNames[offset+i] << ":" << inpcount; + } // if (mNew == 0) { scalrec.intRecord.orbit = mCounters[mScalerName2Position[orb]]; diff --git a/DataFormats/Detectors/CTP/src/Scalers.cxx b/DataFormats/Detectors/CTP/src/Scalers.cxx index 6f443fd5a77c4..900645416fe52 100644 --- a/DataFormats/Detectors/CTP/src/Scalers.cxx +++ b/DataFormats/Detectors/CTP/src/Scalers.cxx @@ -65,7 +65,7 @@ void CTPScalerRecordRaw::printStream(std::ostream& stream) const for (auto const& cnts : scalers) { cnts.printStream(stream); } - for (auto const& dets : scalersDets) { + for (auto const& dets : scalersInps) { stream << dets << " "; } stream << std::endl; @@ -77,7 +77,7 @@ void CTPScalerRecordO2::printStream(std::ostream& stream) const for (auto const& cnts : scalers) { cnts.printStream(stream); } - for (auto const& dets : scalersDets) { + for (auto const& dets : scalersInps) { stream << dets << " "; } stream << std::endl; diff --git a/Detectors/CTP/macro/GetBunchFillingForRun.C b/Detectors/CTP/macro/GetBunchFillingForRun.C deleted file mode 100644 index b610ac5932b9f..0000000000000 --- a/Detectors/CTP/macro/GetBunchFillingForRun.C +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include -#include -#endif -using namespace o2::ctp; - -void GetBunchFillingForRun(bool test = 1) -{ - if (test == 0) { - return; - } - o2::ccdb::CcdbApi api; - api.init("http://alice-ccdb.cern.ch"); // alice-ccdb.cern.ch - auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); - int runNumber = 526926; - std::string fillNumber = "8238"; - auto soreor = ccdbMgr.getRunDuration(runNumber); - uint64_t timeStamp = (soreor.second - soreor.first) / 2 + soreor.first; - std::cout << "Timestamp:" << timeStamp << std::endl; - std::string srun = std::to_string(runNumber); - map metadata; // can be empty - // metadata["runNumber"] = srun; - metadata["fillNumber"] = fillNumber; - auto lhcifdata = ccdbMgr.getSpecific("GLO/Config/GRPLHCIF", timeStamp, metadata); - auto bfilling = lhcifdata->getBunchFilling(); - std::vector bcs = bfilling.getFilledBCs(); - for (auto const& bc : bcs) { - std::cout << bc << std::endl; - } -} From 916568c1f93aeb1683c04f2018a57606a7de99a0 Mon Sep 17 00:00:00 2001 From: lietava Date: Sun, 24 Sep 2023 16:18:49 +0200 Subject: [PATCH 127/324] clang --- DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h | 4 ++-- DataFormats/Detectors/CTP/src/RunManager.cxx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h index e230b2494a85e..8b6257881c1e4 100644 --- a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h @@ -67,7 +67,7 @@ struct CTPScalerRecordRaw { o2::InteractionRecord intRecord; double_t epochTime; std::vector scalers; - //std::vector scalersDets; + // std::vector scalersDets; std::vector scalersInps; void printStream(std::ostream& stream) const; ClassDefNV(CTPScalerRecordRaw, 3); @@ -77,7 +77,7 @@ struct CTPScalerRecordO2 { o2::InteractionRecord intRecord; double_t epochTime; std::vector scalers; - //std::vector scalersDets; + // std::vector scalersDets; std::vector scalersInps; void printStream(std::ostream& stream) const; void printFromZero(std::ostream& stream, CTPScalerRecordO2& record0) const; diff --git a/DataFormats/Detectors/CTP/src/RunManager.cxx b/DataFormats/Detectors/CTP/src/RunManager.cxx index 8ba37695be5f7..4f83c110c01ec 100644 --- a/DataFormats/Detectors/CTP/src/RunManager.cxx +++ b/DataFormats/Detectors/CTP/src/RunManager.cxx @@ -139,9 +139,9 @@ int CTPRunManager::addScalers(uint32_t irun, std::time_t time) int NINPS = 48; int offset = 599; for (uint32_t i = 0; i < NINPS; i++) { - uint32_t inpcount = mCounters[offset+i]; + uint32_t inpcount = mCounters[offset + i]; scalrec.scalersInps.push_back(inpcount); - //LOG(info) << "Scaler for input:" << CTPRunScalers::scalerNames[offset+i] << ":" << inpcount; + // LOG(info) << "Scaler for input:" << CTPRunScalers::scalerNames[offset+i] << ":" << inpcount; } // if (mNew == 0) { From 2a158cd0ecd9362c100f0114efa290fe67dad1db Mon Sep 17 00:00:00 2001 From: Ruben Shahoyan Date: Mon, 25 Sep 2023 11:33:30 +0200 Subject: [PATCH 128/324] Increment ClassDefs --- DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h index 8b6257881c1e4..85c9d30fef2f7 100644 --- a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h @@ -70,7 +70,7 @@ struct CTPScalerRecordRaw { // std::vector scalersDets; std::vector scalersInps; void printStream(std::ostream& stream) const; - ClassDefNV(CTPScalerRecordRaw, 3); + ClassDefNV(CTPScalerRecordRaw, 4); }; struct CTPScalerRecordO2 { CTPScalerRecordO2() = default; @@ -81,7 +81,7 @@ struct CTPScalerRecordO2 { std::vector scalersInps; void printStream(std::ostream& stream) const; void printFromZero(std::ostream& stream, CTPScalerRecordO2& record0) const; - ClassDefNV(CTPScalerRecordO2, 3); + ClassDefNV(CTPScalerRecordO2, 4); }; class CTPRunScalers { From d06f15b027801d899957b745fb090188db714069 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 25 Sep 2023 09:32:07 +0200 Subject: [PATCH 129/324] dpl-workflow: Limit number of nodes in multiplicity computation to 230 to avoid downscaling --- prodtests/full-system-test/dpl-workflow.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 31f3f6785e87f..5d2e55d2335cf 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -48,7 +48,7 @@ if [[ $EPNSYNCMODE == 1 ]] || type numactl >/dev/null 2>&1 && [[ `numactl -H | g [[ $NUMAGPUIDS != 0 ]] && ARGS_ALL+=" --child-driver 'numactl --membind $NUMAID --cpunodebind $NUMAID'" fi if [[ -z ${TIMEFRAME_RATE_LIMIT:-} ]] && [[ $DIGITINPUT != 1 ]]; then - TIMEFRAME_RATE_LIMIT=$((12 * 230 / $RECO_NUM_NODES_WORKFLOW * ($NUMAGPUIDS != 0 ? 1 : 2) * 128 / $NHBPERTF)) + TIMEFRAME_RATE_LIMIT=$((12 * 230 / ($RECO_NUM_NODES_WORKFLOW < 230 ? $RECO_NUM_NODES_WORKFLOW : 230) * ($NUMAGPUIDS != 0 ? 1 : 2) * 128 / $NHBPERTF)) [[ $BEAMTYPE != "PbPb" && ${HIGH_RATE_PP:-0} == 0 ]] && TIMEFRAME_RATE_LIMIT=$(($TIMEFRAME_RATE_LIMIT * 3)) ! has_detector TPC && TIMEFRAME_RATE_LIMIT=$(($TIMEFRAME_RATE_LIMIT * 4)) [[ ! -z ${EPN_GLOBAL_SCALING:-} ]] && TIMEFRAME_RATE_LIMIT=$(($TIMEFRAME_RATE_LIMIT * $EPN_GLOBAL_SCALING)) From d27c4f8be8c2002ff991ba3bb5f5ab2a2658f095 Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 22 Sep 2023 13:37:11 +0200 Subject: [PATCH 130/324] Extract both lumis from CTP CTF Also the HBF count for the 2nd lumi was not propagated to the CTF, now it is done (though it is anyway the same as the main lumi HBF counts) --- .../CTP/include/DataFormatsCTP/CTF.h | 19 ++++++++++--------- .../include/CTPReconstruction/CTFCoder.h | 2 ++ .../include/CTPReconstruction/CTFHelper.h | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h index eb6c2cb98c761..3635b8ede44db 100644 --- a/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/CTF.h @@ -29,15 +29,16 @@ namespace ctp struct CTFHeader : public o2::ctf::CTFDictHeader { uint64_t lumiCounts = 0; /// FT0 Luminosity counts moving average over lumiNHBFs orbits uint64_t lumiCountsFV0 = 0; /// FV0 Luminosity counts moving average over lumiNHBFs orbits - uint32_t lumiNHBFs = 0; /// Number of HBFs over which lumi is integrated - uint32_t lumiOrbit = 0; /// 1st orbit of TF where lumi was updated, can be compared with firstOrbit - uint32_t nTriggers = 0; /// number of triggers - uint32_t firstOrbit = 0; /// orbit of 1st trigger - uint16_t firstBC = 0; /// bc of 1st trigger - uint16_t inp1 = 0; /// lumiCounts input ID - uint16_t inp2 = 0; /// lumiCountsFV0 input ID - - ClassDefNV(CTFHeader, 4); + uint32_t lumiNHBFs = 0; /// Number of HBFs over which lumi is integrated + uint32_t lumiNHBFsFV0 = 0; /// Number of FV0 HBFs over which lumi is integrated + uint32_t lumiOrbit = 0; /// 1st orbit of TF where lumi was updated, can be compared with firstOrbit + uint32_t nTriggers = 0; /// number of triggers + uint32_t firstOrbit = 0; /// orbit of 1st trigger + uint16_t firstBC = 0; /// bc of 1st trigger + uint16_t inp1 = 0; /// lumiCounts input ID + uint16_t inp2 = 0; /// lumiCountsFV0 input ID + + ClassDefNV(CTFHeader, 5); }; /// wrapper for the Entropy-encoded trigger inputs and classes of the TF diff --git a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h index efe31c431d368..6ffb3575207e5 100644 --- a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h +++ b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h @@ -145,7 +145,9 @@ o2::ctf::CTFIOSize CTFCoder::decode(const CTF::base& ec, VTRG& data, LumiInfo& l std::map digitsMap; o2::InteractionRecord ir(header.firstBC, header.firstOrbit); lumi.nHBFCounted = header.lumiNHBFs; + lumi.nHBFCountedFV0 = header.lumiNHBFsFV0 ? header.lumiNHBFsFV0 : header.lumiNHBFs; lumi.counts = header.lumiCounts; + lumi.countsFV0 = header.lumiCountsFV0; lumi.orbit = header.lumiOrbit; lumi.inp1 = int(header.inp1); lumi.inp2 = int(header.inp2); diff --git a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h index b2847a59ab3ff..34228e3acc55f 100644 --- a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h +++ b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFHelper.h @@ -38,7 +38,7 @@ class CTFHelper CTFHeader createHeader(const LumiInfo& lumi) { CTFHeader h{o2::detectors::DetID::CTP, 0, 1, 0, // dummy timestamp, version 1.0 - lumi.counts, lumi.countsFV0, lumi.nHBFCounted, lumi.orbit, + lumi.counts, lumi.countsFV0, lumi.nHBFCounted, lumi.nHBFCountedFV0, lumi.orbit, uint32_t(mData.size()), 0, 0, uint16_t(lumi.inp1), uint16_t(lumi.inp2)}; if (mData.size()) { h.firstOrbit = mData[0].intRecord.orbit; From f2900305b7e8ebbb3f9b7dc46c50d19bbce95828 Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 22 Sep 2023 17:21:12 +0200 Subject: [PATCH 131/324] Add options to rescale CTP lumi and select its source used for TPC corrections --- .../Detectors/CTP/include/DataFormatsCTP/LumiInfo.h | 2 ++ .../include/TPCCalibration/CorrectionMapsLoader.h | 3 +++ Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx | 9 +++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/LumiInfo.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/LumiInfo.h index 918f602bbd2d1..e9eb8ba497c17 100644 --- a/DataFormats/Detectors/CTP/include/DataFormatsCTP/LumiInfo.h +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/LumiInfo.h @@ -32,8 +32,10 @@ struct LumiInfo { int inp2 = 6; // VBA float getLumi() const { return nHBFCounted > 0 ? float(counts / (nHBFCounted * o2::constants::lhc::LHCOrbitMUS * 1e-6)) : 0.f; } float getLumiFV0() const { return nHBFCountedFV0 > 0 ? float(countsFV0 / (nHBFCountedFV0 * o2::constants::lhc::LHCOrbitMUS * 1e-6)) : 0.f; } + float getLumiAlt() const { return getLumiFV0(); } float getLumiError() const { return nHBFCounted > 0 ? float(std::sqrt(counts) / (nHBFCounted * o2::constants::lhc::LHCOrbitMUS * 1e-6)) : 0.f; } float getLumiFV0Error() const { return nHBFCountedFV0 > 0 ? float(std::sqrt(countsFV0) / (nHBFCountedFV0 * o2::constants::lhc::LHCOrbitMUS * 1e-6)) : 0.f; } + float getLumiAltError() const { return getLumiFV0Error(); } void printInputs() const; ClassDefNV(LumiInfo, 3); }; diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h b/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h index 0771b922a19d4..043ed05e33d70 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h @@ -54,6 +54,9 @@ class CorrectionMapsLoader : public o2::gpu::CorrectionMapsHelper protected: static void addOption(std::vector& options, o2::framework::ConfigParamSpec&& osp); static void addInput(std::vector& inputs, o2::framework::InputSpec&& isp); + + float mInstLumiFactor = 1.0; // multiplicative factor for inst. lumi + int mCTPLumiSource = 0; // 0: main, 1: alternative CTP lumi source #endif }; diff --git a/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx b/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx index 1c9a5852a6953..ae955a1ef312b 100644 --- a/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx +++ b/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx @@ -44,7 +44,7 @@ void CorrectionMapsLoader::extractCCDBInputs(ProcessingContext& pc) pc.inputs().get("tpcCorrMapRef"); // not used at the moment if (getUseCTPLumi() && mInstLumiOverride <= 0.) { auto lumiObj = pc.inputs().get("CTPLumi"); - setInstLumi(lumiObj.getLumi()); + setInstLumi(mInstLumiFactor * (mCTPLumiSource == 0 ? lumiObj.getLumi() : lumiObj.getLumiAlt())); } } @@ -72,6 +72,8 @@ void CorrectionMapsLoader::addOptions(std::vector& options) addOption(options, ConfigParamSpec{"corrmap-lumi-mean", VariantType::Float, 0.f, {"override TPC corr.map mean lumi (if > 0), disable corrections if < 0"}}); addOption(options, ConfigParamSpec{"corrmap-lumi-inst", VariantType::Float, 0.f, {"override instantaneous CTP lumi (if > 0) for TPC corr.map scaling, disable corrections if < 0"}}); addOption(options, ConfigParamSpec{"corrmap-lumi-mode", VariantType::Int, 0, {"scaling mode: (default) 0 = static + scale * full; 1 = full + scale * derivative"}}); + addOption(options, ConfigParamSpec{"ctp-lumi-factor", VariantType::Float, 1.0f, {"scaling to apply to instantaneous lumi from CTP (but not corrmap-lumi-inst)"}}); + addOption(options, ConfigParamSpec{"ctp-lumi-source", VariantType::Int, 0, {"CTP lumi source: 0 = LumiInfo.getLumi(), 1 = LumiInfo.getLumiAlt()"}}); } //________________________________________________________ @@ -125,12 +127,15 @@ void CorrectionMapsLoader::init(o2::framework::InitContext& ic) mMeanLumiOverride = ic.options().get("corrmap-lumi-mean"); mInstLumiOverride = ic.options().get("corrmap-lumi-inst"); mLumiScaleMode = ic.options().get("corrmap-lumi-mode"); + mInstLumiFactor = ic.options().get("ctp-lumi-factor"); + mCTPLumiSource = ic.options().get("ctp-lumi-source"); if (mMeanLumiOverride != 0.) { setMeanLumi(mMeanLumiOverride); } if (mInstLumiOverride != 0.) { setInstLumi(mInstLumiOverride); } - LOGP(info, "CTP Lumi request for TPC corr.map scaling={}, override values: lumiMean={} lumiInst={} lumiScaleMode={}", getUseCTPLumi() ? "ON" : "OFF", mMeanLumiOverride, mInstLumiOverride, mLumiScaleMode); + LOGP(info, "CTP Lumi request for TPC corr.map scaling={}, override values: lumiMean={} lumiInst={} lumiScaleMode={}, LumiInst scale={}, CTP Lumi source={}", + getUseCTPLumi() ? "ON" : "OFF", mMeanLumiOverride, mInstLumiOverride, mLumiScaleMode, mInstLumiFactor, mCTPLumiSource); } #endif // #ifndef GPUCA_GPUCODE_DEVICE From f9711ba81b7087720b60c7405db7ef5c3ba0139d Mon Sep 17 00:00:00 2001 From: swenzel Date: Thu, 21 Sep 2023 15:28:51 +0200 Subject: [PATCH 132/324] o2-sim: Better VMC shutdown (via plugin code) Introducing the ability to close/terminate the VMC simulation engines. * for instance to print final statistics about steps, magnetic field calls etc. --- Detectors/gconfig/g4Config.C | 14 +++++++ Detectors/gconfig/include/SimSetup/SimSetup.h | 4 ++ Detectors/gconfig/src/G4Config.cxx | 9 ++++- Detectors/gconfig/src/SimSetup.cxx | 37 ++++++++++++++----- run/O2SimDeviceRunner.cxx | 4 +- 5 files changed, 56 insertions(+), 12 deletions(-) diff --git a/Detectors/gconfig/g4Config.C b/Detectors/gconfig/g4Config.C index 96650006270f5..8f74c0105dbf5 100644 --- a/Detectors/gconfig/g4Config.C +++ b/Detectors/gconfig/g4Config.C @@ -133,3 +133,17 @@ void Config() std::cout << "g4Config.C finished" << std::endl; } + +void Terminate() +{ + static bool terminated = false; + if (!terminated) { + std::cout << "Executing G4 terminate\n"; + TGeant4* geant4 = dynamic_cast(TVirtualMC::GetMC()); + if (geant4) { + // we need to call finish run for Geant4 ... Since we use ProcessEvent() interface; + geant4->FinishRun(); + } + terminated = true; + } +} diff --git a/Detectors/gconfig/include/SimSetup/SimSetup.h b/Detectors/gconfig/include/SimSetup/SimSetup.h index 5bf685ab9a4f5..020315fb0f2c0 100644 --- a/Detectors/gconfig/include/SimSetup/SimSetup.h +++ b/Detectors/gconfig/include/SimSetup/SimSetup.h @@ -10,11 +10,15 @@ // or submit itself to any jurisdiction. #ifndef O2_SIMSETUP_H +#define O2_SIMSETUP_H namespace o2 { struct SimSetup { static void setup(const char* engine); + + // a static entrypoint to shutdown the VMC system + static void shutdown(); }; } // namespace o2 diff --git a/Detectors/gconfig/src/G4Config.cxx b/Detectors/gconfig/src/G4Config.cxx index 662bb60067c42..b8a27f5c1975f 100644 --- a/Detectors/gconfig/src/G4Config.cxx +++ b/Detectors/gconfig/src/G4Config.cxx @@ -29,16 +29,23 @@ using std::endl; // these are used in commonConfig.C using o2::eventgen::DecayerPythia8; +#include "../g4Config.C" + namespace o2 { namespace g4config { -#include "../g4Config.C" void G4Config() { LOG(info) << "Setting up G4 sim from library code"; Config(); } + +void G4Terminate() +{ + Terminate(); +} + } // namespace g4config } // namespace o2 diff --git a/Detectors/gconfig/src/SimSetup.cxx b/Detectors/gconfig/src/SimSetup.cxx index 6e11c50fae865..e9dc1da667369 100644 --- a/Detectors/gconfig/src/SimSetup.cxx +++ b/Detectors/gconfig/src/SimSetup.cxx @@ -11,6 +11,7 @@ #include #include "SimSetup/SimSetup.h" +#include "TVirtualMC.h" #include #include "SetCuts.h" #include @@ -25,9 +26,8 @@ namespace o2 typedef void (*setup_fnc)(); -void setupFromPlugin(const char* libname, const char* setupfuncname) +void execFromPlugin(const char* libname, const char* funcname) { - LOG(info) << "Loading simulation plugin " << libname; auto libHandle = dlopen(libname, RTLD_NOW); // try to make the library loading a bit more portable: if (!libHandle) { @@ -43,26 +43,43 @@ void setupFromPlugin(const char* libname, const char* setupfuncname) libHandle = dlopen(stream.str().c_str(), RTLD_NOW); } assert(libHandle); - auto setup = (setup_fnc)dlsym(libHandle, setupfuncname); - assert(setup); - setup(); + auto func = (setup_fnc)dlsym(libHandle, funcname); + assert(func); + func(); +} + +void execSetupFromPlugin(const char* libname, const char* funcname) +{ + LOG(info) << "Seting up transport engine from library " << libname; + execFromPlugin(libname, funcname); } void SimSetup::setup(const char* engine) { if (strcmp(engine, "TGeant3") == 0) { - setupFromPlugin("libO2G3Setup", "_ZN2o28g3config8G3ConfigEv"); + execSetupFromPlugin("libO2G3Setup", "_ZN2o28g3config8G3ConfigEv"); } else if (strcmp(engine, "TGeant4") == 0) { - setupFromPlugin("libO2G4Setup", "_ZN2o28g4config8G4ConfigEv"); + execSetupFromPlugin("libO2G4Setup", "_ZN2o28g4config8G4ConfigEv"); } else if (strcmp(engine, "TFluka") == 0) { - setupFromPlugin("libO2FLUKASetup", "_ZN2o211flukaconfig11FlukaConfigEv"); + execSetupFromPlugin("libO2FLUKASetup", "_ZN2o211flukaconfig11FlukaConfigEv"); } else if (strcmp(engine, "MCReplay") == 0) { - setupFromPlugin("libO2MCReplaySetup", "_ZN2o214mcreplayconfig14MCReplayConfigEv"); + execSetupFromPlugin("libO2MCReplaySetup", "_ZN2o214mcreplayconfig14MCReplayConfigEv"); } else if (strcmp(engine, "O2TrivialMCEngine") == 0) { - setupFromPlugin("libO2O2TrivialMCEngineSetup", "_ZN2o223o2trivialmcengineconfig23O2TrivialMCEngineConfigEv"); + execSetupFromPlugin("libO2O2TrivialMCEngineSetup", "_ZN2o223o2trivialmcengineconfig23O2TrivialMCEngineConfigEv"); } else { LOG(fatal) << "Unsupported engine " << engine; } o2::SetCuts(); } + +// function to shutdown the engines and do some necessary +// finalisation work +void SimSetup::shutdown() +{ + auto vmc = TVirtualMC::GetMC(); + if (strcmp(vmc->GetName(), "TGeant4") == 0) { + execFromPlugin("libO2G4Setup", "_ZN2o28g4config11G4TerminateEv"); + } +} + } // namespace o2 diff --git a/run/O2SimDeviceRunner.cxx b/run/O2SimDeviceRunner.cxx index 512f6059f9569..524e609883926 100644 --- a/run/O2SimDeviceRunner.cxx +++ b/run/O2SimDeviceRunner.cxx @@ -12,6 +12,7 @@ /// @author Sandro Wenzel #include "O2SimDevice.h" +#include "SimSetup/SimSetup.h" #include #include #include @@ -66,7 +67,7 @@ void sigaction_handler(int signal, siginfo_t* signal_info, void*) break; } } - + o2::SimSetup::shutdown(); _exit(0); } @@ -177,6 +178,7 @@ int runSim(KernelSetup setup) while (setup.sim->Kernel(setup.workerID, *setup.primchannel, *setup.datachannel, setup.primstatuschannel)) { } doLogInfo(setup.workerID, "simulation is done"); + o2::SimSetup::shutdown(); return 0; } From ef024800aaf18a055b95fd0d0b124901bb7d55c3 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 25 Sep 2023 09:43:08 +0200 Subject: [PATCH 133/324] GPU: Reduce verbosity --- GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx | 2 +- GPU/Workflow/src/GPUWorkflowPipeline.cxx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index 36461025c526d..22801402a8021 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -946,7 +946,7 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) if (GetProcessingSettings().param.tpcTriggerHandling) { GPUOutputControl* triggerOutput = mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTriggerWords)]; if (triggerOutput && triggerOutput->allocator) { - GPUInfo("Storing %lu trigger words", mTriggerBuffer->triggers.size()); + // GPUInfo("Storing %lu trigger words", mTriggerBuffer->triggers.size()); auto* outputBuffer = (decltype(mTriggerBuffer->triggers)::value_type*)triggerOutput->allocator(mTriggerBuffer->triggers.size() * sizeof(decltype(mTriggerBuffer->triggers)::value_type)); std::copy(mTriggerBuffer->triggers.begin(), mTriggerBuffer->triggers.end(), outputBuffer); } diff --git a/GPU/Workflow/src/GPUWorkflowPipeline.cxx b/GPU/Workflow/src/GPUWorkflowPipeline.cxx index 3803fe2c96744..6bb8e49e566b5 100644 --- a/GPU/Workflow/src/GPUWorkflowPipeline.cxx +++ b/GPU/Workflow/src/GPUWorkflowPipeline.cxx @@ -78,7 +78,7 @@ void GPURecoWorkflowSpec::initPipeline(o2::framework::InitContext& ic) void GPURecoWorkflowSpec::RunWorkerThread(int id) { - LOG(info) << "Running pipeline worker " << id; + LOG(debug) << "Running pipeline worker " << id; auto& workerContext = mPipeline->workers[id]; while (!mPipeline->shouldTerminate) { GPURecoWorkflow_QueueObject* context; @@ -257,7 +257,7 @@ void GPURecoWorkflowSpec::RunReceiveThread() bool received = false; int recvTimeot = 1000; fair::mq::MessagePtr msg; - LOG(info) << "Waiting for out of band message"; + LOG(debug) << "Waiting for out of band message"; do { try { msg = device->NewMessageFor("gpu-prepare-channel", 0, 0); From 875d0d69da260a3d522a933b389e9109277ff935 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 25 Sep 2023 10:28:17 +0200 Subject: [PATCH 134/324] GPU: Improve scheduling of synchronization of finalization of output transfer of previous TF, and notification to foreign chain --- .../Global/GPUChainTrackingClusterizer.cxx | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index 22801402a8021..f2983d38b12de 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -648,6 +648,17 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) char transferRunning[NSLICES] = {0}; unsigned int outputQueueStart = mOutputQueue.size(); + auto notifyForeignChainFinished = [this]() { + if (mPipelineNotifyCtx) { + SynchronizeStream(mRec->NStreams() - 2); // Must finish before updating ioPtrs in (global) constant memory + { + std::lock_guard lock(mPipelineNotifyCtx->mutex); + mPipelineNotifyCtx->ready = true; + } + mPipelineNotifyCtx->cond.notify_one(); + } + }; + for (unsigned int iSliceBase = 0; iSliceBase < NSLICES; iSliceBase += GetProcessingSettings().nTPCClustererLanes) { std::vector laneHasData(GetProcessingSettings().nTPCClustererLanes, false); static_assert(NSLICES <= GPUCA_MAX_STREAMS, "Stream events must be able to hold all slices"); @@ -923,6 +934,10 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) GPUMemCpy(RecoStep::TPCClusterFinding, (void*)&mInputsHost->mPclusterNativeOutput[nClsFirst], (void*)&mInputsShadow->mPclusterNativeBuffer[nClsFirst], (nClsTotal - nClsFirst) * sizeof(mInputsHost->mPclusterNativeOutput[nClsFirst]), mRec->NStreams() - 1, false); } } + + if (mWaitForFinalInputs && iSliceBase >= 24 && iSliceBase < 24 + GetProcessingSettings().nTPCClustererLanes) { + notifyForeignChainFinished(); + } } for (int i = 0; i < GetProcessingSettings().nTPCClustererLanes; i++) { if (transferRunning[i]) { @@ -930,15 +945,6 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) } } - if (mPipelineNotifyCtx) { - SynchronizeStream(mRec->NStreams() - 2); // Must finish before updating ioPtrs in (global) constant memory - { - std::lock_guard lock(mPipelineNotifyCtx->mutex); - mPipelineNotifyCtx->ready = true; - } - mPipelineNotifyCtx->cond.notify_one(); - } - if (mWaitForFinalInputs) { mWaitForFinalInputs(); } @@ -995,6 +1001,10 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) mIOPtrs.clustersNative = tmpNative; } + if (!mWaitForFinalInputs) { + notifyForeignChainFinished(); + } + if (buildNativeGPU) { processorsShadow()->ioPtrs.clustersNative = mInputsShadow->mPclusterNativeAccess; WriteToConstantMemory(RecoStep::TPCClusterFinding, (char*)&processors()->ioPtrs - (char*)processors(), &processorsShadow()->ioPtrs, sizeof(processorsShadow()->ioPtrs), 0); From d8c51aae158d1dfd37947071ef152883f11a3675 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 25 Sep 2023 13:03:08 +0200 Subject: [PATCH 135/324] GPU double-pipeline: Do calib updates during last sectors of clusterization, after receiving late input data --- GPU/GPUTracking/Global/GPUChainTracking.cxx | 8 ++++++-- GPU/GPUTracking/Global/GPUChainTracking.h | 2 +- .../Global/GPUChainTrackingClusterizer.cxx | 14 +++++++++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 1d30f4d8baa01..33c267519470f 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -607,8 +607,9 @@ void GPUChainTracking::SetTRDGeometry(std::unique_ptr&& g processors()->calibObjects.trdGeometry = mTRDGeometryU.get(); } -void GPUChainTracking::DoQueuedUpdates(int stream) +int GPUChainTracking::DoQueuedUpdates(int stream, bool updateSlave) { + int retVal = 0; std::unique_ptr grp; const GPUSettingsProcessing* p = nullptr; std::lock_guard lk(mMutexUpdateCalib); @@ -646,14 +647,17 @@ void GPUChainTracking::DoQueuedUpdates(int stream) } if (grp || p) { mRec->UpdateSettings(grp.get(), p); + retVal = 1; } - if ((mUpdateNewCalibObjects || mRec->slavesExist()) && mRec->IsGPU()) { + if ((mUpdateNewCalibObjects || (mRec->slavesExist() && updateSlave)) && mRec->IsGPU()) { UpdateGPUCalibObjectsPtrs(stream); // Reinitialize + retVal = 1; } mNewCalibObjects.reset(nullptr); mNewCalibValues.reset(nullptr); mUpdateNewCalibObjects = false; + return retVal; } int GPUChainTracking::RunChain() diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index c575c8ed5eb2f..944a891e5c1f6 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -86,7 +86,7 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega bool SupportsDoublePipeline() override { return true; } int FinalizePipelinedProcessing() override; void ClearErrorCodes(bool cpuOnly = false); - void DoQueuedUpdates(int stream); // Forces doing queue calib updates, don't call when you are not sure you are allowed to do so! + int DoQueuedUpdates(int stream, bool updateSlave = true); // Forces doing queue calib updates, don't call when you are not sure you are allowed to do so! bool QARanForTF() const { return mFractionalQAEnabled; } // Structures for input and output data diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index f2983d38b12de..07a3b22b5f649 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -658,6 +658,7 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) mPipelineNotifyCtx->cond.notify_one(); } }; + bool synchronizeCalibUpdate = false; for (unsigned int iSliceBase = 0; iSliceBase < NSLICES; iSliceBase += GetProcessingSettings().nTPCClustererLanes) { std::vector laneHasData(GetProcessingSettings().nTPCClustererLanes, false); @@ -935,9 +936,13 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) } } - if (mWaitForFinalInputs && iSliceBase >= 24 && iSliceBase < 24 + GetProcessingSettings().nTPCClustererLanes) { + if (mWaitForFinalInputs && iSliceBase >= 21 && iSliceBase < 21 + GetProcessingSettings().nTPCClustererLanes) { notifyForeignChainFinished(); } + if (mWaitForFinalInputs && iSliceBase >= 30 && iSliceBase < 30 + GetProcessingSettings().nTPCClustererLanes) { + mWaitForFinalInputs(); + synchronizeCalibUpdate = DoQueuedUpdates(0, false); + } } for (int i = 0; i < GetProcessingSettings().nTPCClustererLanes; i++) { if (transferRunning[i]) { @@ -945,10 +950,6 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) } } - if (mWaitForFinalInputs) { - mWaitForFinalInputs(); - } - if (GetProcessingSettings().param.tpcTriggerHandling) { GPUOutputControl* triggerOutput = mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTriggerWords)]; if (triggerOutput && triggerOutput->allocator) { @@ -1016,6 +1017,9 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) if (synchronizeOutput) { SynchronizeStream(mRec->NStreams() - 1); } + if (synchronizeCalibUpdate) { + SynchronizeStream(0); + } if (buildNativeHost && GetProcessingSettings().debugLevel >= 4) { for (unsigned int i = 0; i < NSLICES; i++) { for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) { From 08bba367aa10483238eace250f02839d1941a619 Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Mon, 25 Sep 2023 16:21:57 +0200 Subject: [PATCH 136/324] Denote deadbeef error to warning --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index d18ce84e29147..4cfc7545cd01c 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -335,7 +335,7 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve static int maxWarn = 10; // Correct would be o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef, but Framework does not depend on CommonUtils..., but not so critical since receives will send correct number of DEADBEEF messages static int contDeadBeef = 0; if (++contDeadBeef <= maxWarn) { - LOGP(error, "Found {}/{} data specs, missing data specs: {}, injecting 0xDEADBEEF", present.size() - unmatchedDescriptions.size(), present.size(), missing); + LOGP(alarm, "Found {}/{} data specs, missing data specs: {}, injecting 0xDEADBEEF", present.size() - unmatchedDescriptions.size(), present.size(), missing); } } } From 52ddf8dc65a485b6acc6257d2ef907610ca3a1b5 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 25 Sep 2023 23:03:58 +0200 Subject: [PATCH 137/324] DPL: inject firstTForbit and tfCounter when missing (#11953) * DPL: inject firstTForbit and tfCounter when missing Use the values from from the first available data header. * Clarify error messages --------- Co-authored-by: David Rohr --- .../Core/src/ExternalFairMQDeviceProxy.cxx | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 4cfc7545cd01c..4118e1ce0d0e2 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -243,6 +243,7 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve unmatchedDescriptions.clear(); bool allFound = true; DataProcessingHeader const* dph = nullptr; + DataHeader const* firstDH = nullptr; // Do not check anything which has DISTSUBTIMEFRAME in it. for (size_t pi = 0; pi < present.size(); ++pi) { @@ -274,6 +275,9 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve } continue; } + if (firstDH == nullptr) { + firstDH = dh; + } for (size_t pi = 0; pi < present.size(); ++pi) { if (present[pi]) { continue; @@ -300,14 +304,16 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve } if (unmatchedDescriptions.size() > 0) { + if (firstDH == nullptr) { + LOG(error) << "Input proxy received incomplete data without any data header. This should not happen! Cannot inject missing data as requsted."; + return; + } + if (dph == nullptr) { + LOG(error) << "Input proxy received incomplete data without any data processing header. This should happen! Cannot inject missing data as requsted."; + return; + } std::string missing = ""; for (auto mi : unmatchedDescriptions) { - if (dph == nullptr) { - // This can happen for non DPL messages in input, - // like it happens for some tests. - LOG(debug) << "DataProcessingHeader not found. Skipping message pair."; - continue; - } auto& spec = routes[mi].matcher; missing += " " + DataSpecUtils::describe(spec); // If we have a ConcreteDataMatcher, we can create a message with the correct header. @@ -317,11 +323,13 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve if (subSpec == std::nullopt) { *subSpec = 0xDEADBEEF; } - o2::header::DataHeader dh; + o2::header::DataHeader dh{*firstDH}; dh.dataOrigin = concrete.origin; dh.dataDescription = concrete.description; dh.subSpecification = *subSpec; dh.payloadSize = 0; + dh.splitPayloadParts = 0; + dh.splitPayloadIndex = 0; dh.payloadSerializationMethod = header::gSerializationMethodNone; auto& channelName = routes[mi].channel; From 8f8fea6c1f10992f41cb6ab191c81b202045ac99 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 25 Sep 2023 21:48:59 +0200 Subject: [PATCH 138/324] FST: Make DD wait time configurable --- prodtests/full-system-test/start_tmux.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/prodtests/full-system-test/start_tmux.sh b/prodtests/full-system-test/start_tmux.sh index acf7f43451f1f..e6451d7940a2a 100755 --- a/prodtests/full-system-test/start_tmux.sh +++ b/prodtests/full-system-test/start_tmux.sh @@ -108,6 +108,7 @@ else FST_SLEEP1=0 FST_SLEEP2=30 fi +[[ ! -z $FST_TMUX_DD_WAIT ]] && FST_SLEEP2=$FST_TMUX_DD_WAIT if [[ ! -z $FST_TMUX_SINGLENUMA ]]; then eval "FST_SLEEP$((FST_TMUX_SINGLENUMA ^ 1))=\"0; echo SKIPPED; sleep 1000; exit\"" From 2189c87003981043747877e9d5e371132fac840e Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 25 Sep 2023 14:21:45 +0200 Subject: [PATCH 139/324] GPU: Clean up multi-threading, fix START/STOP/START for the future, don't poll for FMQ states, and better handling to avoid blocking FMQ state changes --- .../include/GPUWorkflow/GPUWorkflowSpec.h | 6 +- GPU/Workflow/src/GPUWorkflowInternal.h | 8 ++- GPU/Workflow/src/GPUWorkflowPipeline.cxx | 69 ++++++++++++++----- GPU/Workflow/src/GPUWorkflowSpec.cxx | 2 +- 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index d77a2c63462eb..ae7fe2d462d41 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -33,6 +33,7 @@ class TStopwatch; namespace fair::mq { struct RegionInfo; +enum class State : int; } // namespace fair::mq namespace o2 { @@ -160,17 +161,18 @@ class GPURecoWorkflowSpec : public o2::framework::Task template void processInputs(o2::framework::ProcessingContext&, D&, E&, F&, G&, bool&, H&, I&, J&, K&); + int runMain(o2::framework::ProcessingContext* pc, GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, int threadIndex = 0, GPUInterfaceInputUpdate* inputUpdateCallback = nullptr); int runITSTracking(o2::framework::ProcessingContext& pc); int handlePipeline(o2::framework::ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, gpurecoworkflow_internals::GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS, std::unique_ptr& context); void RunReceiveThread(); void RunWorkerThread(int id); - void TerminateThreads(); + void ExitPipeline(); void handlePipelineEndOfStream(o2::framework::EndOfStreamContext& ec); void initPipeline(o2::framework::InitContext& ic); void enqueuePipelinedJob(GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, gpurecoworkflow_internals::GPURecoWorkflow_QueueObject* context, bool inputFinal); void finalizeInputPipelinedJob(GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, gpurecoworkflow_internals::GPURecoWorkflow_QueueObject* context); - int runMain(o2::framework::ProcessingContext* pc, GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, int threadIndex = 0, GPUInterfaceInputUpdate* inputUpdateCallback = nullptr); + void receiveFMQStateCallback(fair::mq::State); CompletionPolicyData* mPolicyData; std::function mPolicyOrder; diff --git a/GPU/Workflow/src/GPUWorkflowInternal.h b/GPU/Workflow/src/GPUWorkflowInternal.h index a6e94008c20ee..9e805b3448bfc 100644 --- a/GPU/Workflow/src/GPUWorkflowInternal.h +++ b/GPU/Workflow/src/GPUWorkflowInternal.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace o2::gpu { @@ -59,7 +60,12 @@ struct GPURecoWorkflow_QueueObject { struct GPURecoWorkflowSpec_PipelineInternals { std::mutex mutexDecodeInput; - fair::mq::Device* fmqDevice; + fair::mq::Device* fmqDevice = nullptr; + + fair::mq::State fmqState = fair::mq::State::Undefined; + bool endOfStreamReceived = false; + std::mutex fmqStateMutex; + std::condition_variable fmqStateCheckNotify; std::thread receiveThread; std::mutex threadMutex; diff --git a/GPU/Workflow/src/GPUWorkflowPipeline.cxx b/GPU/Workflow/src/GPUWorkflowPipeline.cxx index 6bb8e49e566b5..6b1f5764f8a9a 100644 --- a/GPU/Workflow/src/GPUWorkflowPipeline.cxx +++ b/GPU/Workflow/src/GPUWorkflowPipeline.cxx @@ -34,6 +34,7 @@ #include #include +#include using namespace o2::framework; using namespace o2::header; @@ -45,6 +46,8 @@ using namespace o2::gpu::gpurecoworkflow_internals; namespace o2::gpu { +static const std::string GPURecoWorkflowSpec_FMQCallbackKey = "GPURecoWorkflowSpec_FMQCallbackKey"; + struct pipelinePrepareMessage { static constexpr size_t MAGIC_WORD = 0X8473957353424134; size_t magicWord = MAGIC_WORD; @@ -60,6 +63,7 @@ void GPURecoWorkflowSpec::initPipeline(o2::framework::InitContext& ic) { if (mSpecConfig.enableDoublePipeline == 1) { mPipeline->fmqDevice = ic.services().get().device(); + mPipeline->fmqDevice->SubscribeToStateChange(GPURecoWorkflowSpec_FMQCallbackKey, [this](fair::mq::State s) { receiveFMQStateCallback(s); }); mPolicyOrder = [this](o2::framework::DataProcessingHeader::StartTime timeslice) { std::unique_lock lk(mPipeline->completionPolicyMutex); mPipeline->completionPolicyNotify.wait(lk, [pipeline = mPipeline.get()] { return pipeline->pipelineSenderTerminating || !pipeline->completionPolicyQueue.empty(); }); @@ -233,7 +237,11 @@ int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutP void GPURecoWorkflowSpec::handlePipelineEndOfStream(EndOfStreamContext& ec) { if (mSpecConfig.enableDoublePipeline == 1) { - TerminateThreads(); // TODO: Apparently breaks START / STOP / START + { + std::lock_guard lk(mPipeline->fmqStateMutex); + mPipeline->endOfStreamReceived = true; + } + mPipeline->fmqStateCheckNotify.notify_all(); } if (mSpecConfig.enableDoublePipeline == 2) { auto* device = ec.services().get().device(); @@ -247,18 +255,37 @@ void GPURecoWorkflowSpec::handlePipelineEndOfStream(EndOfStreamContext& ec) } } +void GPURecoWorkflowSpec::receiveFMQStateCallback(fair::mq::State newState) +{ + { + std::lock_guard lk(mPipeline->fmqStateMutex); + if (mPipeline->fmqState != fair::mq::State::Running && newState == fair::mq::State::Running) { + mPipeline->endOfStreamReceived = false; + } + mPipeline->fmqState = newState; + if (newState == fair::mq::State::Exiting) { + mPipeline->fmqDevice->UnsubscribeFromStateChange(GPURecoWorkflowSpec_FMQCallbackKey); + } + } + mPipeline->fmqStateCheckNotify.notify_all(); +} + void GPURecoWorkflowSpec::RunReceiveThread() { auto* device = mPipeline->fmqDevice; - while (device->GetCurrentState() != fair::mq::State::Running) { - usleep(300000); - } while (!mPipeline->shouldTerminate) { bool received = false; int recvTimeot = 1000; fair::mq::MessagePtr msg; LOG(debug) << "Waiting for out of band message"; do { + { + std::unique_lock lk(mPipeline->fmqStateMutex); + mPipeline->fmqStateCheckNotify.wait(lk, [this]() { return (mPipeline->fmqState == fair::mq::State::Running && !mPipeline->endOfStreamReceived) || mPipeline->shouldTerminate; }); // Do not check mPipeline->fmqDevice->NewStatePending() since we wait for EndOfStream! + } + if (mPipeline->shouldTerminate) { + break; + } try { msg = device->NewMessageFor("gpu-prepare-channel", 0, 0); do { @@ -279,8 +306,10 @@ void GPURecoWorkflowSpec::RunReceiveThread() LOG(fatal) << "Prepare message corrupted, invalid magic word"; } if (m->flagEndOfStream) { - LOG(info) << "Received end-of-stream from out-of-band channel, terminating receive thread"; // TODO: Breaks START / STOP / START - break; + LOG(info) << "Received end-of-stream from out-of-band channel"; + mPipeline->endOfStreamReceived = true; + mPipeline->mNTFReceived = 0; + continue; } auto context = std::make_unique(); @@ -317,7 +346,7 @@ void GPURecoWorkflowSpec::RunReceiveThread() context->ptrs.tpcZS = &context->tpcZS; context->ptrs.settingsTF = &context->tfSettings; context->mTFId = mPipeline->mNTFReceived; - if (mPipeline->mNTFReceived++ >= mPipeline->workers.size()) { // Do not inject the first 2 TF, since we need a first round of calib updates from DPL before starting + if (mPipeline->mNTFReceived++ >= mPipeline->workers.size()) { // Do not inject the first workers.size() TFs, since we need a first round of calib updates from DPL before starting enqueuePipelinedJob(&context->ptrs, nullptr, context.get(), false); } { @@ -338,18 +367,22 @@ void GPURecoWorkflowSpec::RunReceiveThread() mPipeline->completionPolicyNotify.notify_one(); } -void GPURecoWorkflowSpec::TerminateThreads() +void GPURecoWorkflowSpec::ExitPipeline() { - mPipeline->shouldTerminate = true; - for (unsigned int i = 0; i < mPipeline->workers.size(); i++) { - mPipeline->workers[i].inputQueueNotify.notify_one(); - } - if (mPipeline->receiveThread.joinable()) { - mPipeline->receiveThread.join(); - } - for (unsigned int i = 0; i < mPipeline->workers.size(); i++) { - if (mPipeline->workers[i].thread.joinable()) { - mPipeline->workers[i].thread.join(); + if (mSpecConfig.enableDoublePipeline == 1 && mPipeline->fmqDevice) { + mPipeline->fmqDevice = nullptr; + mPipeline->shouldTerminate = true; + mPipeline->fmqStateCheckNotify.notify_all(); + for (unsigned int i = 0; i < mPipeline->workers.size(); i++) { + mPipeline->workers[i].inputQueueNotify.notify_one(); + } + if (mPipeline->receiveThread.joinable()) { + mPipeline->receiveThread.join(); + } + for (unsigned int i = 0; i < mPipeline->workers.size(); i++) { + if (mPipeline->workers[i].thread.joinable()) { + mPipeline->workers[i].thread.join(); + } } } } diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 9834f81ed5266..c47d86832df41 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -1211,7 +1211,7 @@ Outputs GPURecoWorkflowSpec::outputs() void GPURecoWorkflowSpec::deinitialize() { - TerminateThreads(); + ExitPipeline(); mQA.reset(nullptr); mDisplayFrontend.reset(nullptr); mGPUReco.reset(nullptr); From b3e10d243812a1866a39797c863bf28f5fe200ef Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 25 Sep 2023 20:27:07 +0200 Subject: [PATCH 140/324] GPU QA: Use single GPU QA instance for double-pipeline --- GPU/GPUTracking/Benchmark/standalone.cxx | 3 +++ GPU/GPUTracking/Global/GPUChainTracking.cxx | 28 ++++++++++++-------- GPU/GPUTracking/Global/GPUChainTracking.h | 6 +++-- GPU/GPUTracking/Interface/GPUO2Interface.cxx | 4 +++ GPU/GPUTracking/qa/GPUQA.h | 1 + 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/GPU/GPUTracking/Benchmark/standalone.cxx b/GPU/GPUTracking/Benchmark/standalone.cxx index ad0ac17b83565..9dc4c5a4908bf 100644 --- a/GPU/GPUTracking/Benchmark/standalone.cxx +++ b/GPU/GPUTracking/Benchmark/standalone.cxx @@ -501,6 +501,7 @@ int ReadEvent(int n) if ((configStandalone.proc.runQA || configStandalone.eventDisplay) && !configStandalone.QA.noMC) { chainTracking->ForceInitQA(); snprintf(filename, 256, "events/%s/mc.%d.dump", configStandalone.eventsDir, n); + chainTracking->GetQA()->UpdateChain(chainTracking); if (chainTracking->GetQA()->ReadO2MCData(filename)) { snprintf(filename, 256, "events/%s/mc.%d.dump", configStandalone.eventsDir, 0); if (chainTracking->GetQA()->ReadO2MCData(filename) && configStandalone.proc.runQA) { @@ -734,12 +735,14 @@ int main(int argc, char** argv) recAsync->SetDebugLevelTmp(configStandalone.proc.debugLevel); } chainTrackingAsync = recAsync->AddChain(); + chainTrackingAsync->SetQAFromForeignChain(chainTracking); } if (configStandalone.proc.doublePipeline) { if (configStandalone.proc.debugLevel >= 3) { recPipeline->SetDebugLevelTmp(configStandalone.proc.debugLevel); } chainTrackingPipeline = recPipeline->AddChain(); + chainTrackingPipeline->SetQAFromForeignChain(chainTracking); } #ifdef GPUCA_HAVE_O2HEADERS if (!configStandalone.proc.doublePipeline) { diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 33c267519470f..0ea5603c2efb2 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -373,11 +373,14 @@ int GPUChainTracking::Init() } if (GPUQA::QAAvailable() && (GetProcessingSettings().runQA || GetProcessingSettings().eventDisplay)) { - mQA.reset(new GPUQA(this)); + auto& qa = mQAFromForeignChain ? mQAFromForeignChain->mQA : mQA; + if (!qa) { + qa.reset(new GPUQA(this)); + } } if (GetProcessingSettings().eventDisplay) { #ifndef GPUCA_ALIROOT_LIB - mEventDisplay.reset(GPUDisplayInterface::getDisplay(GetProcessingSettings().eventDisplay, this, mQA.get())); + mEventDisplay.reset(GPUDisplayInterface::getDisplay(GetProcessingSettings().eventDisplay, this, GetQA())); #endif if (mEventDisplay == nullptr) { throw std::runtime_error("Error loading event display"); @@ -479,19 +482,21 @@ int GPUChainTracking::PrepareEvent() int GPUChainTracking::ForceInitQA() { - if (!mQA) { - mQA.reset(new GPUQA(this)); + auto& qa = mQAFromForeignChain ? mQAFromForeignChain->mQA : mQA; + if (!qa) { + qa.reset(new GPUQA(this)); } - if (!mQA->IsInitialized()) { - return mQA->InitQA(); + if (!GetQA()->IsInitialized()) { + return GetQA()->InitQA(); } return 0; } int GPUChainTracking::Finalize() { - if (GetProcessingSettings().runQA && mQA->IsInitialized() && !(mConfigQA && mConfigQA->shipToQC)) { - mQA->DrawQAHistograms(); + if (GetProcessingSettings().runQA && GetQA()->IsInitialized() && !(mConfigQA && mConfigQA->shipToQC) && !mQAFromForeignChain) { + GetQA()->UpdateChain(this); + GetQA()->DrawQAHistograms(); } if (GetProcessingSettings().debugLevel >= 6) { mDebugFile->close(); @@ -670,8 +675,8 @@ int GPUChainTracking::RunChain() mCompressionStatistics.reset(new GPUTPCClusterStatistics); } const bool needQA = GPUQA::QAAvailable() && (GetProcessingSettings().runQA || (GetProcessingSettings().eventDisplay && (mIOPtrs.nMCInfosTPC || GetProcessingSettings().runMC))); - if (needQA && mQA->IsInitialized() == false) { - if (mQA->InitQA(GetProcessingSettings().runQA ? -GetProcessingSettings().runQA : -1)) { + if (needQA && GetQA()->IsInitialized() == false) { + if (GetQA()->InitQA(GetProcessingSettings().runQA ? -GetProcessingSettings().runQA : -1)) { return 1; } } @@ -796,7 +801,8 @@ int GPUChainTracking::RunChainFinalize() const bool needQA = GPUQA::QAAvailable() && (GetProcessingSettings().runQA || (GetProcessingSettings().eventDisplay && mIOPtrs.nMCInfosTPC)); if (needQA && mFractionalQAEnabled) { mRec->getGeneralStepTimer(GeneralStep::QA).Start(); - mQA->RunQA(!GetProcessingSettings().runQA); + GetQA()->UpdateChain(this); + GetQA()->RunQA(!GetProcessingSettings().runQA); mRec->getGeneralStepTimer(GeneralStep::QA).Stop(); if (GetProcessingSettings().debugLevel == 0) { GPUInfo("Total QA runtime: %d us", (int)(mRec->getGeneralStepTimer(GeneralStep::QA).GetElapsedTime() * 1000000)); diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index 944a891e5c1f6..acdf9f7b446c2 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -156,9 +156,10 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega const GPUTPCGMMerger& GetTPCMerger() const { return processors()->tpcMerger; } GPUTPCGMMerger& GetTPCMerger() { return processors()->tpcMerger; } GPUDisplayInterface* GetEventDisplay() { return mEventDisplay.get(); } - const GPUQA* GetQA() const { return mQA.get(); } - GPUQA* GetQA() { return mQA.get(); } + const GPUQA* GetQA() const { return mQAFromForeignChain ? mQAFromForeignChain->mQA.get() : mQA.get(); } + GPUQA* GetQA() { return mQAFromForeignChain ? mQAFromForeignChain->mQA.get() : mQA.get(); } int ForceInitQA(); + void SetQAFromForeignChain(GPUChainTracking* chain) { mQAFromForeignChain = chain; } // Processing functions int RunTPCClusterizer(bool synchronizeOutput = true); @@ -254,6 +255,7 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega // Display / QA bool mDisplayRunning = false; std::unique_ptr mEventDisplay; + GPUChainTracking* mQAFromForeignChain = nullptr; std::unique_ptr mQA; std::unique_ptr mCompressionStatistics; diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index f2e91b633c7bf..2dd001725ee7f 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -80,6 +80,9 @@ int GPUO2Interface::Initialize(const GPUO2InterfaceConfiguration& config) } for (unsigned int i = 0; i < mNContexts; i++) { mCtx[i].mChain = mCtx[i].mRec->AddChain(mConfig->configInterface.maxTPCHits, mConfig->configInterface.maxTRDTracklets); + if (i) { + mCtx[i].mChain->SetQAFromForeignChain(mCtx[0].mChain); + } mCtx[i].mChain->mConfigDisplay = &mConfig->configDisplay; mCtx[i].mChain->mConfigQA = &mConfig->configQA; mCtx[i].mRec->SetSettings(&mConfig->configGRP, &mConfig->configReconstruction, &mConfig->configProcessing, &mConfig->configWorkflow); @@ -145,6 +148,7 @@ void GPUO2Interface::DumpEvent(int nEvent, GPUTrackingInOutPointers* data) if (mConfig->configProcessing.runMC) { mCtx[0].mChain->ForceInitQA(); snprintf(fname, 1024, "mc.%d.dump", nEvent); + mCtx[0].mChain->GetQA()->UpdateChain(mCtx[0].mChain); mCtx[0].mChain->GetQA()->DumpO2MCData(fname); } #endif diff --git a/GPU/GPUTracking/qa/GPUQA.h b/GPU/GPUTracking/qa/GPUQA.h index 0084c6dfff290..d5fef788c099c 100644 --- a/GPU/GPUTracking/qa/GPUQA.h +++ b/GPU/GPUTracking/qa/GPUQA.h @@ -113,6 +113,7 @@ class GPUQA int ReadO2MCData(const char* filename); static bool QAAvailable() { return true; } bool IsInitialized() { return mQAInitialized; } + void UpdateChain(GPUChainTracking* chain) { mTracking = chain; } const std::vector& getHistograms1D() const { return *mHist1D; } const std::vector& getHistograms2D() const { return *mHist2D; } From d40d422e524ab0c40fb40b998283ac3695e0afb8 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 25 Sep 2023 23:31:43 +0200 Subject: [PATCH 141/324] GPU SA MultiThreading: transfer SHM region id per pointer not per TF --- GPU/Workflow/src/GPUWorkflowPipeline.cxx | 65 +++++++++++++----------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/GPU/Workflow/src/GPUWorkflowPipeline.cxx b/GPU/Workflow/src/GPUWorkflowPipeline.cxx index 6b1f5764f8a9a..f564f1e5e6837 100644 --- a/GPU/Workflow/src/GPUWorkflowPipeline.cxx +++ b/GPU/Workflow/src/GPUWorkflowPipeline.cxx @@ -53,7 +53,6 @@ struct pipelinePrepareMessage { size_t magicWord = MAGIC_WORD; DataProcessingHeader::StartTime timeSliceId; GPUSettingsTF tfSettings; - fair::mq::RegionInfo regionInfo; size_t pointerCounts[GPUTrackingInOutZS::NSLICES][GPUTrackingInOutZS::NENDPOINTS]; size_t pointersTotal; bool flagEndOfStream; @@ -188,7 +187,7 @@ int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutP } } - size_t prepareBufferSize = sizeof(pipelinePrepareMessage) + ptrsTotal * sizeof(size_t) * 2; + size_t prepareBufferSize = sizeof(pipelinePrepareMessage) + ptrsTotal * sizeof(size_t) * 4; std::vector messageBuffer(prepareBufferSize / sizeof(size_t)); pipelinePrepareMessage& preMessage = *(pipelinePrepareMessage*)messageBuffer.data(); preMessage.magicWord = preMessage.MAGIC_WORD; @@ -197,28 +196,31 @@ int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutP preMessage.flagEndOfStream = false; memcpy((void*)&preMessage.tfSettings, (const void*)ptrs.settingsTF, sizeof(preMessage.tfSettings)); - if (ptrsTotal) { - bool regionFound = false; - for (unsigned int i = 0; i < mRegionInfos.size(); i++) { - if ((size_t)firstPtr >= (size_t)mRegionInfos[i].ptr && (size_t)firstPtr < (size_t)mRegionInfos[i].ptr + mRegionInfos[i].size) { - preMessage.regionInfo = mRegionInfos[i]; - regionFound = true; - break; - } - } - if (!regionFound) { - LOG(fatal) << "Found a TPC ZS pointer outside of shared memory"; - } - } - size_t* ptrBuffer = messageBuffer.data() + sizeof(preMessage) / sizeof(size_t); size_t ptrsCopied = 0; + int lastRegion = -1; for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { preMessage.pointerCounts[i][j] = ptrs.tpcZS->slice[i].count[j]; for (unsigned int k = 0; k < ptrs.tpcZS->slice[i].count[j]; k++) { - ptrBuffer[ptrsCopied + k] = (size_t)ptrs.tpcZS->slice[i].zsPtr[j][k] - (size_t)preMessage.regionInfo.ptr; + const void* curPtr = ptrs.tpcZS->slice[i].zsPtr[j][k]; + bool regionFound = lastRegion != -1 && (size_t)curPtr >= (size_t)mRegionInfos[lastRegion].ptr && (size_t)curPtr < (size_t)mRegionInfos[lastRegion].ptr + mRegionInfos[lastRegion].size; + if (!regionFound) { + for (unsigned int l = 0; l < mRegionInfos.size(); l++) { + if ((size_t)curPtr >= (size_t)mRegionInfos[l].ptr && (size_t)curPtr < (size_t)mRegionInfos[l].ptr + mRegionInfos[l].size) { + lastRegion = l; + regionFound = true; + break; + } + } + } + if (!regionFound) { + LOG(fatal) << "Found a TPC ZS pointer outside of shared memory"; + } + ptrBuffer[ptrsCopied + k] = (size_t)curPtr - (size_t)mRegionInfos[lastRegion].ptr; ptrBuffer[ptrsTotal + ptrsCopied + k] = ptrs.tpcZS->slice[i].nZSPtr[j][k]; + ptrBuffer[2 * ptrsTotal + ptrsCopied + k] = mRegionInfos[lastRegion].managed; + ptrBuffer[3 * ptrsTotal + ptrsCopied + k] = mRegionInfos[lastRegion].id; } ptrsCopied += ptrs.tpcZS->slice[i].count[j]; } @@ -316,26 +318,31 @@ void GPURecoWorkflowSpec::RunReceiveThread() context->timeSliceId = m->timeSliceId; context->tfSettings = m->tfSettings; - size_t regionOffset = 0; - if (m->pointersTotal) { - bool regionFound = false; - for (unsigned int i = 0; i < mRegionInfos.size(); i++) { - if (mRegionInfos[i].managed == m->regionInfo.managed && mRegionInfos[i].id == m->regionInfo.id) { - regionFound = true; - regionOffset = (size_t)mRegionInfos[i].ptr; - break; - } - } - } size_t ptrsCopied = 0; size_t* ptrBuffer = (size_t*)msg->GetData() + sizeof(pipelinePrepareMessage) / sizeof(size_t); context->tpcZSmeta.Pointers[0][0].resize(m->pointersTotal); context->tpcZSmeta.Sizes[0][0].resize(m->pointersTotal); + int lastRegion = -1; for (unsigned int i = 0; i < GPUTrackingInOutZS::NSLICES; i++) { for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { context->tpcZS.slice[i].count[j] = m->pointerCounts[i][j]; for (unsigned int k = 0; k < context->tpcZS.slice[i].count[j]; k++) { - context->tpcZSmeta.Pointers[0][0][ptrsCopied + k] = (void*)(ptrBuffer[ptrsCopied + k] + regionOffset); + bool regionManaged = ptrBuffer[2 * m->pointersTotal + ptrsCopied + k]; + size_t regionId = ptrBuffer[3 * m->pointersTotal + ptrsCopied + k]; + bool regionFound = lastRegion != -1 && mRegionInfos[lastRegion].managed == regionManaged && mRegionInfos[lastRegion].id == regionId; + if (!regionFound) { + for (unsigned int l = 0; l < mRegionInfos.size(); l++) { + if (mRegionInfos[l].managed == regionManaged && mRegionInfos[l].id == regionId) { + lastRegion = l; + regionFound = true; + break; + } + } + } + if (!regionFound) { + LOG(fatal) << "Received ZS Ptr for SHM region (managed " << (int)regionManaged << ", id " << regionId << "), which was not registered for us"; + } + context->tpcZSmeta.Pointers[0][0][ptrsCopied + k] = (void*)(ptrBuffer[ptrsCopied + k] + (size_t)mRegionInfos[lastRegion].ptr); context->tpcZSmeta.Sizes[0][0][ptrsCopied + k] = ptrBuffer[m->pointersTotal + ptrsCopied + k]; } context->tpcZS.slice[i].zsPtr[j] = context->tpcZSmeta.Pointers[0][0].data() + ptrsCopied; From f3b42066a473f00f2ac54c7225bda95da053dac2 Mon Sep 17 00:00:00 2001 From: Ruben Shahoyan Date: Tue, 26 Sep 2023 09:21:52 +0200 Subject: [PATCH 142/324] Suppres duplicate matches from ITS track clones on sector edges (#11958) Co-authored-by: shahoian --- .../include/GlobalTracking/MatchTPCITS.h | 7 +++++ Detectors/GlobalTracking/src/MatchTPCITS.cxx | 31 ++++++++++++++----- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h index 16c8051f45d5a..7dc23b0af84de 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h @@ -142,10 +142,17 @@ struct TrackLocTPC : public o2::track::TrackParCov { ///< ITS track outward parameters propagated to reference X, with time bracket and index of ///< original track in the currently loaded ITS reco output struct TrackLocITS : public o2::track::TrackParCov { + enum : uint16_t { CloneBefore = 0x1, + CloneAfter = 0x2 }; o2::math_utils::Bracketf_t tBracket; ///< bracketing time in \mus int sourceID = 0; ///< track origin id int roFrame = MinusOne; ///< ITS readout frame assigned to this track int matchID = MinusOne; ///< entry (non if MinusOne) of its matchCand struct in the mMatchesITS + bool hasCloneBefore() const { return getUserField() & CloneBefore; } + bool hasCloneAfter() const { return getUserField() & CloneAfter; } + int getCloneShift() const { return hasCloneBefore() ? -1 : (hasCloneAfter() ? 1 : 0); } + void setCloneBefore() { setUserField(getUserField() | CloneBefore); } + void setCloneAfter() { setUserField(getUserField() | CloneAfter); } ClassDefNV(TrackLocITS, 1); }; diff --git a/Detectors/GlobalTracking/src/MatchTPCITS.cxx b/Detectors/GlobalTracking/src/MatchTPCITS.cxx index c913571038129..32ee299bf6a64 100644 --- a/Detectors/GlobalTracking/src/MatchTPCITS.cxx +++ b/Detectors/GlobalTracking/src/MatchTPCITS.cxx @@ -264,7 +264,6 @@ void MatchTPCITS::selectBestMatches() ///< loop over match records and select the ones with best chi2 mTimer[SWSelectBest].Start(false); int nValidated = 0, iter = 0, nValidatedTotal = 0; - do { nValidated = 0; int ntpc = mTPCWork.size(), nremaining = 0; @@ -295,12 +294,6 @@ bool MatchTPCITS::validateTPCMatch(int iTPC) { const auto& tTPC = mTPCWork[iTPC]; auto& rcTPC = mMatchRecordsTPC[tTPC.matchID]; // best TPC->ITS match - /* // should never happen - if (rcTPC.nextRecID == Validated) { - LOG(warning) << "TPC->ITS was already validated"; - return false; // RS do we need this - } - */ // check if it is consistent with corresponding ITS->TPC match auto& tITS = mITSWork[rcTPC.partnerID]; // partner ITS track auto& rcITS = mMatchRecordsITS[tITS.matchID]; // best ITS->TPC match record @@ -308,6 +301,26 @@ bool MatchTPCITS::validateTPCMatch(int iTPC) return false; } if (rcITS.partnerID == iTPC) { // is best matching TPC track for this ITS track actually iTPC? + int cloneID = tITS.getCloneShift(); // check if there is a clone of tITS + while (cloneID) { + cloneID += rcTPC.partnerID; + auto& tITSClone = mITSWork[cloneID]; + if (isDisabledITS(tITSClone)) { // ignore clone + break; + } + int nextITSCloneMatchID = tITSClone.matchID; + if (rcITS.isBetter(mMatchRecordsITS[nextITSCloneMatchID])) { // best ITS->TPC match record for the clone is worse than the rcITS + LOGP(debug, "Suppressing clone cloneID={} of winner clone {} of source ITS {}", cloneID, rcTPC.partnerID, tITS.sourceID); + while (nextITSCloneMatchID > MinusOne) { + auto& rcITSClone = mMatchRecordsITS[nextITSCloneMatchID]; + removeITSfromTPC(cloneID, rcITSClone.partnerID); + nextITSCloneMatchID = rcITSClone.nextRecID; + } + tITSClone.matchID = MinusTen; // disable + break; + } + return false; // ignore match at this iteration + } // unlink winner TPC track from all ITS candidates except winning one int nextTPC = rcTPC.nextRecID; while (nextTPC > MinusOne) { @@ -1148,6 +1161,9 @@ void MatchTPCITS::addLastTrackCloneForNeighbourSector(int sector) o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, mParams->XMatchingRef, MaxSnp, 2., MatCorrType::USEMatCorrNONE)) { // TODO: use faster prop here, no 3d field, materials mITSSectIndexCache[sector].push_back(mITSWork.size() - 1); // register track CLONE + // flag clone + mITSWork.back().setCloneBefore(); + mITSWork[mITSWork.size() - 2].setCloneAfter(); if (mMCTruthON) { mITSLblWork.emplace_back(mITSTrkLabels[trc.sourceID]); } @@ -1265,6 +1281,7 @@ bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS) mMatchedTracks.emplace_back(tTPC, tITS); // create a copy of TPC track at xRef auto& trfit = mMatchedTracks.back(); + trfit.getParamOut().setUserField(0); // reset eventual clones flag // in continuos mode the Z of TPC track is meaningless, unless it is CE crossing // track (currently absent, TODO) if (!mCompareTracksDZ) { From 15be311c5dd9d687edd4b25c368d99b9e134c88b Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Mon, 25 Sep 2023 18:15:27 +0200 Subject: [PATCH 143/324] [EMCAL-1044] Sort towers in DDL according to FEC ID Channels must be sorted according to FEC ID as the ALTRO decoder now makes used of channel ordering to find corrupted channels --- .../include/EMCALSimulation/RawWriter.h | 12 ++++++ Detectors/EMCAL/simulation/src/RawWriter.cxx | 37 +++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h index 91c534c3ba82b..4388035215d4f 100644 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h @@ -191,6 +191,18 @@ class RawWriter /// The input data is converted to 10 but ALTRO words and put on the stream. std::vector encodeBunchData(const std::vector& data); + /// \brief Extracting branch index from the hardware address + /// \param hwaddress Hardware address of the channel + int getBranchIndexFromHwAddress(int hwaddress) { return ((hwaddress >> 11) & 0x1); } + + /// \brief Extracting FEC index in branch from the hardware address + /// \param hwaddress Hardware address of the channel + int getFecIndexFromHwAddress(int hwaddress) { return ((hwaddress >> 7) & 0xF); } + + /// \brief Extracting Channel index in FEC from the hardware address + /// \param hwaddress Hardware address of the channel + int getChannelIndexFromHwAddress(int hwaddress) { return (hwaddress & 0xF); } + private: int mNADCSamples = 15; ///< Number of time samples int mPedestal = 1; ///< Pedestal diff --git a/Detectors/EMCAL/simulation/src/RawWriter.cxx b/Detectors/EMCAL/simulation/src/RawWriter.cxx index e289b9bfbca6e..14c32c0e299ae 100644 --- a/Detectors/EMCAL/simulation/src/RawWriter.cxx +++ b/Detectors/EMCAL/simulation/src/RawWriter.cxx @@ -9,6 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include + #include #include @@ -127,12 +129,39 @@ bool RawWriter::processTrigger(const o2::emcal::TriggerRecord& trg) continue; } + // sort found towers according to FEC inside + // within the FEC channels are also sorted according + // their local channel ID + std::map> fecSortedTowersWithSignal; + auto& mappingDDL = mMappingHandler->getMappingForDDL(srucont.mSRUid); for (const auto& [tower, channel] : srucont.mChannels) { - bool saturatedBunchHG = false; - createPayload(channel, ChannelType_t::HIGH_GAIN, srucont.mSRUid, payload, saturatedBunchHG); - if (saturatedBunchHG) { - createPayload(channel, ChannelType_t::LOW_GAIN, srucont.mSRUid, payload, saturatedBunchHG); + auto hwaddress = mappingDDL.getHardwareAddress(channel.mRow, channel.mCol, ChannelType_t::HIGH_GAIN); + auto fecInDLL = getBranchIndexFromHwAddress(hwaddress) * 10 + getFecIndexFromHwAddress(hwaddress); + auto channelID = getChannelIndexFromHwAddress(hwaddress); + auto fecFound = fecSortedTowersWithSignal.find(fecInDLL); + if (fecFound != fecSortedTowersWithSignal.end()) { + fecFound->second[channelID] = tower; + } else { + std::map channelsInFec; + channelsInFec[channelID] = tower; + fecSortedTowersWithSignal[fecInDLL] = channelsInFec; + } + } + + // encode payload for sorted channels + for (const auto& [fec, channelsInFec] : fecSortedTowersWithSignal) { + for (auto [channelID, tower] : channelsInFec) { + auto towerChannel = srucont.mChannels.find(tower); + if (towerChannel != srucont.mChannels.end()) { + bool saturatedBunchHG = false; + createPayload(towerChannel->second, ChannelType_t::HIGH_GAIN, srucont.mSRUid, payload, saturatedBunchHG); + if (saturatedBunchHG) { + createPayload(towerChannel->second, ChannelType_t::LOW_GAIN, srucont.mSRUid, payload, saturatedBunchHG); + } + } else { + LOG(error) << "No data found for FEC " << fec << ", channel " << channelID << "(tower " << tower << ")"; + } } } From 3b6525c2c2deb52b0973fd4b0b7876f4ddd963a9 Mon Sep 17 00:00:00 2001 From: syano0822 Date: Tue, 26 Sep 2023 21:57:29 +0900 Subject: [PATCH 144/324] Add the noise map clear function in Detectors/ITSMFT/MFT/condition/src/DCSConfigReader.cxx/.h --- .../MFT/condition/include/MFTCondition/DCSConfigReader.h | 1 + Detectors/ITSMFT/MFT/condition/src/DCSConfigReader.cxx | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/Detectors/ITSMFT/MFT/condition/include/MFTCondition/DCSConfigReader.h b/Detectors/ITSMFT/MFT/condition/include/MFTCondition/DCSConfigReader.h index c18094674ba74..ba5b8d9e1c26b 100644 --- a/Detectors/ITSMFT/MFT/condition/include/MFTCondition/DCSConfigReader.h +++ b/Detectors/ITSMFT/MFT/condition/include/MFTCondition/DCSConfigReader.h @@ -38,6 +38,7 @@ class DCSConfigReader void init(bool); void loadConfig(gsl::span configBuf); // load MFT config void clear(); + void clearDeadmap(); const std::vector& getConfigInfo() const { return mDCSConfig; } const o2::itsmft::NoiseMap& getNoiseMap() const { return mNoiseMap; } diff --git a/Detectors/ITSMFT/MFT/condition/src/DCSConfigReader.cxx b/Detectors/ITSMFT/MFT/condition/src/DCSConfigReader.cxx index 58a91edb140ee..97f353cb0f140 100644 --- a/Detectors/ITSMFT/MFT/condition/src/DCSConfigReader.cxx +++ b/Detectors/ITSMFT/MFT/condition/src/DCSConfigReader.cxx @@ -39,10 +39,19 @@ void DCSConfigReader::clear() mDCSConfig.clear(); } +void DCSConfigReader::clearDeadmap() +{ + for (int iChip = 0; iChip < 936; ++iChip) { + mNoiseMap.resetChip(iChip); + } +} + //_______________________________________________________________ void DCSConfigReader::parseConfig() { + clearDeadmap(); + char delimiter_newline = '\n'; char delimiter = ','; From 702e4705e1f9a9fffa3f0ea34ec2f05e39acd532 Mon Sep 17 00:00:00 2001 From: frmanso Date: Wed, 20 Sep 2023 14:02:41 +0200 Subject: [PATCH 145/324] Removing overlaps of carbon plates --- .../ITSMFT/MFT/base/src/HeatExchanger.cxx | 4840 ++++++++++++----- 1 file changed, 3447 insertions(+), 1393 deletions(-) diff --git a/Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx b/Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx index ced7476d020f3..99b42f6102ae9 100644 --- a/Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx +++ b/Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx @@ -1,6 +1,6 @@ // Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright +// holders. All rights not expressly granted are reserved. // // This software is distributed under the terms of the GNU General Public // License v3 (GPL Version 3), copied verbatim in the file "COPYING". @@ -13,20 +13,20 @@ /// \brief Class building the MFT heat exchanger /// \author P. Demongodin, and Raphael Tieulent -#include "TMath.h" -#include "TGeoManager.h" +#include "MFTBase/HeatExchanger.h" +#include "MFTBase/Constants.h" +#include "MFTBase/Geometry.h" +#include "MFTBase/MFTBaseParam.h" +#include "TGeoBBox.h" +#include "TGeoBoolNode.h" #include "TGeoCompositeShape.h" -#include "TGeoTube.h" -#include "TGeoTorus.h" #include "TGeoCone.h" -#include "TGeoBoolNode.h" -#include "TGeoBBox.h" +#include "TGeoManager.h" +#include "TGeoTorus.h" +#include "TGeoTube.h" #include "TGeoVolume.h" +#include "TMath.h" #include -#include "MFTBase/Constants.h" -#include "MFTBase/HeatExchanger.h" -#include "MFTBase/Geometry.h" -#include "MFTBase/MFTBaseParam.h" using namespace o2::mft; @@ -34,57 +34,15 @@ ClassImp(o2::mft::HeatExchanger); //_____________________________________________________________________________ HeatExchanger::HeatExchanger() - : mHalfDisk(nullptr), - mHalfDiskRotation(nullptr), - mHalfDiskTransformation(nullptr), - mRWater(0.), - mDRPipe(0.), - mHeatExchangerThickness(0.), - mCarbonThickness(0.), - mHalfDiskGap(0.), - mRohacellThickness(0.), - mNPart(), - mRMin(), - mZPlan(), - mSupportXDimensions(), - mSupportYDimensions(), - mLWater0(), - mXPosition0(), - mAngle0(), - mRadius0(), - mLpartial0(), - mLWater1(), - mXPosition1(), - mAngle1(), - mRadius1(), - mLpartial1(), - mLWater2(), - mXPosition2(), - mAngle2(), - mRadius2(), - mLpartial2(), - mLWater3(), - mXPosition3(), - mAngle3(), - mRadius3(), - mLpartial3(), - mRadius3fourth(), - mAngle3fourth(), - mBeta3fourth(), - mLWater4(), - mXPosition4(), - mAngle4(), - mRadius4(), - mLpartial4(), - mAngle4fifth(), - mRadius4fifth() + : mHalfDisk(nullptr), mHalfDiskRotation(nullptr), mHalfDiskTransformation(nullptr), mRWater(0.), mDRPipe(0.), mHeatExchangerThickness(0.), mCarbonThickness(0.), mHalfDiskGap(0.), mRohacellThickness(0.), mNPart(), mRMin(), mZPlan(), mSupportXDimensions(), mSupportYDimensions(), mLWater0(), mXPosition0(), mAngle0(), mRadius0(), mLpartial0(), mLWater1(), mXPosition1(), mAngle1(), mRadius1(), mLpartial1(), mLWater2(), mXPosition2(), mAngle2(), mRadius2(), mLpartial2(), mLWater3(), mXPosition3(), mAngle3(), mRadius3(), mLpartial3(), mRadius3fourth(), mAngle3fourth(), mBeta3fourth(), mLWater4(), mXPosition4(), mAngle4(), mRadius4(), mLpartial4(), mAngle4fifth(), mRadius4fifth() { auto& mftBaseParam = MFTBaseParam::Instance(); mRWater = 0.1 / 2.; // water pipe diameter 1 mm mDRPipe = 0.0025; // water pipe thickness 25 microns - // for the chips aligment --> decrease of the HE thickness then increase of the rohacell density + // for the chips aligment --> decrease of the HE thickness then increase of + // the rohacell density Double_t decreaseHE = 0.0; if (mftBaseParam.buildAlignment) { decreaseHE = 0.4; @@ -95,51 +53,10 @@ HeatExchanger::HeatExchanger() } //_____________________________________________________________________________ -HeatExchanger::HeatExchanger(Double_t rWater, Double_t dRPipe, Double_t heatExchangerThickness, +HeatExchanger::HeatExchanger(Double_t rWater, Double_t dRPipe, + Double_t heatExchangerThickness, Double_t carbonThickness) - : mHalfDisk(nullptr), - mHalfDiskRotation(nullptr), - mHalfDiskTransformation(nullptr), - mRWater(rWater), - mDRPipe(dRPipe), - mHeatExchangerThickness(heatExchangerThickness), - mCarbonThickness(carbonThickness), - mHalfDiskGap(0.), - mRohacellThickness(0.), - mNPart(), - mRMin(), - mZPlan(), - mSupportXDimensions(), - mSupportYDimensions(), - mXPosition0(), - mAngle0(), - mRadius0(), - mLpartial0(), - mLWater1(), - mXPosition1(), - mAngle1(), - mRadius1(), - mLpartial1(), - mLWater2(), - mXPosition2(), - mAngle2(), - mRadius2(), - mLpartial2(), - mLWater3(), - mXPosition3(), - mAngle3(), - mRadius3(), - mLpartial3(), - mRadius3fourth(), - mAngle3fourth(), - mBeta3fourth(), - mLWater4(), - mXPosition4(), - mAngle4(), - mRadius4(), - mLpartial4(), - mAngle4fifth(), - mRadius4fifth() + : mHalfDisk(nullptr), mHalfDiskRotation(nullptr), mHalfDiskTransformation(nullptr), mRWater(rWater), mDRPipe(dRPipe), mHeatExchangerThickness(heatExchangerThickness), mCarbonThickness(carbonThickness), mHalfDiskGap(0.), mRohacellThickness(0.), mNPart(), mRMin(), mZPlan(), mSupportXDimensions(), mSupportYDimensions(), mXPosition0(), mAngle0(), mRadius0(), mLpartial0(), mLWater1(), mXPosition1(), mAngle1(), mRadius1(), mLpartial1(), mLWater2(), mXPosition2(), mAngle2(), mRadius2(), mLpartial2(), mLWater3(), mXPosition3(), mAngle3(), mRadius3(), mLpartial3(), mRadius3fourth(), mAngle3fourth(), mBeta3fourth(), mLWater4(), mXPosition4(), mAngle4(), mRadius4(), mLpartial4(), mAngle4fifth(), mRadius4fifth() { initParameters(); } @@ -257,27 +174,55 @@ void HeatExchanger::createManifold(Int_t disk) Double_t lengthBottom1; lengthBottom1 = lengthMiddle1[disk]; - auto* Top1 = new TGeoBBox(Form("Top1MF%d", disk), lengthTop1[disk] / 2, widthTop1[disk] / 2, thicknessTop[disk] / 2); - auto* Top2 = new TGeoBBox(Form("Top2MF%d", disk), lengthTop2 / 2, widthTop2 / 2, thicknessTop[disk] / 2); - auto* Top3 = new TGeoTube(Form("Top3MF%d", disk), 0, cornerRadiusTop[disk], thicknessTop[disk] / 2); - auto* Middle1 = new TGeoBBox(Form("Middle1MF%d", disk), lengthMiddle1[disk] / 2, widthMiddle1[disk] / 2, thicknessMiddle[disk] / 2); - auto* Bottom1 = new TGeoBBox(Form("Bottom1MF%d", disk), lengthBottom1 / 2, widthBottom1[disk] / 2, thicknessBottom[disk] / 2); + auto* Top1 = new TGeoBBox(Form("Top1MF%d", disk), lengthTop1[disk] / 2, + widthTop1[disk] / 2, thicknessTop[disk] / 2); + auto* Top2 = new TGeoBBox(Form("Top2MF%d", disk), lengthTop2 / 2, + widthTop2 / 2, thicknessTop[disk] / 2); + auto* Top3 = new TGeoTube(Form("Top3MF%d", disk), 0, cornerRadiusTop[disk], + thicknessTop[disk] / 2); + auto* Middle1 = + new TGeoBBox(Form("Middle1MF%d", disk), lengthMiddle1[disk] / 2, + widthMiddle1[disk] / 2, thicknessMiddle[disk] / 2); + auto* Bottom1 = + new TGeoBBox(Form("Bottom1MF%d", disk), lengthBottom1 / 2, + widthBottom1[disk] / 2, thicknessBottom[disk] / 2); TGeoTranslation* tTop[7]; - tTop[0] = new TGeoTranslation(Form("tTop1MF%d", disk), 0., 0., thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); - tTop[1] = new TGeoTranslation(Form("tTop2MF%d", disk), lengthTop1[disk] / 2 + lengthTop2 / 2, 0., thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); - tTop[2] = new TGeoTranslation(Form("tTop3MF%d", disk), lengthTop1[disk] / 2, widthTop1[disk] / 2 - cornerRadiusTop[disk], thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); - tTop[3] = new TGeoTranslation(Form("tTop4MF%d", disk), lengthTop1[disk] / 2, -(widthTop1[disk] / 2 - cornerRadiusTop[disk]), thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); - tTop[4] = new TGeoTranslation(Form("tTop5MF%d", disk), -(lengthTop1[disk] / 2 + lengthTop2 / 2), 0., thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); - tTop[5] = new TGeoTranslation(Form("tTop6MF%d", disk), -lengthTop1[disk] / 2, widthTop1[disk] / 2 - cornerRadiusTop[disk], thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); - tTop[6] = new TGeoTranslation(Form("tTop7MF%d", disk), -lengthTop1[disk] / 2, -(widthTop1[disk] / 2 - cornerRadiusTop[disk]), thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); + tTop[0] = + new TGeoTranslation(Form("tTop1MF%d", disk), 0., 0., + thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); + tTop[1] = new TGeoTranslation( + Form("tTop2MF%d", disk), lengthTop1[disk] / 2 + lengthTop2 / 2, 0., + thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); + tTop[2] = + new TGeoTranslation(Form("tTop3MF%d", disk), lengthTop1[disk] / 2, + widthTop1[disk] / 2 - cornerRadiusTop[disk], + thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); + tTop[3] = + new TGeoTranslation(Form("tTop4MF%d", disk), lengthTop1[disk] / 2, + -(widthTop1[disk] / 2 - cornerRadiusTop[disk]), + thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); + tTop[4] = new TGeoTranslation( + Form("tTop5MF%d", disk), -(lengthTop1[disk] / 2 + lengthTop2 / 2), 0., + thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); + tTop[5] = + new TGeoTranslation(Form("tTop6MF%d", disk), -lengthTop1[disk] / 2, + widthTop1[disk] / 2 - cornerRadiusTop[disk], + thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); + tTop[6] = + new TGeoTranslation(Form("tTop7MF%d", disk), -lengthTop1[disk] / 2, + -(widthTop1[disk] / 2 - cornerRadiusTop[disk]), + thicknessMiddle[disk] / 2 + thicknessTop[disk] / 2); for (Int_t i = 0; i < 7; ++i) { tTop[i]->RegisterYourself(); } - TGeoTranslation* tMiddle1 = new TGeoTranslation(Form("tMiddle1MF%d", disk), 0, 0, 0); - TGeoTranslation* tBottom1 = new TGeoTranslation(Form("tBottom1MF%d", disk), 0, 0, -(thicknessMiddle[disk] / 2 + thicknessBottom[disk] / 2)); + TGeoTranslation* tMiddle1 = + new TGeoTranslation(Form("tMiddle1MF%d", disk), 0, 0, 0); + TGeoTranslation* tBottom1 = new TGeoTranslation( + Form("tBottom1MF%d", disk), 0, 0, + -(thicknessMiddle[disk] / 2 + thicknessBottom[disk] / 2)); tMiddle1->RegisterYourself(); tBottom1->RegisterYourself(); @@ -302,17 +247,28 @@ void HeatExchanger::createManifold(Int_t disk) lengthPipeHole1[3] = 0.95; lengthPipeHole1[4] = 0.95; - Double_t lengthPipeHole2 = (thicknessTop[disk] + thicknessMiddle[disk] + thicknessBottom[disk]) - lengthPipeHole1[disk]; - - TGeoTube* Pipe1 = new TGeoTube("Pipe1", 0, radiusPipeHole1[disk], lengthPipeHole1[disk] / 2 + Geometry::sEpsilon); - TGeoCone* Pipe2 = new TGeoCone("Pipe2", lengthPipeHole2 / 2 + Geometry::sEpsilon, 0, radiusPipeHole1[disk], 0, radiusPipeHole2[disk]); - - TGeoTranslation* tPipePart1 = new TGeoTranslation(Form("tPipePart1MF%d", disk), 0, 0, 0); - TGeoTranslation* tPipePart2 = new TGeoTranslation(Form("tPipePart2MF%d", disk), 0, 0, lengthPipeHole1[disk] / 2 + lengthPipeHole2 / 2); + Double_t lengthPipeHole2 = + (thicknessTop[disk] + thicknessMiddle[disk] + thicknessBottom[disk]) - + lengthPipeHole1[disk]; + + TGeoTube* Pipe1 = + new TGeoTube("Pipe1", 0, radiusPipeHole1[disk], + lengthPipeHole1[disk] / 2 + Geometry::sEpsilon); + TGeoCone* Pipe2 = + new TGeoCone("Pipe2", lengthPipeHole2 / 2 + Geometry::sEpsilon, 0, + radiusPipeHole1[disk], 0, radiusPipeHole2[disk]); + + TGeoTranslation* tPipePart1 = + new TGeoTranslation(Form("tPipePart1MF%d", disk), 0, 0, 0); + TGeoTranslation* tPipePart2 = + new TGeoTranslation(Form("tPipePart2MF%d", disk), 0, 0, + lengthPipeHole1[disk] / 2 + lengthPipeHole2 / 2); tPipePart1->RegisterYourself(); tPipePart2->RegisterYourself(); - TGeoCompositeShape* shapePipe = new TGeoCompositeShape(Form("shapePipeMF%d", disk), Form("Pipe1:tPipePart1MF%d + Pipe2:tPipePart2MF%d", disk, disk)); + TGeoCompositeShape* shapePipe = new TGeoCompositeShape( + Form("shapePipeMF%d", disk), + Form("Pipe1:tPipePart1MF%d + Pipe2:tPipePart2MF%d", disk, disk)); Int_t nPipeRow[5]; nPipeRow[0] = 3; @@ -323,7 +279,8 @@ void HeatExchanger::createManifold(Int_t disk) TGeoTranslation* tPipe; - // The lengthBulge is a parameter for manifold2. This is required to tune the water pipe position. + // The lengthBulge is a parameter for manifold2. This is required to tune the + // water pipe position. Double_t lengthBulge[5]; lengthBulge[0] = 0.395; lengthBulge[1] = 0.395; @@ -355,19 +312,38 @@ void HeatExchanger::createManifold(Int_t disk) offsetPipeRow[4][3] = mXPosition4[3] - lengthBulge[4] / 2; offsetPipeRow[4][4] = mXPosition4[4] - lengthBulge[4] / 2; - Double_t deltaz = mHeatExchangerThickness - Geometry::sKaptonOnCarbonThickness * 4 - 2 * mCarbonThickness; + Double_t deltaz = mHeatExchangerThickness - + Geometry::sKaptonOnCarbonThickness * 4 - + 2 * mCarbonThickness; Double_t lengthTwoPipeCol[5]; - lengthTwoPipeCol[0] = mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - 2 * Geometry::sGlueRohacellCarbonThickness - 2 * Geometry::sKaptonOnCarbonThickness; - lengthTwoPipeCol[1] = mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - 2 * Geometry::sGlueRohacellCarbonThickness - 2 * Geometry::sKaptonOnCarbonThickness; - lengthTwoPipeCol[2] = mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - 2 * Geometry::sGlueRohacellCarbonThickness - 2 * Geometry::sKaptonOnCarbonThickness; - lengthTwoPipeCol[3] = mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - 2 * Geometry::sGlueRohacellCarbonThickness - 2 * Geometry::sKaptonOnCarbonThickness; - lengthTwoPipeCol[4] = mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - 2 * Geometry::sGlueRohacellCarbonThickness - 2 * Geometry::sKaptonOnCarbonThickness; + lengthTwoPipeCol[0] = mZPlan[disk] + deltaz / 2. - mCarbonThickness - + mRWater - mDRPipe - + 2 * Geometry::sGlueRohacellCarbonThickness - + 2 * Geometry::sKaptonOnCarbonThickness; + lengthTwoPipeCol[1] = mZPlan[disk] + deltaz / 2. - mCarbonThickness - + mRWater - mDRPipe - + 2 * Geometry::sGlueRohacellCarbonThickness - + 2 * Geometry::sKaptonOnCarbonThickness; + lengthTwoPipeCol[2] = mZPlan[disk] + deltaz / 2. - mCarbonThickness - + mRWater - mDRPipe - + 2 * Geometry::sGlueRohacellCarbonThickness - + 2 * Geometry::sKaptonOnCarbonThickness; + lengthTwoPipeCol[3] = mZPlan[disk] + deltaz / 2. - mCarbonThickness - + mRWater - mDRPipe - + 2 * Geometry::sGlueRohacellCarbonThickness - + 2 * Geometry::sKaptonOnCarbonThickness; + lengthTwoPipeCol[4] = mZPlan[disk] + deltaz / 2. - mCarbonThickness - + mRWater - mDRPipe - + 2 * Geometry::sGlueRohacellCarbonThickness - + 2 * Geometry::sKaptonOnCarbonThickness; TString namePipe = ""; for (Int_t iPipeRow = 0; iPipeRow < nPipeRow[disk]; iPipeRow++) { - tPipe = new TGeoTranslation(Form("tPipe%dMF%d", iPipeRow + 1, disk), lengthMiddle1[disk] / 2 - offsetPipeRow[disk][iPipeRow], 0, 0); + tPipe = new TGeoTranslation( + Form("tPipe%dMF%d", iPipeRow + 1, disk), + lengthMiddle1[disk] / 2 - offsetPipeRow[disk][iPipeRow], 0, 0); tPipe->RegisterYourself(); if (iPipeRow == nPipeRow[disk] - 1) { @@ -377,22 +353,45 @@ void HeatExchanger::createManifold(Int_t disk) } } - TGeoCompositeShape* posiPipeOneCol = new TGeoCompositeShape(Form("posiPipeOneColMF%d", disk), namePipe); + TGeoCompositeShape* posiPipeOneCol = + new TGeoCompositeShape(Form("posiPipeOneColMF%d", disk), namePipe); - tPipe = new TGeoTranslation(Form("tPipeLeftMF%d", disk), 0, -lengthTwoPipeCol[disk], 0); + tPipe = new TGeoTranslation(Form("tPipeLeftMF%d", disk), 0, + -lengthTwoPipeCol[disk], 0); tPipe->RegisterYourself(); - tPipe = new TGeoTranslation(Form("tPipeRightMF%d", disk), 0, lengthTwoPipeCol[disk], 0); + tPipe = new TGeoTranslation(Form("tPipeRightMF%d", disk), 0, + lengthTwoPipeCol[disk], 0); tPipe->RegisterYourself(); - TGeoCompositeShape* shapePipes = new TGeoCompositeShape(Form("shapePipesMF%d", disk), Form("posiPipeOneColMF%d:tPipeLeftMF%d + posiPipeOneColMF%d:tPipeRightMF%d", disk, disk, disk, disk)); - TGeoCompositeShape* shapeBase = new TGeoCompositeShape(Form("shapeBaseMF%d", disk), Form("Top1MF%d:tTop1MF%d + Top2MF%d:tTop2MF%d + Top3MF%d:tTop3MF%d + Top3MF%d:tTop4MF%d + Top2MF%d:tTop5MF%d + Top3MF%d:tTop6MF%d + Top3MF%d:tTop7MF%d + Middle1MF%d:tMiddle1MF%d + Bottom1MF%d:tBottom1MF%d", disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk)); - - TGeoTranslation* tBase = new TGeoTranslation(Form("tBaseMF%d", disk), 0, 0, -((thicknessTop[disk] + thicknessMiddle[disk] + thicknessBottom[disk]) / 2 - (thicknessBottom[disk] + thicknessMiddle[disk] / 2))); + TGeoCompositeShape* shapePipes = new TGeoCompositeShape( + Form("shapePipesMF%d", disk), Form("posiPipeOneColMF%d:tPipeLeftMF%d + " + "posiPipeOneColMF%d:tPipeRightMF%d", + disk, disk, disk, disk)); + TGeoCompositeShape* shapeBase = new TGeoCompositeShape( + Form("shapeBaseMF%d", disk), + Form("Top1MF%d:tTop1MF%d + Top2MF%d:tTop2MF%d + Top3MF%d:tTop3MF%d + " + "Top3MF%d:tTop4MF%d + Top2MF%d:tTop5MF%d + Top3MF%d:tTop6MF%d + " + "Top3MF%d:tTop7MF%d + Middle1MF%d:tMiddle1MF%d + " + "Bottom1MF%d:tBottom1MF%d", + disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, + disk, disk, disk, disk, disk, disk, disk)); + + TGeoTranslation* tBase = new TGeoTranslation( + Form("tBaseMF%d", disk), 0, 0, + -((thicknessTop[disk] + thicknessMiddle[disk] + thicknessBottom[disk]) / + 2 - + (thicknessBottom[disk] + thicknessMiddle[disk] / 2))); tBase->RegisterYourself(); - TGeoTranslation* tPipes = new TGeoTranslation(Form("tPiesMF%d", disk), 0, 0, -((lengthPipeHole1[disk] + lengthPipeHole2) / 2 - lengthPipeHole1[disk] / 2)); + TGeoTranslation* tPipes = + new TGeoTranslation(Form("tPiesMF%d", disk), 0, 0, + -((lengthPipeHole1[disk] + lengthPipeHole2) / 2 - + lengthPipeHole1[disk] / 2)); tPipes->RegisterYourself(); - TGeoCompositeShape* shapeManifold1 = new TGeoCompositeShape(Form("shapeManifold1MF%d", disk), Form("shapeBaseMF%d:tBaseMF%d - shapePipesMF%d:tPiesMF%d", disk, disk, disk, disk)); + TGeoCompositeShape* shapeManifold1 = new TGeoCompositeShape( + Form("shapeManifold1MF%d", disk), + Form("shapeBaseMF%d:tBaseMF%d - shapePipesMF%d:tPiesMF%d", disk, disk, + disk, disk)); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Manifold2 @@ -438,33 +437,67 @@ void HeatExchanger::createManifold(Int_t disk) thicknessBodyBathtub2[3] = 0.4; thicknessBodyBathtub2[4] = 0.4; - auto* coverBody1 = new TGeoBBox(Form("coverBody1MF%d", disk), lengthBody / 2, widthBody / 2, thicknessBody[disk] / 2); - - auto* coverBodyBathtub1 = new TGeoBBox(Form("coverBodyBathtub1MF%d", disk), lengthBodyBathtub1 / 2 + Geometry::sEpsilon, widthBodyBathtub1 / 2 + Geometry::sEpsilon, - thicknessBodyBathtub1[disk] / 2 + Geometry::sEpsilon); - auto* coverBodyBathtub2 = new TGeoBBox(Form("coverBodyBathtub2MF%d", disk), lengthBodyBathtub2 / 2 + Geometry::sEpsilon, widthBodyBathtub2 / 2 + Geometry::sEpsilon, - thicknessBodyBathtub2[disk] / 2 + Geometry::sEpsilon); - auto* coverBodyBathtub3 = new TGeoTube(Form("coverBodyBathtub3MF%d", disk), 0, cornerRadiusBodyBathtub1[disk] + Geometry::sEpsilon, - thicknessBodyBathtub2[disk] / 2 + Geometry::sEpsilon); + auto* coverBody1 = new TGeoBBox(Form("coverBody1MF%d", disk), lengthBody / 2, + widthBody / 2, thicknessBody[disk] / 2); + + auto* coverBodyBathtub1 = + new TGeoBBox(Form("coverBodyBathtub1MF%d", disk), + lengthBodyBathtub1 / 2 + Geometry::sEpsilon, + widthBodyBathtub1 / 2 + Geometry::sEpsilon, + thicknessBodyBathtub1[disk] / 2 + Geometry::sEpsilon); + auto* coverBodyBathtub2 = + new TGeoBBox(Form("coverBodyBathtub2MF%d", disk), + lengthBodyBathtub2 / 2 + Geometry::sEpsilon, + widthBodyBathtub2 / 2 + Geometry::sEpsilon, + thicknessBodyBathtub2[disk] / 2 + Geometry::sEpsilon); + auto* coverBodyBathtub3 = + new TGeoTube(Form("coverBodyBathtub3MF%d", disk), 0, + cornerRadiusBodyBathtub1[disk] + Geometry::sEpsilon, + thicknessBodyBathtub2[disk] / 2 + Geometry::sEpsilon); TGeoTranslation* tcoverBodyBathtub[7]; - tcoverBodyBathtub[0] = new TGeoTranslation(Form("tcoverBodyBathtub1MF%d", disk), 0., 0., 0); - - tcoverBodyBathtub[1] = new TGeoTranslation(Form("tcoverBodyBathtub2MF%d", disk), lengthBodyBathtub1 / 2 + lengthBodyBathtub2 / 2, 0., 0.); - tcoverBodyBathtub[2] = new TGeoTranslation(Form("tcoverBodyBathtub3MF%d", disk), lengthBodyBathtub1 / 2, widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk], 0.); - tcoverBodyBathtub[3] = new TGeoTranslation(Form("tcoverBodyBathtub4MF%d", disk), lengthBodyBathtub1 / 2, -(widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk]), 0.); - - tcoverBodyBathtub[4] = new TGeoTranslation(Form("tcoverBodyBathtub5MF%d", disk), -(lengthBodyBathtub1 / 2 + lengthBodyBathtub2 / 2), 0., 0.); - tcoverBodyBathtub[5] = new TGeoTranslation(Form("tcoverBodyBathtub6MF%d", disk), -(lengthBodyBathtub1 / 2), widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk], 0.); - tcoverBodyBathtub[6] = new TGeoTranslation(Form("tcoverBodyBathtub7MF%d", disk), -(lengthBodyBathtub1 / 2), -(widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk]), 0.); + tcoverBodyBathtub[0] = + new TGeoTranslation(Form("tcoverBodyBathtub1MF%d", disk), 0., 0., 0); + + tcoverBodyBathtub[1] = new TGeoTranslation( + Form("tcoverBodyBathtub2MF%d", disk), + lengthBodyBathtub1 / 2 + lengthBodyBathtub2 / 2, 0., 0.); + tcoverBodyBathtub[2] = new TGeoTranslation( + Form("tcoverBodyBathtub3MF%d", disk), lengthBodyBathtub1 / 2, + widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk], 0.); + tcoverBodyBathtub[3] = new TGeoTranslation( + Form("tcoverBodyBathtub4MF%d", disk), lengthBodyBathtub1 / 2, + -(widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk]), 0.); + + tcoverBodyBathtub[4] = new TGeoTranslation( + Form("tcoverBodyBathtub5MF%d", disk), + -(lengthBodyBathtub1 / 2 + lengthBodyBathtub2 / 2), 0., 0.); + tcoverBodyBathtub[5] = new TGeoTranslation( + Form("tcoverBodyBathtub6MF%d", disk), -(lengthBodyBathtub1 / 2), + widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk], 0.); + tcoverBodyBathtub[6] = new TGeoTranslation( + Form("tcoverBodyBathtub7MF%d", disk), -(lengthBodyBathtub1 / 2), + -(widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk]), 0.); for (Int_t i = 0; i < 7; ++i) { tcoverBodyBathtub[i]->RegisterYourself(); } - TGeoCompositeShape* shapeCoverBathtub = new TGeoCompositeShape(Form("shapeCoverBathtubMF%d", disk), Form("coverBodyBathtub1MF%d + coverBodyBathtub2MF%d:tcoverBodyBathtub2MF%d + coverBodyBathtub3MF%d:tcoverBodyBathtub3MF%d + coverBodyBathtub3MF%d:tcoverBodyBathtub4MF%d + coverBodyBathtub2MF%d:tcoverBodyBathtub5MF%d + coverBodyBathtub3MF%d:tcoverBodyBathtub6MF%d + coverBodyBathtub3MF%d:tcoverBodyBathtub7MF%d", disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk)); - - TGeoTranslation* tcoverBathtub = new TGeoTranslation(Form("tcoverBathtubMF%d", disk), 0, 0, thicknessBody[disk] / 2 - thicknessBodyBathtub1[disk] / 2); + TGeoCompositeShape* shapeCoverBathtub = new TGeoCompositeShape( + Form("shapeCoverBathtubMF%d", disk), + Form("coverBodyBathtub1MF%d + " + "coverBodyBathtub2MF%d:tcoverBodyBathtub2MF%d + " + "coverBodyBathtub3MF%d:tcoverBodyBathtub3MF%d + " + "coverBodyBathtub3MF%d:tcoverBodyBathtub4MF%d + " + "coverBodyBathtub2MF%d:tcoverBodyBathtub5MF%d + " + "coverBodyBathtub3MF%d:tcoverBodyBathtub6MF%d + " + "coverBodyBathtub3MF%d:tcoverBodyBathtub7MF%d", + disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, + disk, disk)); + + TGeoTranslation* tcoverBathtub = new TGeoTranslation( + Form("tcoverBathtubMF%d", disk), 0, 0, + thicknessBody[disk] / 2 - thicknessBodyBathtub1[disk] / 2); tcoverBathtub->RegisterYourself(); Double_t cornerRadiusStep1[5]; @@ -512,36 +545,68 @@ void HeatExchanger::createManifold(Int_t disk) Double_t thicknessStep3; thicknessStep3 = thicknessStep1[disk]; - auto* coverBodyStep1 = new TGeoBBox(Form("coverBodyStep1MF%d", disk), (lengthStep1[disk] - cornerRadiusStep1[disk]) / 2 + Geometry::sEpsilon, widthStep1[disk] / 2 + Geometry::sEpsilon, - thicknessStep1[disk] / 2 + Geometry::sEpsilon); - auto* coverBodyStep2 = new TGeoBBox(Form("coverBodyStep2MF%d", disk), lengthStep2 / 2 + Geometry::sEpsilon, widthStep2 / 2 + Geometry::sEpsilon, + auto* coverBodyStep1 = new TGeoBBox( + Form("coverBodyStep1MF%d", disk), + (lengthStep1[disk] - cornerRadiusStep1[disk]) / 2 + Geometry::sEpsilon, + widthStep1[disk] / 2 + Geometry::sEpsilon, + thicknessStep1[disk] / 2 + Geometry::sEpsilon); + auto* coverBodyStep2 = new TGeoBBox(Form("coverBodyStep2MF%d", disk), + lengthStep2 / 2 + Geometry::sEpsilon, + widthStep2 / 2 + Geometry::sEpsilon, thicknessStep2 / 2 + Geometry::sEpsilon); - auto* coverBodyStep3 = new TGeoTube(Form("coverBodyStep3MF%d", disk), 0, cornerRadiusStep1[disk] + Geometry::sEpsilon, - thicknessStep1[disk] / 2 + Geometry::sEpsilon); - auto* coverBodyStep4 = new TGeoBBox(Form("coverBodyStep4MF%d", disk), lengthStep3[disk] / 2 + Geometry::sEpsilon, widthStep3 / 2 + Geometry::sEpsilon, - thicknessStep3 / 2 + Geometry::sEpsilon); + auto* coverBodyStep3 = + new TGeoTube(Form("coverBodyStep3MF%d", disk), 0, + cornerRadiusStep1[disk] + Geometry::sEpsilon, + thicknessStep1[disk] / 2 + Geometry::sEpsilon); + auto* coverBodyStep4 = + new TGeoBBox(Form("coverBodyStep4MF%d", disk), + lengthStep3[disk] / 2 + Geometry::sEpsilon, + widthStep3 / 2 + Geometry::sEpsilon, + thicknessStep3 / 2 + Geometry::sEpsilon); TGeoTranslation* tcoverBodyStep[4]; - tcoverBodyStep[0] = new TGeoTranslation(Form("tcoverBodyStep1MF%d", disk), 0., 0., 0); - tcoverBodyStep[1] = new TGeoTranslation(Form("tcoverBodyStep2MF%d", disk), (lengthStep1[disk] - cornerRadiusStep1[disk]) / 2 + lengthStep2 / 2, cornerRadiusStep1[disk] / 2, 0.); - tcoverBodyStep[2] = new TGeoTranslation(Form("tcoverBodyStep3MF%d", disk), (lengthStep1[disk] - cornerRadiusStep1[disk]) / 2, -(widthStep1[disk] / 2 - cornerRadiusStep1[disk]), 0.); - tcoverBodyStep[3] = new TGeoTranslation(Form("tcoverBodyStep4MF%d", disk), -(lengthStep1[disk] - lengthStep2) / 2, -widthStep1[disk] / 2, 0.); - - TGeoRotation* rcoverBodyStep = new TGeoRotation(Form("rcoverBodyStep4MF%d", disk), 45, 0, 0); + tcoverBodyStep[0] = + new TGeoTranslation(Form("tcoverBodyStep1MF%d", disk), 0., 0., 0); + tcoverBodyStep[1] = new TGeoTranslation( + Form("tcoverBodyStep2MF%d", disk), + (lengthStep1[disk] - cornerRadiusStep1[disk]) / 2 + lengthStep2 / 2, + cornerRadiusStep1[disk] / 2, 0.); + tcoverBodyStep[2] = new TGeoTranslation( + Form("tcoverBodyStep3MF%d", disk), + (lengthStep1[disk] - cornerRadiusStep1[disk]) / 2, + -(widthStep1[disk] / 2 - cornerRadiusStep1[disk]), 0.); + tcoverBodyStep[3] = new TGeoTranslation( + Form("tcoverBodyStep4MF%d", disk), -(lengthStep1[disk] - lengthStep2) / 2, + -widthStep1[disk] / 2, 0.); + + TGeoRotation* rcoverBodyStep = + new TGeoRotation(Form("rcoverBodyStep4MF%d", disk), 45, 0, 0); rcoverBodyStep->RegisterYourself(); TGeoCombiTrans* combtcoverBodyStep[4]; - combtcoverBodyStep[3] = new TGeoCombiTrans(Form("combtcoverBodyStep4MF%d", disk), -(lengthStep1[disk] - lengthStep2) / 2, -widthStep1[disk] / 2, 0., rcoverBodyStep); + combtcoverBodyStep[3] = + new TGeoCombiTrans(Form("combtcoverBodyStep4MF%d", disk), + -(lengthStep1[disk] - lengthStep2) / 2, + -widthStep1[disk] / 2, 0., rcoverBodyStep); combtcoverBodyStep[3]->RegisterYourself(); for (Int_t i = 0; i < 4; ++i) { tcoverBodyStep[i]->RegisterYourself(); } - TGeoCompositeShape* shapeStep = new TGeoCompositeShape(Form("shapeStepMF%d", disk), Form("coverBodyStep1MF%d:tcoverBodyStep1MF%d + coverBodyStep2MF%d:tcoverBodyStep2MF%d + coverBodyStep3MF%d:tcoverBodyStep3MF%d + coverBodyStep4MF%d:combtcoverBodyStep4MF%d", disk, disk, disk, disk, disk, disk, disk, disk)); - - TGeoTranslation* tcoverStep = new TGeoTranslation(Form("tcoverStepMF%d", disk), -(lengthMiddle1[disk] / 2 - (lengthStep1[disk] / 2 - lengthStep2 / 2)), - (widthBody / 2 - widthStep1[disk] / 2), -(thicknessBody[disk] / 2 - thicknessStep1[disk] / 2)); + TGeoCompositeShape* shapeStep = new TGeoCompositeShape( + Form("shapeStepMF%d", disk), + Form("coverBodyStep1MF%d:tcoverBodyStep1MF%d + " + "coverBodyStep2MF%d:tcoverBodyStep2MF%d + " + "coverBodyStep3MF%d:tcoverBodyStep3MF%d + " + "coverBodyStep4MF%d:combtcoverBodyStep4MF%d", + disk, disk, disk, disk, disk, disk, disk, disk)); + + TGeoTranslation* tcoverStep = new TGeoTranslation( + Form("tcoverStepMF%d", disk), + -(lengthMiddle1[disk] / 2 - (lengthStep1[disk] / 2 - lengthStep2 / 2)), + (widthBody / 2 - widthStep1[disk] / 2), + -(thicknessBody[disk] / 2 - thicknessStep1[disk] / 2)); tcoverStep->RegisterYourself(); Double_t widthBulge[5]; @@ -567,25 +632,41 @@ void HeatExchanger::createManifold(Int_t disk) thicknessBulgeSub[3] = 0.5; thicknessBulgeSub[4] = 0.5; - auto* coverBodyBulge = new TGeoBBox(Form("coverBodyBulgeMF%d", disk), lengthBulge[disk] / 2, widthBulge[disk] / 2, thicknessBulge / 2); - auto* coverBodyBulgeSub = new TGeoBBox(Form("coverBodyBulgeSubMF%d", disk), lengthBulgeSub[disk] / 2, widthBulgeSub / 2, thicknessBulgeSub[disk] / 2 + Geometry::sEpsilon); + auto* coverBodyBulge = + new TGeoBBox(Form("coverBodyBulgeMF%d", disk), lengthBulge[disk] / 2, + widthBulge[disk] / 2, thicknessBulge / 2); + auto* coverBodyBulgeSub = new TGeoBBox( + Form("coverBodyBulgeSubMF%d", disk), lengthBulgeSub[disk] / 2, + widthBulgeSub / 2, thicknessBulgeSub[disk] / 2 + Geometry::sEpsilon); - TGeoRotation* rcoverBodyBulgeSub = new TGeoRotation(Form("rcoverBodyBulgeSubMF%d", disk), 0, 90, 45); + TGeoRotation* rcoverBodyBulgeSub = + new TGeoRotation(Form("rcoverBodyBulgeSubMF%d", disk), 0, 90, 45); rcoverBodyBulgeSub->RegisterYourself(); - TGeoTranslation* tcoverBodyBulgeSub = new TGeoTranslation(Form("tcoverBodyBulgeSubMF%d", disk), -lengthBulge[disk] / 2, 0, 0); + TGeoTranslation* tcoverBodyBulgeSub = new TGeoTranslation( + Form("tcoverBodyBulgeSubMF%d", disk), -lengthBulge[disk] / 2, 0, 0); tcoverBodyBulgeSub->RegisterYourself(); - TGeoCombiTrans* combtcoverBodyBulgeSub = new TGeoCombiTrans(Form("combtcoverBodyBulgeSubMF%d", disk), -lengthBulge[disk] / 2, 0, 0, rcoverBodyBulgeSub); + TGeoCombiTrans* combtcoverBodyBulgeSub = + new TGeoCombiTrans(Form("combtcoverBodyBulgeSubMF%d", disk), + -lengthBulge[disk] / 2, 0, 0, rcoverBodyBulgeSub); combtcoverBodyBulgeSub->RegisterYourself(); - TGeoCompositeShape* shapeBulge = new TGeoCompositeShape(Form("shapeBulgeMF%d", disk), Form("coverBodyBulgeMF%d - coverBodyBulgeSubMF%d:combtcoverBodyBulgeSubMF%d", disk, disk, disk)); + TGeoCompositeShape* shapeBulge = new TGeoCompositeShape( + Form("shapeBulgeMF%d", disk), + Form("coverBodyBulgeMF%d - " + "coverBodyBulgeSubMF%d:combtcoverBodyBulgeSubMF%d", + disk, disk, disk)); - TGeoTranslation* tcoverBulge = new TGeoTranslation(Form("tcoverBulgeMF%d", disk), -(lengthMiddle1[disk] / 2 + lengthBulge[disk] / 2), -(widthBody / 2 - widthBulge[disk] / 2), 0); + TGeoTranslation* tcoverBulge = + new TGeoTranslation(Form("tcoverBulgeMF%d", disk), + -(lengthMiddle1[disk] / 2 + lengthBulge[disk] / 2), + -(widthBody / 2 - widthBulge[disk] / 2), 0); tcoverBulge->RegisterYourself(); Double_t holeRadius[5]; - holeRadius[0] = 0.25; // 0.207; overlap issue of thread, increase up to 0.25, fm + holeRadius[0] = + 0.25; // 0.207; overlap issue of thread, increase up to 0.25, fm holeRadius[1] = 0.25; // 0.207; holeRadius[2] = 0.25; // 0.207; holeRadius[3] = 0.25; // 0.207; @@ -597,26 +678,52 @@ void HeatExchanger::createManifold(Int_t disk) holeOffset[3] = 0.65; holeOffset[4] = 0.65; - auto* coverBodyHole = new TGeoTube(Form("coverBodyHoleMF%d", disk), 0, holeRadius[disk], thicknessBody[disk] / 2 + Geometry::sEpsilon); - TGeoTranslation* tcoverBodyHole = new TGeoTranslation(Form("tcoverBodyHoleMF%d", disk), lengthBody / 2 - holeOffset[disk], 0, 0); + auto* coverBodyHole = + new TGeoTube(Form("coverBodyHoleMF%d", disk), 0, holeRadius[disk], + thicknessBody[disk] / 2 + Geometry::sEpsilon); + TGeoTranslation* tcoverBodyHole = + new TGeoTranslation(Form("tcoverBodyHoleMF%d", disk), + lengthBody / 2 - holeOffset[disk], 0, 0); tcoverBodyHole->RegisterYourself(); - TGeoCompositeShape* shapeManifold2 = new TGeoCompositeShape(Form("shapeManifold2MF%d", disk), Form("coverBody1MF%d - coverBodyHoleMF%d:tcoverBodyHoleMF%d - shapeCoverBathtubMF%d:tcoverBathtubMF%d - shapeStepMF%d:tcoverStepMF%d + shapeBulgeMF%d:tcoverBulgeMF%d", disk, disk, disk, disk, disk, disk, disk, disk, disk)); + TGeoCompositeShape* shapeManifold2 = new TGeoCompositeShape( + Form("shapeManifold2MF%d", disk), + Form("coverBody1MF%d - coverBodyHoleMF%d:tcoverBodyHoleMF%d - " + "shapeCoverBathtubMF%d:tcoverBathtubMF%d - " + "shapeStepMF%d:tcoverStepMF%d + shapeBulgeMF%d:tcoverBulgeMF%d", + disk, disk, disk, disk, disk, disk, disk, disk, disk)); - TGeoRotation* rshapeManifold2 = new TGeoRotation(Form("rshapeManifold2MF%d", disk), 0, 180, 0); + TGeoRotation* rshapeManifold2 = + new TGeoRotation(Form("rshapeManifold2MF%d", disk), 0, 180, 0); rshapeManifold2->RegisterYourself(); - TGeoTranslation* tshapeManifold1 = new TGeoTranslation(Form("tshapeManifold1MF%d", disk), 0, 0, - -((thicknessBody[disk] + thicknessMiddle[disk] + thicknessBottom[disk]) / 2 - (thicknessTop[disk] + thicknessMiddle[disk] + thicknessBottom[disk]) / 2)); + TGeoTranslation* tshapeManifold1 = new TGeoTranslation( + Form("tshapeManifold1MF%d", disk), 0, 0, + -((thicknessBody[disk] + thicknessMiddle[disk] + thicknessBottom[disk]) / + 2 - + (thicknessTop[disk] + thicknessMiddle[disk] + thicknessBottom[disk]) / + 2)); tshapeManifold1->RegisterYourself(); - TGeoTranslation* tshapeManifold2 = new TGeoTranslation(Form("tshapeManifold2MF%d", disk), 0, 0, (thicknessBody[disk] + thicknessMiddle[disk] + thicknessBottom[disk]) / 2 - thicknessBody[disk] / 2); + TGeoTranslation* tshapeManifold2 = new TGeoTranslation( + Form("tshapeManifold2MF%d", disk), 0, 0, + (thicknessBody[disk] + thicknessMiddle[disk] + thicknessBottom[disk]) / + 2 - + thicknessBody[disk] / 2); tshapeManifold2->RegisterYourself(); - TGeoCombiTrans* combtshapeManifold2 = new TGeoCombiTrans(Form("combtshapeManifold2MF%d", disk), 0, 0, (thicknessBody[disk] + thicknessMiddle[disk] + thicknessBottom[disk]) / 2 - thicknessBody[disk] / 2, rshapeManifold2); + TGeoCombiTrans* combtshapeManifold2 = new TGeoCombiTrans( + Form("combtshapeManifold2MF%d", disk), 0, 0, + (thicknessBody[disk] + thicknessMiddle[disk] + thicknessBottom[disk]) / + 2 - + thicknessBody[disk] / 2, + rshapeManifold2); combtshapeManifold2->RegisterYourself(); - TGeoCompositeShape* shapeManifold = new TGeoCompositeShape("shapeManifold", Form("shapeManifold1MF%d:tshapeManifold1MF%d + shapeManifold2MF%d:combtshapeManifold2MF%d", disk, disk, disk, disk)); + TGeoCompositeShape* shapeManifold = new TGeoCompositeShape( + "shapeManifold", Form("shapeManifold1MF%d:tshapeManifold1MF%d + " + "shapeManifold2MF%d:combtshapeManifold2MF%d", + disk, disk, disk, disk)); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Manifold3 @@ -626,32 +733,38 @@ void HeatExchanger::createManifold(Int_t disk) Double_t outerRadiusPlug1 = 0.6 / 2.; // fm 0.99 / 2; //0.8 Double_t thicknessPlug1 = 0.105; - auto* plug1 = new TGeoTube(Form("plug1MF%d", disk), innerRadiusPlug1, outerRadiusPlug1, thicknessPlug1 / 2); + auto* plug1 = new TGeoTube(Form("plug1MF%d", disk), innerRadiusPlug1, + outerRadiusPlug1, thicknessPlug1 / 2); Double_t innerRadiusPlug2 = innerRadiusPlug1; Double_t outerMinRadiusPlug2 = 0.6 / 2.; // fm 0.94 / 2; // 0.85 Double_t outerMaxRadiusPlug2 = outerRadiusPlug1; Double_t thicknessPlug2 = 0.025; - auto* plug2 = new TGeoCone(Form("plug2MF%d", disk), thicknessPlug2 / 2, innerRadiusPlug2, outerMaxRadiusPlug2, innerRadiusPlug2, outerMinRadiusPlug2); + auto* plug2 = new TGeoCone(Form("plug2MF%d", disk), thicknessPlug2 / 2, + innerRadiusPlug2, outerMaxRadiusPlug2, + innerRadiusPlug2, outerMinRadiusPlug2); Double_t innerRadiusPlug3 = innerRadiusPlug1; Double_t outerRadiusPlug3 = 0.5 / 2; // fm 0.720 / 2; Double_t thicknessPlug3 = 0.086; - auto* plug3 = new TGeoTube(Form("plug3MF%d", disk), innerRadiusPlug3, outerRadiusPlug3, thicknessPlug3 / 2); + auto* plug3 = new TGeoTube(Form("plug3MF%d", disk), innerRadiusPlug3, + outerRadiusPlug3, thicknessPlug3 / 2); Double_t innerRadiusPlug4 = innerRadiusPlug1; Double_t outerRadiusPlug4 = 0.7 / 2.; // fm 1.100 / 2; // 0.7 Double_t thicknessPlug4 = 0.1; // fm 0.534; // 0.05 - auto* plug4 = new TGeoTube(Form("plug4MF%d", disk), innerRadiusPlug4, outerRadiusPlug4, thicknessPlug4 / 2); + auto* plug4 = new TGeoTube(Form("plug4MF%d", disk), innerRadiusPlug4, + outerRadiusPlug4, thicknessPlug4 / 2); Double_t innerRadiusPlug5 = innerRadiusPlug1; Double_t outerRadiusPlug5 = 0.9 / 2.; // fm 1.270 / 2; // 0.9 Double_t thicknessPlug5 = 0.700; - auto* plug5main = new TGeoTube(Form("plug5mainMF%d", disk), innerRadiusPlug5, outerRadiusPlug5, thicknessPlug5 / 2); + auto* plug5main = new TGeoTube(Form("plug5mainMF%d", disk), innerRadiusPlug5, + outerRadiusPlug5, thicknessPlug5 / 2); const Int_t nSidePlug5 = 6; Double_t anglesubPlug5 = 360. / nSidePlug5 / 2. * TMath::Pi() / 180.; @@ -659,9 +772,14 @@ void HeatExchanger::createManifold(Int_t disk) Double_t widthPlug5sub = outerRadiusPlug5 * (1 - TMath::Cos(anglesubPlug5)); Double_t thicknessPlug5sub = thicknessPlug5 + Geometry::sEpsilon; - auto* plug5sub = new TGeoBBox(Form("plug5subMF%d", disk), lengthPlug5sub / 2, widthPlug5sub / 2, thicknessPlug5sub / 2); + auto* plug5sub = new TGeoBBox(Form("plug5subMF%d", disk), lengthPlug5sub / 2, + widthPlug5sub / 2, thicknessPlug5sub / 2); - TGeoTranslation* tPlug5sub = new TGeoTranslation(Form("tPlug5subMF%d", disk), 0, outerRadiusPlug5 * TMath::Cos(anglesubPlug5) + outerRadiusPlug5 * (1 - TMath::Cos(anglesubPlug5)) / 2, 0.); + TGeoTranslation* tPlug5sub = new TGeoTranslation( + Form("tPlug5subMF%d", disk), 0, + outerRadiusPlug5 * TMath::Cos(anglesubPlug5) + + outerRadiusPlug5 * (1 - TMath::Cos(anglesubPlug5)) / 2, + 0.); tPlug5sub->RegisterYourself(); TGeoRotation* rPlug5sub[nSidePlug5]; @@ -669,69 +787,94 @@ void HeatExchanger::createManifold(Int_t disk) TString namePlug5 = Form("plug5mainMF%d", disk); for (Int_t index = 0; index < nSidePlug5; ++index) { - rPlug5sub[index] = new TGeoRotation(Form("rPlug5sub%dMF%d", index, disk), index * 60, 0, 0); + rPlug5sub[index] = new TGeoRotation(Form("rPlug5sub%dMF%d", index, disk), + index * 60, 0, 0); rPlug5sub[index]->RegisterYourself(); - TGeoCombiTrans* combtPlug5sub = new TGeoCombiTrans(Form("combtPlug5subMF%d", disk), 0, outerRadiusPlug5 * TMath::Cos(anglesubPlug5) + outerRadiusPlug5 * (1 - TMath::Cos(anglesubPlug5)) / 2, 0., rPlug5sub[index]); + TGeoCombiTrans* combtPlug5sub = new TGeoCombiTrans( + Form("combtPlug5subMF%d", disk), 0, + outerRadiusPlug5 * TMath::Cos(anglesubPlug5) + + outerRadiusPlug5 * (1 - TMath::Cos(anglesubPlug5)) / 2, + 0., rPlug5sub[index]); combtPlug5sub->RegisterYourself(); namePlug5 += Form(" - plug5subMF%d:combtPlug5subMF%d", disk, disk); } - TGeoCompositeShape* plug5 = new TGeoCompositeShape(Form("plug5MF%d", disk), namePlug5); + TGeoCompositeShape* plug5 = + new TGeoCompositeShape(Form("plug5MF%d", disk), namePlug5); Double_t innerRadiusPlug6 = 0; Double_t outerRadiusPlug6 = 0.780 / 2; Double_t thicknessPlug6 = 0.150; - auto* plug6 = new TGeoTube(Form("plug6MF%d", disk), innerRadiusPlug6, outerRadiusPlug6, thicknessPlug6 / 2); + auto* plug6 = new TGeoTube(Form("plug6MF%d", disk), innerRadiusPlug6, + outerRadiusPlug6, thicknessPlug6 / 2); Double_t innerRadiusPlug7 = innerRadiusPlug6; Double_t outerMinRadiusPlug7 = 0.520 / 2; Double_t outerMaxRadiusPlug7 = 0.638 / 2; Double_t thicknessPlug7 = 0.050; - auto* plug7 = new TGeoCone(Form("plug7MF%d", disk), thicknessPlug7 / 2, innerRadiusPlug7, outerMaxRadiusPlug7, innerRadiusPlug7, outerMinRadiusPlug7); + auto* plug7 = new TGeoCone(Form("plug7MF%d", disk), thicknessPlug7 / 2, + innerRadiusPlug7, outerMaxRadiusPlug7, + innerRadiusPlug7, outerMinRadiusPlug7); Double_t innerRadiusPlug8 = innerRadiusPlug6; Double_t outerRadiusPlug8 = 0.413 / 2; Double_t thicknessPlug8 = 0.042; - auto* plug8 = new TGeoTube(Form("plug8MF%d", disk), innerRadiusPlug8, outerRadiusPlug8, thicknessPlug8 / 2); + auto* plug8 = new TGeoTube(Form("plug8MF%d", disk), innerRadiusPlug8, + outerRadiusPlug8, thicknessPlug8 / 2); Double_t innerRadiusPlug9 = innerRadiusPlug6; Double_t outerMinRadiusPlug9 = outerRadiusPlug8; Double_t outerMaxRadiusPlug9 = 0.500 / 2; Double_t thicknessPlug9 = 0.040; - auto* plug9 = new TGeoCone(Form("plug9MF%d", disk), thicknessPlug9 / 2, innerRadiusPlug9, outerMinRadiusPlug9, innerRadiusPlug9, outerMaxRadiusPlug9); + auto* plug9 = new TGeoCone(Form("plug9MF%d", disk), thicknessPlug9 / 2, + innerRadiusPlug9, outerMinRadiusPlug9, + innerRadiusPlug9, outerMaxRadiusPlug9); Double_t innerRadiusPlug10 = innerRadiusPlug6; Double_t outerRadiusPlug10 = outerMaxRadiusPlug9; Double_t thicknessPlug10 = 0.125; - auto* plug10 = new TGeoTube(Form("plug10MF%d", disk), innerRadiusPlug10, outerRadiusPlug10, thicknessPlug10 / 2); + auto* plug10 = new TGeoTube(Form("plug10MF%d", disk), innerRadiusPlug10, + outerRadiusPlug10, thicknessPlug10 / 2); Double_t innerRadiusPlug11 = innerRadiusPlug6; Double_t outerMinRadiusPlug11 = outerRadiusPlug8; Double_t outerMaxRadiusPlug11 = 0.500 / 2; Double_t thicknessPlug11 = 0.043; - auto* plug11 = new TGeoCone(Form("plug11MF%d", disk), thicknessPlug11 / 2, innerRadiusPlug11, outerMaxRadiusPlug11, innerRadiusPlug11, outerMinRadiusPlug11); + auto* plug11 = new TGeoCone(Form("plug11MF%d", disk), thicknessPlug11 / 2, + innerRadiusPlug11, outerMaxRadiusPlug11, + innerRadiusPlug11, outerMinRadiusPlug11); Double_t innerRadiusPlug12 = 0; Double_t outerRadiusPlug12 = 0.289 / 2; - Double_t thicknessPlug12 = thicknessPlug6 + thicknessPlug7 + thicknessPlug8 + thicknessPlug9 + thicknessPlug10 + thicknessPlug11; + Double_t thicknessPlug12 = thicknessPlug6 + thicknessPlug7 + thicknessPlug8 + + thicknessPlug9 + thicknessPlug10 + thicknessPlug11; - auto* plug12main = new TGeoTube(Form("plug12mainMF%d", disk), innerRadiusPlug12, outerRadiusPlug12, thicknessPlug12 / 2 + Geometry::sEpsilon); + auto* plug12main = + new TGeoTube(Form("plug12mainMF%d", disk), innerRadiusPlug12, + outerRadiusPlug12, thicknessPlug12 / 2 + Geometry::sEpsilon); const Int_t nSidePlug12 = 6; Double_t anglesubPlug12 = 360. / nSidePlug12 / 2. * TMath::Pi() / 180.; Double_t lengthPlug12sub = outerRadiusPlug12 * TMath::Cos(anglesubPlug12) * 2; - Double_t widthPlug12sub = outerRadiusPlug12 * (1 - TMath::Cos(anglesubPlug12)); + Double_t widthPlug12sub = + outerRadiusPlug12 * (1 - TMath::Cos(anglesubPlug12)); Double_t thicknessPlug12sub = thicknessPlug12; - auto* plug12sub = new TGeoBBox(Form("plug12subMF%d", disk), lengthPlug12sub / 2, widthPlug12sub / 2, thicknessPlug12sub / 2 + Geometry::sEpsilon); + auto* plug12sub = new TGeoBBox(Form("plug12subMF%d", disk), + lengthPlug12sub / 2, widthPlug12sub / 2, + thicknessPlug12sub / 2 + Geometry::sEpsilon); - TGeoTranslation* tPlug12sub = new TGeoTranslation(Form("tPlug12subMF%d", disk), 0, outerRadiusPlug12 * TMath::Cos(anglesubPlug12) + outerRadiusPlug12 * (1 - TMath::Cos(anglesubPlug12)) / 2, 0.); + TGeoTranslation* tPlug12sub = new TGeoTranslation( + Form("tPlug12subMF%d", disk), 0, + outerRadiusPlug12 * TMath::Cos(anglesubPlug12) + + outerRadiusPlug12 * (1 - TMath::Cos(anglesubPlug12)) / 2, + 0.); tPlug12sub->RegisterYourself(); TGeoRotation* rPlug12sub[nSidePlug12]; @@ -739,30 +882,77 @@ void HeatExchanger::createManifold(Int_t disk) TString namePlug12 = Form("plug12mainMF%d", disk); for (Int_t index = 0; index < nSidePlug12; ++index) { - rPlug12sub[index] = new TGeoRotation(Form("rPlug12sub%dMF%d", index, disk), index * 60, 0, 0); + rPlug12sub[index] = new TGeoRotation(Form("rPlug12sub%dMF%d", index, disk), + index * 60, 0, 0); rPlug12sub[index]->RegisterYourself(); - TGeoCombiTrans* combtPlug12sub = new TGeoCombiTrans(Form("combtPlug12subMF%d", disk), 0, outerRadiusPlug12 * TMath::Cos(anglesubPlug12) + outerRadiusPlug12 * (1 - TMath::Cos(anglesubPlug12)) / 2, 0., rPlug12sub[index]); + TGeoCombiTrans* combtPlug12sub = new TGeoCombiTrans( + Form("combtPlug12subMF%d", disk), 0, + outerRadiusPlug12 * TMath::Cos(anglesubPlug12) + + outerRadiusPlug12 * (1 - TMath::Cos(anglesubPlug12)) / 2, + 0., rPlug12sub[index]); combtPlug12sub->RegisterYourself(); namePlug12 += Form(" - plug12subMF%d:combtPlug12subMF%d", disk, disk); } - TGeoCompositeShape* plug12 = new TGeoCompositeShape(Form("plug12MF%d", disk), namePlug12); + TGeoCompositeShape* plug12 = + new TGeoCompositeShape(Form("plug12MF%d", disk), namePlug12); - Double_t refposPlug = (thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + thicknessPlug4 + thicknessPlug5 + thicknessPlug6 + thicknessPlug7 + thicknessPlug8 + thicknessPlug9 + thicknessPlug10 + thicknessPlug11) / 2; + Double_t refposPlug = + (thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + thicknessPlug4 + + thicknessPlug5 + thicknessPlug6 + thicknessPlug7 + thicknessPlug8 + + thicknessPlug9 + thicknessPlug10 + thicknessPlug11) / + 2; TGeoTranslation* tPlug[12]; - tPlug[0] = new TGeoTranslation(Form("tPlug1MF%d", disk), 0, 0, -refposPlug + thicknessPlug1 / 2); - tPlug[1] = new TGeoTranslation(Form("tPlug2MF%d", disk), 0, 0, -refposPlug + thicknessPlug1 + thicknessPlug2 / 2); - tPlug[2] = new TGeoTranslation(Form("tPlug3MF%d", disk), 0, 0, -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 / 2); - tPlug[3] = new TGeoTranslation(Form("tPlug4MF%d", disk), 0, 0, -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + thicknessPlug4 / 2); - tPlug[4] = new TGeoTranslation(Form("tPlug5MF%d", disk), 0, 0, -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + thicknessPlug4 + thicknessPlug5 / 2); - tPlug[5] = new TGeoTranslation(Form("tPlug6MF%d", disk), 0, 0, -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + thicknessPlug4 + thicknessPlug5 + thicknessPlug6 / 2); - tPlug[6] = new TGeoTranslation(Form("tPlug7MF%d", disk), 0, 0, -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + thicknessPlug4 + thicknessPlug5 + thicknessPlug6 + thicknessPlug7 / 2); - tPlug[7] = new TGeoTranslation(Form("tPlug8MF%d", disk), 0, 0, -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + thicknessPlug4 + thicknessPlug5 + thicknessPlug6 + thicknessPlug7 + thicknessPlug8 / 2); - tPlug[8] = new TGeoTranslation(Form("tPlug9MF%d", disk), 0, 0, -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + thicknessPlug4 + thicknessPlug5 + thicknessPlug6 + thicknessPlug7 + thicknessPlug8 + thicknessPlug9 / 2); - tPlug[9] = new TGeoTranslation(Form("tPlug10MF%d", disk), 0, 0, -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + thicknessPlug4 + thicknessPlug5 + thicknessPlug6 + thicknessPlug7 + thicknessPlug8 + thicknessPlug9 + thicknessPlug10 / 2); - tPlug[10] = new TGeoTranslation(Form("tPlug11MF%d", disk), 0, 0, -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + thicknessPlug4 + thicknessPlug5 + thicknessPlug6 + thicknessPlug7 + thicknessPlug8 + thicknessPlug9 + thicknessPlug10 + thicknessPlug11 / 2); - tPlug[11] = new TGeoTranslation(Form("tPlug12MF%d", disk), 0, 0, -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + thicknessPlug4 + thicknessPlug5 + thicknessPlug12 / 2); + tPlug[0] = new TGeoTranslation(Form("tPlug1MF%d", disk), 0, 0, + -refposPlug + thicknessPlug1 / 2); + tPlug[1] = + new TGeoTranslation(Form("tPlug2MF%d", disk), 0, 0, + -refposPlug + thicknessPlug1 + thicknessPlug2 / 2); + tPlug[2] = new TGeoTranslation(Form("tPlug3MF%d", disk), 0, 0, + -refposPlug + thicknessPlug1 + thicknessPlug2 + + thicknessPlug3 / 2); + tPlug[3] = new TGeoTranslation(Form("tPlug4MF%d", disk), 0, 0, + -refposPlug + thicknessPlug1 + thicknessPlug2 + + thicknessPlug3 + thicknessPlug4 / 2); + tPlug[4] = new TGeoTranslation(Form("tPlug5MF%d", disk), 0, 0, + -refposPlug + thicknessPlug1 + thicknessPlug2 + + thicknessPlug3 + thicknessPlug4 + + thicknessPlug5 / 2); + tPlug[5] = new TGeoTranslation(Form("tPlug6MF%d", disk), 0, 0, + -refposPlug + thicknessPlug1 + thicknessPlug2 + + thicknessPlug3 + thicknessPlug4 + + thicknessPlug5 + thicknessPlug6 / 2); + tPlug[6] = + new TGeoTranslation(Form("tPlug7MF%d", disk), 0, 0, + -refposPlug + thicknessPlug1 + thicknessPlug2 + + thicknessPlug3 + thicknessPlug4 + thicknessPlug5 + + thicknessPlug6 + thicknessPlug7 / 2); + tPlug[7] = new TGeoTranslation(Form("tPlug8MF%d", disk), 0, 0, + -refposPlug + thicknessPlug1 + thicknessPlug2 + + thicknessPlug3 + thicknessPlug4 + + thicknessPlug5 + thicknessPlug6 + + thicknessPlug7 + thicknessPlug8 / 2); + tPlug[8] = new TGeoTranslation( + Form("tPlug9MF%d", disk), 0, 0, + -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + + thicknessPlug4 + thicknessPlug5 + thicknessPlug6 + thicknessPlug7 + + thicknessPlug8 + thicknessPlug9 / 2); + tPlug[9] = new TGeoTranslation( + Form("tPlug10MF%d", disk), 0, 0, + -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + + thicknessPlug4 + thicknessPlug5 + thicknessPlug6 + thicknessPlug7 + + thicknessPlug8 + thicknessPlug9 + thicknessPlug10 / 2); + tPlug[10] = new TGeoTranslation( + Form("tPlug11MF%d", disk), 0, 0, + -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + + thicknessPlug4 + thicknessPlug5 + thicknessPlug6 + thicknessPlug7 + + thicknessPlug8 + thicknessPlug9 + thicknessPlug10 + + thicknessPlug11 / 2); + tPlug[11] = new TGeoTranslation( + Form("tPlug12MF%d", disk), 0, 0, + -refposPlug + thicknessPlug1 + thicknessPlug2 + thicknessPlug3 + + thicknessPlug4 + thicknessPlug5 + thicknessPlug12 / 2); TString namePlug = ""; for (Int_t ipart = 0; ipart < 12; ++ipart) { @@ -770,13 +960,16 @@ void HeatExchanger::createManifold(Int_t disk) if (ipart == 0) { namePlug += Form("plug1MF%d:tPlug1MF%d", disk, disk); } else if (ipart == 11) { - namePlug += Form(" - plug%dMF%d:tPlug%dMF%d", ipart + 1, disk, ipart + 1, disk); + namePlug += + Form(" - plug%dMF%d:tPlug%dMF%d", ipart + 1, disk, ipart + 1, disk); } else { - namePlug += Form(" + plug%dMF%d:tPlug%dMF%d", ipart + 1, disk, ipart + 1, disk); + namePlug += + Form(" + plug%dMF%d:tPlug%dMF%d", ipart + 1, disk, ipart + 1, disk); } } - TGeoCompositeShape* shapePlug = new TGeoCompositeShape(Form("shapePlugMF%d", disk), namePlug); + TGeoCompositeShape* shapePlug = + new TGeoCompositeShape(Form("shapePlugMF%d", disk), namePlug); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Water @@ -789,29 +982,48 @@ void HeatExchanger::createManifold(Int_t disk) watherThickness[3] = thicknessBodyBathtub2[3] - thicknessTop[3]; watherThickness[4] = thicknessBodyBathtub2[4] - thicknessTop[4]; - auto* water1 = new TGeoBBox(Form("water1MF%d", disk), lengthBodyBathtub1 / 2, widthBodyBathtub1 / 2, watherThickness[disk] / 2); - auto* water2 = new TGeoBBox(Form("water2MF%d", disk), lengthBodyBathtub2 / 2, widthBodyBathtub2 / 2, watherThickness[disk] / 2); - auto* water3 = new TGeoTube(Form("water3MF%d", disk), 0, cornerRadiusBodyBathtub1[disk], watherThickness[disk] / 2); + auto* water1 = new TGeoBBox(Form("water1MF%d", disk), lengthBodyBathtub1 / 2, + widthBodyBathtub1 / 2, watherThickness[disk] / 2); + auto* water2 = new TGeoBBox(Form("water2MF%d", disk), lengthBodyBathtub2 / 2, + widthBodyBathtub2 / 2, watherThickness[disk] / 2); + auto* water3 = + new TGeoTube(Form("water3MF%d", disk), 0, cornerRadiusBodyBathtub1[disk], + watherThickness[disk] / 2); TGeoTranslation* twater[7]; twater[0] = new TGeoTranslation(Form("twater1MF%d", disk), 0., 0., 0); - twater[1] = new TGeoTranslation(Form("twater2MF%d", disk), lengthBodyBathtub1 / 2 + lengthBodyBathtub2 / 2, 0., 0.); - twater[2] = new TGeoTranslation(Form("twater3MF%d", disk), lengthBodyBathtub1 / 2, widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk], 0.); - twater[3] = new TGeoTranslation(Form("twater4MF%d", disk), lengthBodyBathtub1 / 2, -(widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk]), 0.); - - twater[4] = new TGeoTranslation(Form("twater5MF%d", disk), -(lengthBodyBathtub1 / 2 + lengthBodyBathtub2 / 2), 0., 0.); - twater[5] = new TGeoTranslation(Form("twater6MF%d", disk), -(lengthBodyBathtub1 / 2), widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk], 0.); - twater[6] = new TGeoTranslation(Form("twater7MF%d", disk), -(lengthBodyBathtub1 / 2), -(widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk]), 0.); + twater[1] = new TGeoTranslation( + Form("twater2MF%d", disk), + lengthBodyBathtub1 / 2 + lengthBodyBathtub2 / 2, 0., 0.); + twater[2] = new TGeoTranslation( + Form("twater3MF%d", disk), lengthBodyBathtub1 / 2, + widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk], 0.); + twater[3] = new TGeoTranslation( + Form("twater4MF%d", disk), lengthBodyBathtub1 / 2, + -(widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk]), 0.); + + twater[4] = new TGeoTranslation( + Form("twater5MF%d", disk), + -(lengthBodyBathtub1 / 2 + lengthBodyBathtub2 / 2), 0., 0.); + twater[5] = new TGeoTranslation( + Form("twater6MF%d", disk), -(lengthBodyBathtub1 / 2), + widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk], 0.); + twater[6] = new TGeoTranslation( + Form("twater7MF%d", disk), -(lengthBodyBathtub1 / 2), + -(widthBodyBathtub1 / 2 - cornerRadiusBodyBathtub1[disk]), 0.); for (Int_t i = 0; i < 7; ++i) { twater[i]->RegisterYourself(); } - TGeoCompositeShape* shapeWater = new TGeoCompositeShape(Form("shapeCoverBathtubMF%d", disk), - Form("water1MF%d + water2MF%d:twater2MF%d + water3MF%d:twater3MF%d + water3MF%d:twater4MF%d + water2MF%d:twater5MF%d +" - "water3MF%d:twater6MF%d + water3MF%d:twater7MF%d", - disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk)); + TGeoCompositeShape* shapeWater = new TGeoCompositeShape( + Form("shapeCoverBathtubMF%d", disk), + Form("water1MF%d + water2MF%d:twater2MF%d + water3MF%d:twater3MF%d + " + "water3MF%d:twater4MF%d + water2MF%d:twater5MF%d +" + "water3MF%d:twater6MF%d + water3MF%d:twater7MF%d", + disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, disk, + disk, disk)); TGeoCombiTrans* transformation1 = nullptr; TGeoCombiTrans* transformation2 = nullptr; @@ -825,59 +1037,94 @@ void HeatExchanger::createManifold(Int_t disk) TGeoMedium* kMed_plug = gGeoManager->GetMedium("MFT_Alu$"); TGeoMedium* kMed_Water = gGeoManager->GetMedium("MFT_Water$"); - Double_t thicknessTotMF = (thicknessBody[disk] + thicknessMiddle[disk] + thicknessBottom[disk]); + Double_t thicknessTotMF = + (thicknessBody[disk] + thicknessMiddle[disk] + thicknessBottom[disk]); - Double_t deltay = 0.2; // shift respect to the median plan of the MFT - Double_t mfX = 2.2; // width - Double_t mfY = 6.8 - 0.1; // height, decrease to avoid overlap with support, to be solved, fm - Double_t mfZ = 1.7 - 0.85; // thickness, decrease to avoid overlap with support, to be solved, fm + Double_t deltay = 0.2; // shift respect to the median plan of the MFT + Double_t mfX = 2.2; // width + Double_t mfY = + 6.8 - + 0.1; // height, decrease to avoid overlap with support, to be solved, fm + Double_t mfZ = 1.7 - 0.85; // thickness, decrease to avoid overlap with + // support, to be solved, fm Double_t fShift = 0; if (disk == 3 || disk == 4) { - fShift = 0.015; // to avoid overlap with the 2 curved water pipes on the 2 upstream chambers + fShift = 0.015; // to avoid overlap with the 2 curved water pipes on the 2 + // upstream chambers } auto* MF01 = new TGeoVolume(Form("MF%d1", disk), shapeManifold, kMedPeek); - auto* MFplug01 = new TGeoVolume(Form("MFplug%d1", disk), shapePlug, kMed_plug); - auto* MFwater01 = new TGeoVolume(Form("MFwater%d1", disk), shapeWater, kMed_Water); - TGeoRotation* rotation1 = new TGeoRotation(Form("rotation1MF%d", disk), 90, 90., 180.); + auto* MFplug01 = + new TGeoVolume(Form("MFplug%d1", disk), shapePlug, kMed_plug); + auto* MFwater01 = + new TGeoVolume(Form("MFwater%d1", disk), shapeWater, kMed_Water); + TGeoRotation* rotation1 = + new TGeoRotation(Form("rotation1MF%d", disk), 90, 90., 180.); transformation1 = - // new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2 + mfZ / 2 + fShift, mfY / 2 + deltay, mZPlan[disk], rotation1); - new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2 + 0.1 + thicknessTotMF / 2, - mHalfDiskGap + mSupportYDimensions[disk][0] / 2, mZPlan[disk], rotation1); + // new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2 + mfZ / 2 + fShift, + // mfY / 2 + deltay, mZPlan[disk], rotation1); + new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2 + 0.1 + + thicknessTotMF / 2, + mHalfDiskGap + mSupportYDimensions[disk][0] / 2, + mZPlan[disk], rotation1); mHalfDisk->AddNode(MF01, 1, transformation1); - TGeoRotation* rotationplug1 = new TGeoRotation(Form("rotationplug1MF%d", disk), -90, 90., 90.); + TGeoRotation* rotationplug1 = + new TGeoRotation(Form("rotationplug1MF%d", disk), -90, 90., 90.); transformationplug1 = - // new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2 + mfZ / 2 + fShift + thicknessTotMF/2 + refposPlug - (thicknessPlug8 + thicknessPlug9 + thicknessPlug10 + thicknessPlug11),mfY / 2 + deltay - ((lengthBody)/2 - holeOffset[3]), mZPlan[disk], rotationplug1); - new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2 + 0.1 + thicknessTotMF / 2 + thicknessTotMF / 2 + refposPlug - (thicknessPlug8 + thicknessPlug9 + thicknessPlug10 + thicknessPlug11), - mHalfDiskGap + mSupportYDimensions[disk][0] / 2 - ((lengthBody) / 2 - holeOffset[3]), mZPlan[disk], rotationplug1); + // new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2 + mfZ / 2 + fShift + // + thicknessTotMF/2 + refposPlug - (thicknessPlug8 + thicknessPlug9 + + // thicknessPlug10 + thicknessPlug11),mfY / 2 + deltay - ((lengthBody)/2 - + // holeOffset[3]), mZPlan[disk], rotationplug1); + new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2 + 0.1 + + thicknessTotMF / 2 + thicknessTotMF / 2 + + refposPlug - + (thicknessPlug8 + thicknessPlug9 + + thicknessPlug10 + thicknessPlug11), + mHalfDiskGap + mSupportYDimensions[disk][0] / 2 - + ((lengthBody) / 2 - holeOffset[3]), + mZPlan[disk], rotationplug1); mHalfDisk->AddNode(MFplug01, 1, transformationplug1); - transformationwater1 = - new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2 + 0.1 + thicknessTotMF / 2 + (thicknessTotMF / 2 - watherThickness[disk] / 2) - (thicknessBody[disk] - thicknessTop[disk] - watherThickness[disk]), - mHalfDiskGap + mSupportYDimensions[disk][0] / 2, mZPlan[disk], rotation1); + transformationwater1 = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2 + 0.1 + thicknessTotMF / 2 + + (thicknessTotMF / 2 - watherThickness[disk] / 2) - + (thicknessBody[disk] - thicknessTop[disk] - watherThickness[disk]), + mHalfDiskGap + mSupportYDimensions[disk][0] / 2, mZPlan[disk], rotation1); mHalfDisk->AddNode(MFwater01, 1, transformationwater1); auto* MF02 = new TGeoVolume(Form("MF%d2", disk), shapeManifold, kMedPeek); - auto* MFplug02 = new TGeoVolume(Form("MFplug%d2", disk), shapePlug, kMed_plug); - auto* MFwater02 = new TGeoVolume(Form("MFwater%d2", disk), shapeWater, kMed_Water); - TGeoRotation* rotation2 = new TGeoRotation(Form("rotation2MF%d", disk), 90, 90., 0.); - - transformation2 = - new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2 + 0.1 + thicknessTotMF / 2, - -mHalfDiskGap - mSupportYDimensions[disk][0] / 2, mZPlan[disk], rotation2); + auto* MFplug02 = + new TGeoVolume(Form("MFplug%d2", disk), shapePlug, kMed_plug); + auto* MFwater02 = + new TGeoVolume(Form("MFwater%d2", disk), shapeWater, kMed_Water); + TGeoRotation* rotation2 = + new TGeoRotation(Form("rotation2MF%d", disk), 90, 90., 0.); + + transformation2 = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2 + 0.1 + thicknessTotMF / 2, + -mHalfDiskGap - mSupportYDimensions[disk][0] / 2, mZPlan[disk], + rotation2); mHalfDisk->AddNode(MF02, 1, transformation2); - TGeoRotation* rotationplug2 = new TGeoRotation(Form("rotationplug1MF%d", disk), -90, 90., 90.); - transformationplug2 = - new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2 + 0.1 + thicknessTotMF / 2 + thicknessTotMF / 2 + refposPlug - (thicknessPlug8 + thicknessPlug9 + thicknessPlug10 + thicknessPlug11), - -mHalfDiskGap - mSupportYDimensions[disk][0] / 2 + ((lengthBody) / 2 - holeOffset[3]), mZPlan[disk], rotationplug2); + TGeoRotation* rotationplug2 = + new TGeoRotation(Form("rotationplug1MF%d", disk), -90, 90., 90.); + transformationplug2 = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2 + 0.1 + thicknessTotMF / 2 + + thicknessTotMF / 2 + refposPlug - + (thicknessPlug8 + thicknessPlug9 + thicknessPlug10 + thicknessPlug11), + -mHalfDiskGap - mSupportYDimensions[disk][0] / 2 + + ((lengthBody) / 2 - holeOffset[3]), + mZPlan[disk], rotationplug2); mHalfDisk->AddNode(MFplug02, 1, transformationplug2); - transformationwater2 = - new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2 + 0.1 + thicknessTotMF / 2 + ((thicknessTotMF / 2 - watherThickness[disk] / 2) - (thicknessBody[disk] - thicknessTop[disk] - watherThickness[disk])), - -mHalfDiskGap - mSupportYDimensions[disk][0] / 2, mZPlan[disk], rotation2); + transformationwater2 = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2 + 0.1 + thicknessTotMF / 2 + + ((thicknessTotMF / 2 - watherThickness[disk] / 2) - + (thicknessBody[disk] - thicknessTop[disk] - watherThickness[disk])), + -mHalfDiskGap - mSupportYDimensions[disk][0] / 2, mZPlan[disk], + rotation2); mHalfDisk->AddNode(MFwater02, 1, transformationwater2); } @@ -907,131 +1154,251 @@ void HeatExchanger::createHalfDisk0(Int_t half) TGeoRotation* rotation = nullptr; TGeoCombiTrans* transformation = nullptr; - // **************************************** Water part **************************************** - // ********************** Four parameters mLwater0, mRadius0, mAngle0, mLpartial0 ************* + // **************************************** Water part + // **************************************** + // ********************** Four parameters mLwater0, mRadius0, mAngle0, + // mLpartial0 ************* Double_t ivolume = 0; // offset chamber 0 Double_t mRadiusCentralTore[4]; Double_t xPos0[4]; Double_t yPos0[4]; for (Int_t itube = 0; itube < 3; itube++) { - TGeoVolume* waterTube1 = gGeoManager->MakeTube(Form("waterTube1%d_D0_H%d", itube, half), mWater, 0., mRWater, mLWater0[itube] / 2.); - translation = new TGeoTranslation(mXPosition0[itube] - mHalfDiskGap, 0., mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[itube] / 2.); + TGeoVolume* waterTube1 = + gGeoManager->MakeTube(Form("waterTube1%d_D0_H%d", itube, half), mWater, + 0., mRWater, mLWater0[itube] / 2.); + translation = new TGeoTranslation(mXPosition0[itube] - mHalfDiskGap, 0., + mSupportXDimensions[0][0] / 2. + + mMoreLength01 - mLWater0[itube] / 2.); cooling->AddNode(waterTube1, ivolume++, translation); - TGeoVolume* waterTorus1 = gGeoManager->MakeTorus(Form("waterTorus1%d_D0_H%d", itube, half), mWater, mRadius0[itube], 0., mRWater, 0., mAngle0[itube]); + TGeoVolume* waterTorus1 = gGeoManager->MakeTorus( + Form("waterTorus1%d_D0_H%d", itube, half), mWater, mRadius0[itube], 0., + mRWater, 0., mAngle0[itube]); rotation = new TGeoRotation("rotation", 180., -90., 0.); - transformation = new TGeoCombiTrans(mRadius0[itube] + mXPosition0[itube] - mHalfDiskGap, 0., mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[itube], rotation); + transformation = new TGeoCombiTrans( + mRadius0[itube] + mXPosition0[itube] - mHalfDiskGap, 0., + mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[itube], + rotation); cooling->AddNode(waterTorus1, ivolume++, transformation); - TGeoVolume* waterTube2 = gGeoManager->MakeTube(Form("waterTube2%d_D0_H%d", itube, half), mWater, 0., mRWater, mLpartial0[itube] / 2.); + TGeoVolume* waterTube2 = + gGeoManager->MakeTube(Form("waterTube2%d_D0_H%d", itube, half), mWater, + 0., mRWater, mLpartial0[itube] / 2.); rotation = new TGeoRotation("rotation", 90., 180 - mAngle0[itube], 0.); - xPos0[itube] = mLWater0[itube] + mRadius0[itube] * TMath::Sin(mAngle0[itube] * TMath::DegToRad()) + mLpartial0[itube] / 2 * TMath::Cos(mAngle0[itube] * TMath::DegToRad()); - yPos0[itube] = mXPosition0[itube] - mHalfDiskGap + mRadius0[itube] * (1 - TMath::Cos(mAngle0[itube] * TMath::DegToRad())) + mLpartial0[itube] / 2 * TMath::Sin(mAngle0[itube] * TMath::DegToRad()); - transformation = new TGeoCombiTrans(yPos0[itube], 0., mSupportXDimensions[0][0] / 2. + mMoreLength01 - xPos0[itube], rotation); + xPos0[itube] = + mLWater0[itube] + + mRadius0[itube] * TMath::Sin(mAngle0[itube] * TMath::DegToRad()) + + mLpartial0[itube] / 2 * TMath::Cos(mAngle0[itube] * TMath::DegToRad()); + yPos0[itube] = + mXPosition0[itube] - mHalfDiskGap + + mRadius0[itube] * (1 - TMath::Cos(mAngle0[itube] * TMath::DegToRad())) + + mLpartial0[itube] / 2 * TMath::Sin(mAngle0[itube] * TMath::DegToRad()); + transformation = new TGeoCombiTrans(yPos0[itube], 0., + mSupportXDimensions[0][0] / 2. + + mMoreLength01 - xPos0[itube], + rotation); cooling->AddNode(waterTube2, ivolume++, transformation); - mRadiusCentralTore[itube] = (mSupportXDimensions[0][0] / 2. + mMoreLength01 - xPos0[itube] - mLpartial0[itube] / 2 * TMath::Cos(mAngle0[itube] * TMath::DegToRad())) / TMath::Sin(mAngle0[itube] * TMath::DegToRad()); - TGeoVolume* waterTorusCentral = gGeoManager->MakeTorus(Form("waterTorusCentral%d_D0_H%d", itube, half), mWater, mRadiusCentralTore[itube], 0., mRWater, -mAngle0[itube], 2. * mAngle0[itube]); + mRadiusCentralTore[itube] = + (mSupportXDimensions[0][0] / 2. + mMoreLength01 - xPos0[itube] - + mLpartial0[itube] / 2 * + TMath::Cos(mAngle0[itube] * TMath::DegToRad())) / + TMath::Sin(mAngle0[itube] * TMath::DegToRad()); + TGeoVolume* waterTorusCentral = + gGeoManager->MakeTorus(Form("waterTorusCentral%d_D0_H%d", itube, half), + mWater, mRadiusCentralTore[itube], 0., mRWater, + -mAngle0[itube], 2. * mAngle0[itube]); rotation = new TGeoRotation("rotation", 0., 90., 0.); - transformation = new TGeoCombiTrans(yPos0[itube] + mLpartial0[itube] / 2 * TMath::Sin(mAngle0[itube] * TMath::DegToRad()) - mRadiusCentralTore[itube] * TMath::Cos(mAngle0[itube] * TMath::DegToRad()), 0., 0., rotation); + transformation = new TGeoCombiTrans( + yPos0[itube] + + mLpartial0[itube] / 2 * + TMath::Sin(mAngle0[itube] * TMath::DegToRad()) - + mRadiusCentralTore[itube] * + TMath::Cos(mAngle0[itube] * TMath::DegToRad()), + 0., 0., rotation); cooling->AddNode(waterTorusCentral, ivolume++, transformation); - TGeoVolume* waterTube3 = gGeoManager->MakeTube(Form("waterTube3%d_D0_H%d", 2, half), mWater, 0., mRWater, mLpartial0[itube] / 2.); + TGeoVolume* waterTube3 = + gGeoManager->MakeTube(Form("waterTube3%d_D0_H%d", 2, half), mWater, 0., + mRWater, mLpartial0[itube] / 2.); rotation = new TGeoRotation("rotation", -90., 0 - mAngle0[itube], 0.); - transformation = new TGeoCombiTrans(yPos0[itube], 0., -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - xPos0[itube]), rotation); + transformation = new TGeoCombiTrans( + yPos0[itube], 0., + -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - xPos0[itube]), + rotation); cooling->AddNode(waterTube3, ivolume++, transformation); - TGeoVolume* waterTorus2 = gGeoManager->MakeTorus(Form("waterTorus2%d_D0_H%d", itube, half), mWater, mRadius0[itube], 0., mRWater, 0., mAngle0[itube]); + TGeoVolume* waterTorus2 = gGeoManager->MakeTorus( + Form("waterTorus2%d_D0_H%d", itube, half), mWater, mRadius0[itube], 0., + mRWater, 0., mAngle0[itube]); rotation = new TGeoRotation("rotation", 180., 90., 0.); - transformation = new TGeoCombiTrans(mRadius0[itube] + mXPosition0[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[itube]), rotation); + transformation = new TGeoCombiTrans( + mRadius0[itube] + mXPosition0[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[itube]), + rotation); cooling->AddNode(waterTorus2, ivolume++, transformation); - TGeoVolume* waterTube4 = gGeoManager->MakeTube(Form("waterTube4%d_D0_H%d", itube, half), mWater, 0., mRWater, mLWater0[itube] / 2.); - translation = new TGeoTranslation(mXPosition0[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[itube] / 2.)); + TGeoVolume* waterTube4 = + gGeoManager->MakeTube(Form("waterTube4%d_D0_H%d", itube, half), mWater, + 0., mRWater, mLWater0[itube] / 2.); + translation = new TGeoTranslation(mXPosition0[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[0][0] / 2. + + mMoreLength01 - mLWater0[itube] / 2.)); cooling->AddNode(waterTube4, ivolume++, translation); } - // **************************************************** Tube part ************************************************ - // ****************************** Four parameters mLwater0, mRadius0, mAngle0, mLpartial0 ************************ + // **************************************************** Tube part + // ************************************************ + // ****************************** Four parameters mLwater0, mRadius0, mAngle0, + // mLpartial0 ************************ for (Int_t itube = 0; itube < 3; itube++) { - TGeoVolume* pipeTube1 = gGeoManager->MakeTube(Form("pipeTube1%d_D0_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLWater0[itube] / 2.); - translation = new TGeoTranslation(mXPosition0[itube] - mHalfDiskGap, 0., mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[itube] / 2.); + TGeoVolume* pipeTube1 = + gGeoManager->MakeTube(Form("pipeTube1%d_D0_H%d", itube, half), mPipe, + mRWater, mRWater + mDRPipe, mLWater0[itube] / 2.); + translation = new TGeoTranslation(mXPosition0[itube] - mHalfDiskGap, 0., + mSupportXDimensions[0][0] / 2. + + mMoreLength01 - mLWater0[itube] / 2.); cooling->AddNode(pipeTube1, ivolume++, translation); - TGeoVolume* pipeTorus1 = gGeoManager->MakeTorus(Form("pipeTorus1%d_D0_H%d", itube, half), mPipe, mRadius0[itube], mRWater, mRWater + mDRPipe, 0., mAngle0[itube]); + TGeoVolume* pipeTorus1 = gGeoManager->MakeTorus( + Form("pipeTorus1%d_D0_H%d", itube, half), mPipe, mRadius0[itube], + mRWater, mRWater + mDRPipe, 0., mAngle0[itube]); rotation = new TGeoRotation("rotation", 180., -90., 0.); - transformation = new TGeoCombiTrans(mRadius0[itube] + mXPosition0[itube] - mHalfDiskGap, 0., mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[itube], rotation); + transformation = new TGeoCombiTrans( + mRadius0[itube] + mXPosition0[itube] - mHalfDiskGap, 0., + mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[itube], + rotation); cooling->AddNode(pipeTorus1, ivolume++, transformation); - TGeoVolume* pipeTube2 = gGeoManager->MakeTube(Form("pipeTube2%d_D0_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLpartial0[itube] / 2.); + TGeoVolume* pipeTube2 = gGeoManager->MakeTube( + Form("pipeTube2%d_D0_H%d", itube, half), mPipe, mRWater, + mRWater + mDRPipe, mLpartial0[itube] / 2.); rotation = new TGeoRotation("rotation", 90., 180 - mAngle0[itube], 0.); - xPos0[itube] = mLWater0[itube] + mRadius0[itube] * TMath::Sin(mAngle0[itube] * TMath::DegToRad()) + mLpartial0[itube] / 2 * TMath::Cos(mAngle0[itube] * TMath::DegToRad()); - yPos0[itube] = mXPosition0[itube] - mHalfDiskGap + mRadius0[itube] * (1 - TMath::Cos(mAngle0[itube] * TMath::DegToRad())) + mLpartial0[itube] / 2 * TMath::Sin(mAngle0[itube] * TMath::DegToRad()); - transformation = new TGeoCombiTrans(yPos0[itube], 0., mSupportXDimensions[0][0] / 2. + mMoreLength01 - xPos0[itube], rotation); + xPos0[itube] = + mLWater0[itube] + + mRadius0[itube] * TMath::Sin(mAngle0[itube] * TMath::DegToRad()) + + mLpartial0[itube] / 2 * TMath::Cos(mAngle0[itube] * TMath::DegToRad()); + yPos0[itube] = + mXPosition0[itube] - mHalfDiskGap + + mRadius0[itube] * (1 - TMath::Cos(mAngle0[itube] * TMath::DegToRad())) + + mLpartial0[itube] / 2 * TMath::Sin(mAngle0[itube] * TMath::DegToRad()); + transformation = new TGeoCombiTrans(yPos0[itube], 0., + mSupportXDimensions[0][0] / 2. + + mMoreLength01 - xPos0[itube], + rotation); cooling->AddNode(pipeTube2, ivolume++, transformation); - mRadiusCentralTore[itube] = (mSupportXDimensions[0][0] / 2. + mMoreLength01 - xPos0[itube] - mLpartial0[itube] / 2 * TMath::Cos(mAngle0[itube] * TMath::DegToRad())) / TMath::Sin(mAngle0[itube] * TMath::DegToRad()); - TGeoVolume* pipeTorusCentral = gGeoManager->MakeTorus(Form("pipeTorusCentral%d_D0_H%d", itube, half), mPipe, mRadiusCentralTore[itube], mRWater, - mRWater + mDRPipe, -mAngle0[itube], 2. * mAngle0[itube]); + mRadiusCentralTore[itube] = + (mSupportXDimensions[0][0] / 2. + mMoreLength01 - xPos0[itube] - + mLpartial0[itube] / 2 * + TMath::Cos(mAngle0[itube] * TMath::DegToRad())) / + TMath::Sin(mAngle0[itube] * TMath::DegToRad()); + TGeoVolume* pipeTorusCentral = gGeoManager->MakeTorus( + Form("pipeTorusCentral%d_D0_H%d", itube, half), mPipe, + mRadiusCentralTore[itube], mRWater, mRWater + mDRPipe, -mAngle0[itube], + 2. * mAngle0[itube]); rotation = new TGeoRotation("rotation", 0., 90., 0.); - transformation = new TGeoCombiTrans(yPos0[itube] + mLpartial0[itube] / 2 * TMath::Sin(mAngle0[itube] * TMath::DegToRad()) - mRadiusCentralTore[itube] * TMath::Cos(mAngle0[itube] * TMath::DegToRad()), 0., 0., rotation); + transformation = new TGeoCombiTrans( + yPos0[itube] + + mLpartial0[itube] / 2 * + TMath::Sin(mAngle0[itube] * TMath::DegToRad()) - + mRadiusCentralTore[itube] * + TMath::Cos(mAngle0[itube] * TMath::DegToRad()), + 0., 0., rotation); cooling->AddNode(pipeTorusCentral, ivolume++, transformation); - TGeoVolume* pipeTube3 = gGeoManager->MakeTube(Form("pipeTube3%d_D0_H%d", 2, half), mPipe, mRWater, mRWater + mDRPipe, mLpartial0[itube] / 2.); + TGeoVolume* pipeTube3 = gGeoManager->MakeTube( + Form("pipeTube3%d_D0_H%d", 2, half), mPipe, mRWater, mRWater + mDRPipe, + mLpartial0[itube] / 2.); rotation = new TGeoRotation("rotation", -90., 0 - mAngle0[itube], 0.); - transformation = new TGeoCombiTrans(yPos0[itube], 0., -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - xPos0[itube]), rotation); + transformation = new TGeoCombiTrans( + yPos0[itube], 0., + -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - xPos0[itube]), + rotation); cooling->AddNode(pipeTube3, ivolume++, transformation); - TGeoVolume* pipeTorus2 = gGeoManager->MakeTorus(Form("pipeTorus2%d_D0_H%d", itube, half), mPipe, mRadius0[itube], mRWater, mRWater + mDRPipe, 0., mAngle0[itube]); + TGeoVolume* pipeTorus2 = gGeoManager->MakeTorus( + Form("pipeTorus2%d_D0_H%d", itube, half), mPipe, mRadius0[itube], + mRWater, mRWater + mDRPipe, 0., mAngle0[itube]); rotation = new TGeoRotation("rotation", 180., 90., 0.); - transformation = new TGeoCombiTrans(mRadius0[itube] + mXPosition0[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[itube]), rotation); + transformation = new TGeoCombiTrans( + mRadius0[itube] + mXPosition0[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[itube]), + rotation); cooling->AddNode(pipeTorus2, ivolume++, transformation); - TGeoVolume* pipeTube4 = gGeoManager->MakeTube(Form("pipeTube4%d_D0_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLWater0[itube] / 2.); - translation = new TGeoTranslation(mXPosition0[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[itube] / 2.)); + TGeoVolume* pipeTube4 = + gGeoManager->MakeTube(Form("pipeTube4%d_D0_H%d", itube, half), mPipe, + mRWater, mRWater + mDRPipe, mLWater0[itube] / 2.); + translation = new TGeoTranslation(mXPosition0[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[0][0] / 2. + + mMoreLength01 - mLWater0[itube] / 2.)); cooling->AddNode(pipeTube4, ivolume++, translation); } // *********************************************************************************************** - Double_t deltaz = mHeatExchangerThickness - Geometry::sKaptonOnCarbonThickness * 4 - Geometry::sKaptonGlueThickness * 4 - 2 * mCarbonThickness; + Double_t deltaz = mHeatExchangerThickness - + Geometry::sKaptonOnCarbonThickness * 4 - + Geometry::sKaptonGlueThickness * 4 - 2 * mCarbonThickness; rotation = new TGeoRotation("rotation", -90., 90., 0.); - transformation = - new TGeoCombiTrans(0., 0., mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - 2 * Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - + 2 * Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(cooling, 3, transformation); - transformation = - new TGeoCombiTrans(0., 0., mZPlan[disk] - deltaz / 2. + mCarbonThickness + mRWater + mDRPipe + 2 * Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + mZPlan[disk] - deltaz / 2. + mCarbonThickness + mRWater + mDRPipe + + 2 * Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(cooling, 4, transformation); - // **************************************** Carbon Plates **************************************** + // **************************************** Carbon Plates + // **************************************** auto* carbonPlate = new TGeoVolumeAssembly(Form("carbonPlate_D0_H%d", half)); - auto* carbonBase0 = new TGeoBBox(Form("carbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0] / 2. + mMoreLength01), - (mSupportYDimensions[disk][0]) / 2., mCarbonThickness); - auto* t01 = new TGeoTranslation("t01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + + auto& mftBaseParam = MFTBaseParam::Instance(); + Double_t mReducedX = 0.; + if (mftBaseParam.buildAlignment) { + mReducedX = 0.6; + } + + auto* carbonBase0 = new TGeoBBox( + Form("carbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0] / 2. + mMoreLength01 - mReducedX), + (mSupportYDimensions[disk][0]) / 2., mCarbonThickness); + auto* t01 = new TGeoTranslation( + "t01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); t01->RegisterYourself(); auto* holeCarbon0 = - new TGeoTubeSeg(Form("holeCarbon0_D0_H%d", half), 0., mRMin[disk], mCarbonThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holeCarbon0_D0_H%d", half), 0., mRMin[disk], + mCarbonThickness + 0.000001, 0, 180.); auto* t02 = new TGeoTranslation("t02", 0., -mHalfDiskGap, 0.); t02->RegisterYourself(); auto* carbonhole0 = new TGeoSubtraction(carbonBase0, holeCarbon0, t01, t02); auto* ch0 = new TGeoCompositeShape(Form("Carbon0_D0_H%d", half), carbonhole0); - auto* carbonBaseWithHole0 = new TGeoVolume(Form("carbonBaseWithHole_D0_H%d", half), ch0, mCarbon); + auto* carbonBaseWithHole0 = + new TGeoVolume(Form("carbonBaseWithHole_D0_H%d", half), ch0, mCarbon); carbonBaseWithHole0->SetLineColor(kGray + 3); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - carbonPlate->AddNode(carbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + carbonPlate->AddNode(carbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t ty = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { ty += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partCarbon = - gGeoManager->MakeBox(Form("partCarbon_D0_H%d_%d", half, ipart), mCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., mCarbonThickness); + TGeoVolume* partCarbon = gGeoManager->MakeBox( + Form("partCarbon_D0_H%d_%d", half, ipart), mCarbon, + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., mCarbonThickness); partCarbon->SetLineColor(kGray + 3); auto* t = new TGeoTranslation("t", 0, ty + mHalfDiskGap, mZPlan[disk]); carbonPlate->AddNode(partCarbon, ipart, t); @@ -1044,36 +1411,53 @@ void HeatExchanger::createHalfDisk0(Int_t half) transformation = new TGeoCombiTrans(0., 0., -deltaz / 2., rotation); mHalfDisk->AddNode(carbonPlate, 4, transformation); - // **************************************** Glue Bwtween Carbon Plate and Rohacell Plate **************************************** + // **************************************** Glue Bwtween Carbon Plate and + // Rohacell Plate **************************************** TGeoMedium* mGlueRohacellCarbon = gGeoManager->GetMedium("MFT_Epoxy$"); - auto* glueRohacellCarbon = new TGeoVolumeAssembly(Form("glueRohacellCarbon_D0_H%d", half)); - auto* glueRohacellCarbonBase0 = new TGeoBBox(Form("glueRohacellCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2., - (mSupportYDimensions[disk][0]) / 2., Geometry::sGlueRohacellCarbonThickness); - - auto* translation_gluRC01 = new TGeoTranslation("translation_gluRC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* glueRohacellCarbon = + new TGeoVolumeAssembly(Form("glueRohacellCarbon_D0_H%d", half)); + auto* glueRohacellCarbonBase0 = + new TGeoBBox(Form("glueRohacellCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. - mReducedX, + (mSupportYDimensions[disk][0]) / 2., + Geometry::sGlueRohacellCarbonThickness); + + auto* translation_gluRC01 = new TGeoTranslation( + "translation_gluRC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_gluRC01->RegisterYourself(); - auto* translation_gluRC02 = new TGeoTranslation("translation_gluRC02", 0., -mHalfDiskGap, 0.); + auto* translation_gluRC02 = + new TGeoTranslation("translation_gluRC02", 0., -mHalfDiskGap, 0.); translation_gluRC02->RegisterYourself(); - auto* holeglueRohacellCarbon0 = - new TGeoTubeSeg(Form("holeglueRohacellCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sGlueRohacellCarbonThickness + 0.000001, 0, 180.); + auto* holeglueRohacellCarbon0 = new TGeoTubeSeg( + Form("holeglueRohacellCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sGlueRohacellCarbonThickness + 0.000001, 0, 180.); - auto* glueRohacellCarbonhole0 = new TGeoSubtraction(glueRohacellCarbonBase0, holeglueRohacellCarbon0, translation_gluRC01, translation_gluRC02); - auto* gRC0 = new TGeoCompositeShape(Form("glueRohacellCarbon0_D0_H%d", half), glueRohacellCarbonhole0); - auto* glueRohacellCarbonBaseWithHole0 = new TGeoVolume(Form("glueRohacellCarbonWithHole_D0_H%d", half), gRC0, mGlueRohacellCarbon); + auto* glueRohacellCarbonhole0 = + new TGeoSubtraction(glueRohacellCarbonBase0, holeglueRohacellCarbon0, + translation_gluRC01, translation_gluRC02); + auto* gRC0 = new TGeoCompositeShape(Form("glueRohacellCarbon0_D0_H%d", half), + glueRohacellCarbonhole0); + auto* glueRohacellCarbonBaseWithHole0 = + new TGeoVolume(Form("glueRohacellCarbonWithHole_D0_H%d", half), gRC0, + mGlueRohacellCarbon); glueRohacellCarbonBaseWithHole0->SetLineColor(kGreen); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - glueRohacellCarbon->AddNode(glueRohacellCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + glueRohacellCarbon->AddNode(glueRohacellCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyGRC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyGRC += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partGlueRohacellCarbon = - gGeoManager->MakeBox(Form("partGlueRohacellCarbon_D0_H%d_%d", half, ipart), mGlueRohacellCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sGlueRohacellCarbonThickness); + TGeoVolume* partGlueRohacellCarbon = gGeoManager->MakeBox( + Form("partGlueRohacellCarbon_D0_H%d_%d", half, ipart), + mGlueRohacellCarbon, mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., + Geometry::sGlueRohacellCarbonThickness); partGlueRohacellCarbon->SetLineColor(kGreen); auto* t = new TGeoTranslation("t", 0, tyGRC + mHalfDiskGap, mZPlan[disk]); glueRohacellCarbon->AddNode(partGlueRohacellCarbon, ipart, t); @@ -1081,41 +1465,62 @@ void HeatExchanger::createHalfDisk0(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(glueRohacellCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness), rotation); + transformation = new TGeoCombiTrans(0., 0., + -(deltaz / 2. - mCarbonThickness - + Geometry::sGlueRohacellCarbonThickness), + rotation); mHalfDisk->AddNode(glueRohacellCarbon, 4, transformation); - // **************************************** Kapton on Carbon Plate **************************************** + // **************************************** Kapton on Carbon Plate + // **************************************** TGeoMedium* mKaptonOnCarbon = gGeoManager->GetMedium("MFT_Kapton$"); - auto* kaptonOnCarbon = new TGeoVolumeAssembly(Form("kaptonOnCarbon_D0_H%d", half)); - auto* kaptonOnCarbonBase0 = new TGeoBBox(Form("kaptonOnCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0] / 2. + mMoreLength01), - (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonOnCarbonThickness); - - auto* translation_KC01 = new TGeoTranslation("translation_KC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* kaptonOnCarbon = + new TGeoVolumeAssembly(Form("kaptonOnCarbon_D0_H%d", half)); + auto* kaptonOnCarbonBase0 = new TGeoBBox( + Form("kaptonOnCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0] / 2. + mMoreLength01 - mReducedX), + (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonOnCarbonThickness); + + auto* translation_KC01 = new TGeoTranslation( + "translation_KC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_KC01->RegisterYourself(); - auto* translation_KC02 = new TGeoTranslation("translation_KC02", 0., -mHalfDiskGap, 0.); + auto* translation_KC02 = + new TGeoTranslation("translation_KC02", 0., -mHalfDiskGap, 0.); translation_KC02->RegisterYourself(); auto* holekaptonOnCarbon0 = - new TGeoTubeSeg(Form("holekaptonOnCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sKaptonOnCarbonThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holekaptonOnCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sKaptonOnCarbonThickness + 0.000001, 0, 180.); - auto* kaptonOnCarbonhole0 = new TGeoSubtraction(kaptonOnCarbonBase0, holekaptonOnCarbon0, translation_KC01, translation_KC02); - auto* KC0 = new TGeoCompositeShape(Form("kaptonOnCarbon_D0_H%d", half), kaptonOnCarbonhole0); - auto* kaptonOnCarbonBaseWithHole0 = new TGeoVolume(Form("kaptonOnCarbonWithHole_D0_H%d", half), KC0, mKaptonOnCarbon); + auto* kaptonOnCarbonhole0 = + new TGeoSubtraction(kaptonOnCarbonBase0, holekaptonOnCarbon0, + translation_KC01, translation_KC02); + auto* KC0 = new TGeoCompositeShape(Form("kaptonOnCarbon_D0_H%d", half), + kaptonOnCarbonhole0); + auto* kaptonOnCarbonBaseWithHole0 = new TGeoVolume( + Form("kaptonOnCarbonWithHole_D0_H%d", half), KC0, mKaptonOnCarbon); kaptonOnCarbonBaseWithHole0->SetLineColor(kMagenta); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - kaptonOnCarbon->AddNode(kaptonOnCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + kaptonOnCarbon->AddNode(kaptonOnCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyKC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyKC += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partkaptonOnCarbonBase = - gGeoManager->MakeBox(Form("partkaptonOnCarbon_D0_H%d_%d", half, ipart), mKaptonOnCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonOnCarbonThickness); + TGeoVolume* partkaptonOnCarbonBase = gGeoManager->MakeBox( + Form("partkaptonOnCarbon_D0_H%d_%d", half, ipart), mKaptonOnCarbon, + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., + Geometry::sKaptonOnCarbonThickness); partkaptonOnCarbonBase->SetLineColor(kMagenta); auto* t = new TGeoTranslation("t", 0, tyKC + mHalfDiskGap, mZPlan[disk]); kaptonOnCarbon->AddNode(partkaptonOnCarbonBase, ipart, t); @@ -1123,41 +1528,63 @@ void HeatExchanger::createHalfDisk0(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + Geometry::sKaptonGlueThickness * 2, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + + Geometry::sKaptonGlueThickness * 2, + rotation); mHalfDisk->AddNode(kaptonOnCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + Geometry::sKaptonGlueThickness * 2), rotation); + transformation = new TGeoCombiTrans( + 0., 0., + -(deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + + Geometry::sKaptonGlueThickness * 2), + rotation); mHalfDisk->AddNode(kaptonOnCarbon, 4, transformation); - // **************************************** Kapton glue on the carbon plate **************************************** + // **************************************** Kapton glue on the carbon plate + // **************************************** TGeoMedium* mGlueKaptonCarbon = gGeoManager->GetMedium("MFT_Epoxy$"); - auto* glueKaptonCarbon = new TGeoVolumeAssembly(Form("glueKaptonCarbon_D0_H%d", half)); - auto* glueKaptonCarbonBase0 = new TGeoBBox(Form("glueKaptonCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0] / 2. + mMoreLength01), - (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonGlueThickness); - - auto* translation_gluKC01 = new TGeoTranslation("translation_gluKC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* glueKaptonCarbon = + new TGeoVolumeAssembly(Form("glueKaptonCarbon_D0_H%d", half)); + auto* glueKaptonCarbonBase0 = new TGeoBBox( + Form("glueKaptonCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0] / 2. + mMoreLength01 - mReducedX), + (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonGlueThickness); + + auto* translation_gluKC01 = new TGeoTranslation( + "translation_gluKC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_gluKC01->RegisterYourself(); - auto* translation_gluKC02 = new TGeoTranslation("translation_gluKC02", 0., -mHalfDiskGap, 0.); + auto* translation_gluKC02 = + new TGeoTranslation("translation_gluKC02", 0., -mHalfDiskGap, 0.); translation_gluKC02->RegisterYourself(); - auto* holeglueKaptonCarbon0 = - new TGeoTubeSeg(Form("holeglueKaptonCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sKaptonGlueThickness + 0.000001, 0, 180.); + auto* holeglueKaptonCarbon0 = new TGeoTubeSeg( + Form("holeglueKaptonCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sKaptonGlueThickness + 0.000001, 0, 180.); - auto* glueKaptonCarbonhole0 = new TGeoSubtraction(glueKaptonCarbonBase0, holeglueKaptonCarbon0, translation_gluKC01, translation_gluKC02); - auto* gKC0 = new TGeoCompositeShape(Form("glueKaptonCarbon0_D0_H%d", half), glueKaptonCarbonhole0); - auto* glueKaptonCarbonBaseWithHole0 = new TGeoVolume(Form("glueKaptonCarbonWithHole_D0_H%d", half), gKC0, mGlueKaptonCarbon); + auto* glueKaptonCarbonhole0 = + new TGeoSubtraction(glueKaptonCarbonBase0, holeglueKaptonCarbon0, + translation_gluKC01, translation_gluKC02); + auto* gKC0 = new TGeoCompositeShape(Form("glueKaptonCarbon0_D0_H%d", half), + glueKaptonCarbonhole0); + auto* glueKaptonCarbonBaseWithHole0 = new TGeoVolume( + Form("glueKaptonCarbonWithHole_D0_H%d", half), gKC0, mGlueKaptonCarbon); glueKaptonCarbonBaseWithHole0->SetLineColor(kGreen); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - glueKaptonCarbon->AddNode(glueKaptonCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + glueKaptonCarbon->AddNode(glueKaptonCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyGKC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyGKC += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partGlueKaptonCarbon = - gGeoManager->MakeBox(Form("partGlueKaptonCarbon_D0_H%d_%d", half, ipart), mGlueKaptonCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonGlueThickness); + TGeoVolume* partGlueKaptonCarbon = gGeoManager->MakeBox( + Form("partGlueKaptonCarbon_D0_H%d_%d", half, ipart), mGlueKaptonCarbon, + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonGlueThickness); partGlueKaptonCarbon->SetLineColor(kGreen); auto* t = new TGeoTranslation("t", 0, tyGKC + mHalfDiskGap, mZPlan[disk]); glueKaptonCarbon->AddNode(partGlueKaptonCarbon, ipart, t); @@ -1165,19 +1592,30 @@ void HeatExchanger::createHalfDisk0(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness, + rotation); mHalfDisk->AddNode(glueKaptonCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness), rotation); + transformation = new TGeoCombiTrans( + 0., 0., + -(deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness), + rotation); mHalfDisk->AddNode(glueKaptonCarbon, 4, transformation); - // **************************************** Rohacell Plate **************************************** - auto* rohacellPlate = new TGeoVolumeAssembly(Form("rohacellPlate_D0_H%d", half)); - auto* rohacellBase0 = new TGeoBBox(Form("rohacellBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2., (mSupportYDimensions[disk][0]) / 2., - mRohacellThickness); - auto* holeRohacell0 = new TGeoTubeSeg(Form("holeRohacell0_D0_H%d", half), 0., mRMin[disk], mRohacellThickness + 0.000001, 0, 180.); - - // **************************************** GROOVES ************************************************* - // Creating grooves or not according to sGrooves + // **************************************** Rohacell Plate + // **************************************** + auto* rohacellPlate = + new TGeoVolumeAssembly(Form("rohacellPlate_D0_H%d", half)); + auto* rohacellBase0 = new TGeoBBox( + Form("rohacellBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2., + (mSupportYDimensions[disk][0]) / 2., mRohacellThickness); + auto* holeRohacell0 = + new TGeoTubeSeg(Form("holeRohacell0_D0_H%d", half), 0., mRMin[disk], + mRohacellThickness + 0.000001, 0, 180.); + + // **************************************** GROOVES + // ************************************************* Creating grooves or not + // according to sGrooves Double_t diameter = 0.21; // groove diameter Double_t epsilon = 0.06; // outside shift of the goove Int_t iCount = 0; @@ -1189,20 +1627,31 @@ void HeatExchanger::createHalfDisk0(Int_t half) TGeoCompositeShape* rohacellGroove[300]; for (Int_t igroove = 0; igroove < 3; igroove++) { - grooveTube[0][igroove] = new TGeoTube("linear", 0., diameter, mLWater0[igroove] / 2.); - grooveTorus[1][igroove] = new TGeoTorus("SideTorus", mRadius0[igroove], 0., diameter, 0., mAngle0[igroove]); - grooveTube[2][igroove] = new TGeoTube("tiltedLinear", 0., diameter, mLpartial0[igroove] / 2.); - grooveTorus[3][igroove] = new TGeoTorus("centralTorus", mRadiusCentralTore[igroove], 0., diameter, -mAngle0[igroove], 2. * mAngle0[igroove]); - grooveTube[4][igroove] = new TGeoTube("tiltedLinear", 0., diameter, mLpartial0[igroove] / 2.); - grooveTorus[5][igroove] = new TGeoTorus("SideTorus", mRadius0[igroove], 0., diameter, 0., mAngle0[igroove]); - grooveTube[6][igroove] = new TGeoTube("linear", 0., diameter, mLWater0[igroove] / 2.); + grooveTube[0][igroove] = + new TGeoTube("linear", 0., diameter, mLWater0[igroove] / 2.); + grooveTorus[1][igroove] = new TGeoTorus("SideTorus", mRadius0[igroove], 0., + diameter, 0., mAngle0[igroove]); + grooveTube[2][igroove] = + new TGeoTube("tiltedLinear", 0., diameter, mLpartial0[igroove] / 2.); + grooveTorus[3][igroove] = + new TGeoTorus("centralTorus", mRadiusCentralTore[igroove], 0., diameter, + -mAngle0[igroove], 2. * mAngle0[igroove]); + grooveTube[4][igroove] = + new TGeoTube("tiltedLinear", 0., diameter, mLpartial0[igroove] / 2.); + grooveTorus[5][igroove] = new TGeoTorus("SideTorus", mRadius0[igroove], 0., + diameter, 0., mAngle0[igroove]); + grooveTube[6][igroove] = + new TGeoTube("linear", 0., diameter, mLWater0[igroove] / 2.); } // Rotation matrix TGeoRotation* rotationLinear = new TGeoRotation("rotation", -90., 90., 0.); - TGeoRotation* rotationSideTorusL = new TGeoRotation("rotationSideTorusLeft", -90., 0., 0.); - TGeoRotation* rotationSideTorusR = new TGeoRotation("rotationSideTorusRight", 90., 180., 180.); - TGeoRotation* rotationCentralTorus = new TGeoRotation("rotationCentralTorus", 90., 0., 0.); + TGeoRotation* rotationSideTorusL = + new TGeoRotation("rotationSideTorusLeft", -90., 0., 0.); + TGeoRotation* rotationSideTorusR = + new TGeoRotation("rotationSideTorusRight", 90., 180., 180.); + TGeoRotation* rotationCentralTorus = + new TGeoRotation("rotationCentralTorus", 90., 0., 0.); TGeoRotation* rotationTiltedLinearR; TGeoRotation* rotationTiltedLinearL; @@ -1210,51 +1659,96 @@ void HeatExchanger::createHalfDisk0(Int_t half) if (Geometry::sGrooves == 1) { for (Int_t iface = 1; iface > -2; iface -= 2) { // front and rear for (Int_t igroove = 0; igroove < 3; igroove++) { // 3 grooves - mPosition[igroove] = mXPosition0[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap; + mPosition[igroove] = mXPosition0[igroove] - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap; for (Int_t ip = 0; ip < 7; ip++) { // each groove is made of 7 parts switch (ip) { case 0: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - mLWater0[igroove] / 2., mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2. + mMoreLength01 - + mLWater0[igroove] / 2., + mPosition[igroove], iface * (mRohacellThickness + epsilon), + rotationLinear); if (igroove == 0 && iface == 1) { - rohacellBaseGroove[0] = new TGeoSubtraction(rohacellBase0, grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); - rohacellGroove[0] = new TGeoCompositeShape(Form("rohacell0Groove%d_G%d_F%d_H%d", ip, igroove, iface, half), rohacellBaseGroove[0]); + rohacellBaseGroove[0] = + new TGeoSubtraction(rohacellBase0, grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); + rohacellGroove[0] = + new TGeoCompositeShape(Form("rohacell0Groove%d_G%d_F%d_H%d", + ip, igroove, iface, half), + rohacellBaseGroove[0]); }; break; case 1: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - mLWater0[igroove], mRadius0[igroove] + mXPosition0[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, iface * (mRohacellThickness + epsilon), rotationSideTorusR); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2. + mMoreLength01 - + mLWater0[igroove], + mRadius0[igroove] + mXPosition0[igroove] - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationSideTorusR); break; case 2: // Linear tilted - rotationTiltedLinearR = new TGeoRotation("rotationTiltedLinearRight", 90. - mAngle0[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - xPos0[igroove], yPos0[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); + rotationTiltedLinearR = new TGeoRotation( + "rotationTiltedLinearRight", 90. - mAngle0[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2. + mMoreLength01 - + xPos0[igroove], + yPos0[igroove] - mSupportYDimensions[disk][0] / 2. - + mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); break; case 3: // Central Torus - transfo[ip][igroove] = new TGeoCombiTrans(0., yPos0[igroove] + mLpartial0[igroove] / 2 * TMath::Sin(mAngle0[igroove] * TMath::DegToRad()) - mRadiusCentralTore[igroove] * TMath::Cos(mAngle0[igroove] * TMath::DegToRad()) - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationCentralTorus); + transfo[ip][igroove] = new TGeoCombiTrans( + 0., + yPos0[igroove] + + mLpartial0[igroove] / 2 * + TMath::Sin(mAngle0[igroove] * TMath::DegToRad()) - + mRadiusCentralTore[igroove] * + TMath::Cos(mAngle0[igroove] * TMath::DegToRad()) - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationCentralTorus); break; case 4: // Linear tilted - rotationTiltedLinearL = new TGeoRotation("rotationTiltedLinearLeft", 90. + mAngle0[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - xPos0[igroove]), yPos0[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); + rotationTiltedLinearL = new TGeoRotation( + "rotationTiltedLinearLeft", 90. + mAngle0[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - + xPos0[igroove]), + yPos0[igroove] - mSupportYDimensions[disk][0] / 2. - + mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); break; case 5: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - mLWater0[igroove]), mRadius0[igroove] + mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationSideTorusL); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - + mLWater0[igroove]), + mRadius0[igroove] + mPosition[igroove], + iface * (mRohacellThickness + epsilon), rotationSideTorusL); break; case 6: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - mLWater0[igroove] / 2.), mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - + mLWater0[igroove] / 2.), + mPosition[igroove], iface * (mRohacellThickness + epsilon), + rotationLinear); break; } if (!(ip == 0 && igroove == 0 && iface == 1)) { if (ip & 1) { - rohacellBaseGroove[iCount] = new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, + transfo[ip][igroove]); } else { - rohacellBaseGroove[iCount] = new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, + transfo[ip][igroove]); } - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell0Groove%d_G%d_F%d_H%d", iCount, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell0Groove%d_G%d_F%d_H%d", + iCount, igroove, iface, half), + rohacellBaseGroove[iCount]); } iCount++; } @@ -1270,88 +1764,150 @@ void HeatExchanger::createHalfDisk0(Int_t half) rohacellBase = new TGeoSubtraction(rohacellBase0, holeRohacell0, t01, t02); } if (Geometry::sGrooves == 1) { - rohacellBase = new TGeoSubtraction(rohacellGroove[iCount - 1], holeRohacell0, t01, t02); + rohacellBase = new TGeoSubtraction(rohacellGroove[iCount - 1], + holeRohacell0, t01, t02); } - auto* rh0 = new TGeoCompositeShape(Form("rohacellTore%d_D0_H%d", 0, half), rohacellBase); - auto* rohacellBaseWithHole = new TGeoVolume(Form("rohacellBaseWithHole_D0_H%d", half), rh0, mRohacell); + auto* rh0 = new TGeoCompositeShape(Form("rohacellTore%d_D0_H%d", 0, half), + rohacellBase); + auto* rohacellBaseWithHole = + new TGeoVolume(Form("rohacellBaseWithHole_D0_H%d", half), rh0, mRohacell); TGeoVolume* partRohacell; rohacellBaseWithHole->SetLineColor(kGray); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - rohacellPlate->AddNode(rohacellBaseWithHole, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + rohacellPlate->AddNode(rohacellBaseWithHole, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); ty = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { ty += mSupportYDimensions[disk][ipart] / 2.; auto* t = new TGeoTranslation("t", 0, ty + mHalfDiskGap, mZPlan[disk]); - auto* partRohacell0 = new TGeoBBox(Form("rohacellBase0_D0_H%d_%d", half, ipart), mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., mRohacellThickness); + auto* partRohacell0 = + new TGeoBBox(Form("rohacellBase0_D0_H%d_%d", half, ipart), + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., mRohacellThickness); if (Geometry::sGrooves == 1) { - // ************************ Creating grooves for the other parts of the rohacell plate ********************** + // ************************ Creating grooves for the other parts of the + // rohacell plate ********************** Double_t mShift; for (Int_t iface = 1; iface > -2; iface -= 2) { // front and rear for (Int_t igroove = 0; igroove < 3; igroove++) { // 3 grooves if (ipart == 1) { - mPosition[ipart] = mXPosition0[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1]; + mPosition[ipart] = + mXPosition0[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1]; mShift = -mSupportYDimensions[disk][ipart - 1]; }; if (ipart == 2) { - mPosition[ipart] = mXPosition0[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2]; - mShift = -mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2]; + mPosition[ipart] = + mXPosition0[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2]; + mShift = -mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2]; }; if (ipart == 3) { - mPosition[ipart] = mXPosition0[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2] - mSupportYDimensions[disk][ipart - 3]; - mShift = -mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2] - mSupportYDimensions[disk][ipart - 3]; + mPosition[ipart] = + mXPosition0[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2] - + mSupportYDimensions[disk][ipart - 3]; + mShift = -mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2] - + mSupportYDimensions[disk][ipart - 3]; }; for (Int_t ip = 0; ip < 7; ip++) { // each groove is made of 7 parts switch (ip) { case 0: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[0][0] / 2. - mLWater0[igroove] / 2., mPosition[ipart], iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[0][0] / 2. - mLWater0[igroove] / 2., + mPosition[ipart], iface * (mRohacellThickness + epsilon), + rotationLinear); if (igroove == 0 && iface == 1) { - rohacellBaseGroove[iCount] = new TGeoSubtraction(partRohacell0, grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell0Groove%d_G%d_F%d_H%d", ip, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellBaseGroove[iCount] = + new TGeoSubtraction(partRohacell0, grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell0Groove%d_G%d_F%d_H%d", + ip, igroove, iface, half), + rohacellBaseGroove[iCount]); }; break; case 1: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[igroove], mPosition[ipart] + mRadius0[igroove], - iface * (mRohacellThickness + epsilon), rotationSideTorusR); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[0][0] / 2. + mMoreLength01 - + mLWater0[igroove], + mPosition[ipart] + mRadius0[igroove], + iface * (mRohacellThickness + epsilon), rotationSideTorusR); break; case 2: // Linear tilted - rotationTiltedLinearR = new TGeoRotation("rotationTiltedLinearRight", 90. - mAngle0[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[0][0] / 2. + mMoreLength01 - xPos0[igroove], yPos0[igroove] + mShift - mHalfDiskGap - mSupportYDimensions[disk][ipart] / 2., iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); + rotationTiltedLinearR = new TGeoRotation( + "rotationTiltedLinearRight", 90. - mAngle0[igroove], 90., 0.); + transfo[ip][igroove] = + new TGeoCombiTrans(mSupportXDimensions[0][0] / 2. + + mMoreLength01 - xPos0[igroove], + yPos0[igroove] + mShift - mHalfDiskGap - + mSupportYDimensions[disk][ipart] / 2., + iface * (mRohacellThickness + epsilon), + rotationTiltedLinearR); break; case 3: // Central Torus - transfo[ip][igroove] = new TGeoCombiTrans(0., mPosition[ipart] + yPos0[igroove] + mLpartial0[igroove] / 2 * TMath::Sin(mAngle0[igroove] * TMath::DegToRad()) - mRadiusCentralTore[igroove] * TMath::Cos(mAngle0[igroove] * TMath::DegToRad()) - mXPosition0[igroove], - iface * (mRohacellThickness + epsilon), rotationCentralTorus); + transfo[ip][igroove] = new TGeoCombiTrans( + 0., + mPosition[ipart] + yPos0[igroove] + + mLpartial0[igroove] / 2 * + TMath::Sin(mAngle0[igroove] * TMath::DegToRad()) - + mRadiusCentralTore[igroove] * + TMath::Cos(mAngle0[igroove] * TMath::DegToRad()) - + mXPosition0[igroove], + iface * (mRohacellThickness + epsilon), rotationCentralTorus); break; case 4: // Linear tilted - rotationTiltedLinearL = new TGeoRotation("rotationTiltedLinearLeft", 90. + mAngle0[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[0][0] / 2. + mMoreLength01 - xPos0[igroove]), yPos0[igroove] + mPosition[ipart] - mXPosition0[igroove], - iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); + rotationTiltedLinearL = new TGeoRotation( + "rotationTiltedLinearLeft", 90. + mAngle0[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - + xPos0[igroove]), + yPos0[igroove] + mPosition[ipart] - mXPosition0[igroove], + iface * (mRohacellThickness + epsilon), + rotationTiltedLinearL); break; case 5: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[igroove]), mRadius0[igroove] + mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationSideTorusL); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - + mLWater0[igroove]), + mRadius0[igroove] + mPosition[ipart], + iface * (mRohacellThickness + epsilon), rotationSideTorusL); break; case 6: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[0][0] / 2. + mMoreLength01 - mLWater0[igroove] / 2.), mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[0][0] / 2. + mMoreLength01 - + mLWater0[igroove] / 2.), + mPosition[ipart], iface * (mRohacellThickness + epsilon), + rotationLinear); break; } if (!(ip == 0 && igroove == 0 && iface == 1)) { if (ip & 1) { - rohacellBaseGroove[iCount] = new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTorus[ip][igroove], + nullptr, transfo[ip][igroove]); } else { - rohacellBaseGroove[iCount] = new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); } - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell0Groove%d_G%d_F%d_H%d", iCount, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell0Groove%d_G%d_F%d_H%d", + iCount, igroove, iface, half), + rohacellBaseGroove[iCount]); } iCount++; } @@ -1365,31 +1921,43 @@ void HeatExchanger::createHalfDisk0(Int_t half) TGeoBBox* notchRohacell0; TGeoTranslation* tnotch0; if (ipart == (mNPart[disk] - 1)) { - notchRohacell0 = new TGeoBBox(Form("notchRohacell0_D0_H%d", half), 1.1, 0.4, mRohacellThickness + 0.000001); - tnotch0 = new TGeoTranslation("tnotch0", 0., mSupportYDimensions[disk][ipart] / 2., 0.); + notchRohacell0 = new TGeoBBox(Form("notchRohacell0_D0_H%d", half), 1.1, + 0.4, mRohacellThickness + 0.000001); + tnotch0 = new TGeoTranslation("tnotch0", 0., + mSupportYDimensions[disk][ipart] / 2., 0.); tnotch0->RegisterYourself(); } //============================================================= if (Geometry::sGrooves == 0) { if (ipart == (mNPart[disk] - 1)) { - partRohacellini = new TGeoSubtraction(partRohacell0, notchRohacell0, nullptr, tnotch0); - auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D0_H%d", 0, half), partRohacellini); - partRohacell = new TGeoVolume(Form("partRohacelli_D0_H%d_%d", half, ipart), rhinit, mRohacell); + partRohacellini = new TGeoSubtraction(partRohacell0, notchRohacell0, + nullptr, tnotch0); + auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D0_H%d", 0, half), + partRohacellini); + partRohacell = new TGeoVolume( + Form("partRohacelli_D0_H%d_%d", half, ipart), rhinit, mRohacell); } if (ipart < (mNPart[disk] - 1)) { - partRohacell = new TGeoVolume(Form("partRohacelli_D0_H%d_%d", half, ipart), partRohacell0, mRohacell); + partRohacell = + new TGeoVolume(Form("partRohacelli_D0_H%d_%d", half, ipart), + partRohacell0, mRohacell); } } if (Geometry::sGrooves == 1) { if (ipart == (mNPart[disk] - 1)) { - partRohacellini = new TGeoSubtraction(rohacellGroove[iCount - 1], notchRohacell0, nullptr, tnotch0); - auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D0_H%d", 0, half), partRohacellini); - partRohacell = new TGeoVolume(Form("partRohacelli_D0_H%d_%d", half, ipart), rhinit, mRohacell); + partRohacellini = new TGeoSubtraction(rohacellGroove[iCount - 1], + notchRohacell0, nullptr, tnotch0); + auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D0_H%d", 0, half), + partRohacellini); + partRohacell = new TGeoVolume( + Form("partRohacelli_D0_H%d_%d", half, ipart), rhinit, mRohacell); } if (ipart < (mNPart[disk] - 1)) { - partRohacell = new TGeoVolume(Form("partRohacelli_D0_H%d_%d", half, ipart), rohacellGroove[iCount - 1], mRohacell); + partRohacell = + new TGeoVolume(Form("partRohacelli_D0_H%d_%d", half, ipart), + rohacellGroove[iCount - 1], mRohacell); } } //=========================================================================================================== @@ -1398,11 +1966,15 @@ void HeatExchanger::createHalfDisk0(Int_t half) rohacellPlate->AddNode(partRohacell, ipart, t); ty += mSupportYDimensions[disk][ipart] / 2.; - //========== insert to locate the rohacell plate compare to the disk support ============= + //========== insert to locate the rohacell plate compare to the disk support + //============= if (ipart == (mNPart[disk] - 1)) { TGeoTranslation* tinsert0; - TGeoVolume* insert0 = gGeoManager->MakeBox(Form("insert0_H%d_%d", half, ipart), mPeek, 1.0, 0.35 / 2., mRohacellThickness); - Double_t ylocation = mSupportYDimensions[disk][0] + mHalfDiskGap - 0.35 / 2.; + TGeoVolume* insert0 = + gGeoManager->MakeBox(Form("insert0_H%d_%d", half, ipart), mPeek, 1.0, + 0.35 / 2., mRohacellThickness); + Double_t ylocation = + mSupportYDimensions[disk][0] + mHalfDiskGap - 0.35 / 2.; for (Int_t ip = 1; ip < mNPart[disk]; ip++) { ylocation = ylocation + mSupportYDimensions[disk][ip]; } @@ -1447,134 +2019,251 @@ void HeatExchanger::createHalfDisk1(Int_t half) TGeoRotation* rotation = nullptr; TGeoCombiTrans* transformation = nullptr; - // **************************************** Water part **************************************** - // ********************** Four parameters mLwater1, mRadius1, mAngle1, mLpartial1 ************* + // **************************************** Water part + // **************************************** + // ********************** Four parameters mLwater1, mRadius1, mAngle1, + // mLpartial1 ************* Double_t ivolume = 100; // offset chamber 1 Double_t mRadiusCentralTore[4]; Double_t xPos1[4]; Double_t yPos1[4]; for (Int_t itube = 0; itube < 3; itube++) { - TGeoVolume* waterTube1 = gGeoManager->MakeTube(Form("waterTube1%d_D1_H%d", itube, half), mWater, 0., mRWater, mLWater1[itube] / 2.); - translation = new TGeoTranslation(mXPosition1[itube] - mHalfDiskGap, 0., mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[itube] / 2.); + TGeoVolume* waterTube1 = + gGeoManager->MakeTube(Form("waterTube1%d_D1_H%d", itube, half), mWater, + 0., mRWater, mLWater1[itube] / 2.); + translation = new TGeoTranslation(mXPosition1[itube] - mHalfDiskGap, 0., + mSupportXDimensions[1][0] / 2. + + mMoreLength01 - mLWater1[itube] / 2.); cooling->AddNode(waterTube1, ivolume++, translation); - TGeoVolume* waterTorus1 = gGeoManager->MakeTorus(Form("waterTorus1%d_D1_H%d", itube, half), mWater, mRadius1[itube], 0., mRWater, 0., mAngle1[itube]); + TGeoVolume* waterTorus1 = gGeoManager->MakeTorus( + Form("waterTorus1%d_D1_H%d", itube, half), mWater, mRadius1[itube], 0., + mRWater, 0., mAngle1[itube]); rotation = new TGeoRotation("rotation", 180., -90., 0.); - transformation = new TGeoCombiTrans(mRadius1[itube] + mXPosition1[itube] - mHalfDiskGap, 0., mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[itube], rotation); + transformation = new TGeoCombiTrans( + mRadius1[itube] + mXPosition1[itube] - mHalfDiskGap, 0., + mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[itube], + rotation); cooling->AddNode(waterTorus1, ivolume++, transformation); - TGeoVolume* waterTube2 = gGeoManager->MakeTube(Form("waterTube2%d_D1_H%d", itube, half), mWater, 0., mRWater, mLpartial1[itube] / 2.); + TGeoVolume* waterTube2 = + gGeoManager->MakeTube(Form("waterTube2%d_D1_H%d", itube, half), mWater, + 0., mRWater, mLpartial1[itube] / 2.); rotation = new TGeoRotation("rotation", 90., 180 - mAngle1[itube], 0.); - xPos1[itube] = mLWater1[itube] + mRadius1[itube] * TMath::Sin(mAngle1[itube] * TMath::DegToRad()) + mLpartial1[itube] / 2 * TMath::Cos(mAngle1[itube] * TMath::DegToRad()); - yPos1[itube] = mXPosition1[itube] - mHalfDiskGap + mRadius1[itube] * (1 - TMath::Cos(mAngle1[itube] * TMath::DegToRad())) + mLpartial1[itube] / 2 * TMath::Sin(mAngle1[itube] * TMath::DegToRad()); - transformation = new TGeoCombiTrans(yPos1[itube], 0., mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[itube], rotation); + xPos1[itube] = + mLWater1[itube] + + mRadius1[itube] * TMath::Sin(mAngle1[itube] * TMath::DegToRad()) + + mLpartial1[itube] / 2 * TMath::Cos(mAngle1[itube] * TMath::DegToRad()); + yPos1[itube] = + mXPosition1[itube] - mHalfDiskGap + + mRadius1[itube] * (1 - TMath::Cos(mAngle1[itube] * TMath::DegToRad())) + + mLpartial1[itube] / 2 * TMath::Sin(mAngle1[itube] * TMath::DegToRad()); + transformation = new TGeoCombiTrans(yPos1[itube], 0., + mSupportXDimensions[1][0] / 2. + + mMoreLength01 - xPos1[itube], + rotation); cooling->AddNode(waterTube2, ivolume++, transformation); - mRadiusCentralTore[itube] = (mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[itube] - mLpartial1[itube] / 2 * TMath::Cos(mAngle1[itube] * TMath::DegToRad())) / TMath::Sin(mAngle1[itube] * TMath::DegToRad()); - TGeoVolume* waterTorusCentral = gGeoManager->MakeTorus(Form("waterTorusCentral%d_D1_H%d", itube, half), mWater, mRadiusCentralTore[itube], 0., mRWater, - -mAngle1[itube], 2. * mAngle1[itube]); + mRadiusCentralTore[itube] = + (mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[itube] - + mLpartial1[itube] / 2 * + TMath::Cos(mAngle1[itube] * TMath::DegToRad())) / + TMath::Sin(mAngle1[itube] * TMath::DegToRad()); + TGeoVolume* waterTorusCentral = + gGeoManager->MakeTorus(Form("waterTorusCentral%d_D1_H%d", itube, half), + mWater, mRadiusCentralTore[itube], 0., mRWater, + -mAngle1[itube], 2. * mAngle1[itube]); rotation = new TGeoRotation("rotation", 0., 90., 0.); - transformation = new TGeoCombiTrans(yPos1[itube] + mLpartial1[itube] / 2 * TMath::Sin(mAngle1[itube] * TMath::DegToRad()) - mRadiusCentralTore[itube] * TMath::Cos(mAngle1[itube] * TMath::DegToRad()), 0., 0., rotation); + transformation = new TGeoCombiTrans( + yPos1[itube] + + mLpartial1[itube] / 2 * + TMath::Sin(mAngle1[itube] * TMath::DegToRad()) - + mRadiusCentralTore[itube] * + TMath::Cos(mAngle1[itube] * TMath::DegToRad()), + 0., 0., rotation); cooling->AddNode(waterTorusCentral, ivolume++, transformation); - TGeoVolume* waterTube3 = gGeoManager->MakeTube(Form("waterTube3%d_D1_H%d", 2, half), mWater, 0., mRWater, mLpartial1[itube] / 2.); + TGeoVolume* waterTube3 = + gGeoManager->MakeTube(Form("waterTube3%d_D1_H%d", 2, half), mWater, 0., + mRWater, mLpartial1[itube] / 2.); rotation = new TGeoRotation("rotation", -90., 0 - mAngle1[itube], 0.); - transformation = new TGeoCombiTrans(yPos1[itube], 0., -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[itube]), rotation); + transformation = new TGeoCombiTrans( + yPos1[itube], 0., + -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[itube]), + rotation); cooling->AddNode(waterTube3, ivolume++, transformation); - TGeoVolume* waterTorus2 = gGeoManager->MakeTorus(Form("waterTorus2%d_D1_H%d", itube, half), mWater, mRadius1[itube], 0., mRWater, 0., mAngle1[itube]); + TGeoVolume* waterTorus2 = gGeoManager->MakeTorus( + Form("waterTorus2%d_D1_H%d", itube, half), mWater, mRadius1[itube], 0., + mRWater, 0., mAngle1[itube]); rotation = new TGeoRotation("rotation", 180., 90., 0.); - transformation = new TGeoCombiTrans(mRadius1[itube] + mXPosition1[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[itube]), rotation); + transformation = new TGeoCombiTrans( + mRadius1[itube] + mXPosition1[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[itube]), + rotation); cooling->AddNode(waterTorus2, ivolume++, transformation); - TGeoVolume* waterTube4 = gGeoManager->MakeTube(Form("waterTube4%d_D1_H%d", itube, half), mWater, 0., mRWater, mLWater1[itube] / 2.); - translation = new TGeoTranslation(mXPosition1[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[itube] / 2.)); + TGeoVolume* waterTube4 = + gGeoManager->MakeTube(Form("waterTube4%d_D1_H%d", itube, half), mWater, + 0., mRWater, mLWater1[itube] / 2.); + translation = new TGeoTranslation(mXPosition1[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[1][0] / 2. + + mMoreLength01 - mLWater1[itube] / 2.)); cooling->AddNode(waterTube4, ivolume++, translation); } - // **************************************************** Tube part ************************************************ - // ****************************** Four parameters mLwater1, mRadius1, mAngle1, mLpartial1 ************************ + // **************************************************** Tube part + // ************************************************ + // ****************************** Four parameters mLwater1, mRadius1, mAngle1, + // mLpartial1 ************************ for (Int_t itube = 0; itube < 3; itube++) { - TGeoVolume* pipeTube1 = gGeoManager->MakeTube(Form("pipeTube1%d_D1_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLWater1[itube] / 2.); - translation = new TGeoTranslation(mXPosition1[itube] - mHalfDiskGap, 0., mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[itube] / 2.); + TGeoVolume* pipeTube1 = + gGeoManager->MakeTube(Form("pipeTube1%d_D1_H%d", itube, half), mPipe, + mRWater, mRWater + mDRPipe, mLWater1[itube] / 2.); + translation = new TGeoTranslation(mXPosition1[itube] - mHalfDiskGap, 0., + mSupportXDimensions[1][0] / 2. + + mMoreLength01 - mLWater1[itube] / 2.); cooling->AddNode(pipeTube1, ivolume++, translation); - TGeoVolume* pipeTorus1 = gGeoManager->MakeTorus(Form("pipeTorus1%d_D1_H%d", itube, half), mPipe, mRadius1[itube], mRWater, mRWater + mDRPipe, 0., mAngle1[itube]); + TGeoVolume* pipeTorus1 = gGeoManager->MakeTorus( + Form("pipeTorus1%d_D1_H%d", itube, half), mPipe, mRadius1[itube], + mRWater, mRWater + mDRPipe, 0., mAngle1[itube]); rotation = new TGeoRotation("rotation", 180., -90., 0.); - transformation = new TGeoCombiTrans(mRadius1[itube] + mXPosition1[itube] - mHalfDiskGap, 0., mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[itube], rotation); + transformation = new TGeoCombiTrans( + mRadius1[itube] + mXPosition1[itube] - mHalfDiskGap, 0., + mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[itube], + rotation); cooling->AddNode(pipeTorus1, ivolume++, transformation); - TGeoVolume* pipeTube2 = gGeoManager->MakeTube(Form("pipeTube2%d_D1_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLpartial1[itube] / 2.); + TGeoVolume* pipeTube2 = gGeoManager->MakeTube( + Form("pipeTube2%d_D1_H%d", itube, half), mPipe, mRWater, + mRWater + mDRPipe, mLpartial1[itube] / 2.); rotation = new TGeoRotation("rotation", 90., 180 - mAngle1[itube], 0.); - xPos1[itube] = mLWater1[itube] + mRadius1[itube] * TMath::Sin(mAngle1[itube] * TMath::DegToRad()) + mLpartial1[itube] / 2 * TMath::Cos(mAngle1[itube] * TMath::DegToRad()); - yPos1[itube] = mXPosition1[itube] - mHalfDiskGap + mRadius1[itube] * (1 - TMath::Cos(mAngle1[itube] * TMath::DegToRad())) + mLpartial1[itube] / 2 * TMath::Sin(mAngle1[itube] * TMath::DegToRad()); - transformation = new TGeoCombiTrans(yPos1[itube], 0., mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[itube], rotation); + xPos1[itube] = + mLWater1[itube] + + mRadius1[itube] * TMath::Sin(mAngle1[itube] * TMath::DegToRad()) + + mLpartial1[itube] / 2 * TMath::Cos(mAngle1[itube] * TMath::DegToRad()); + yPos1[itube] = + mXPosition1[itube] - mHalfDiskGap + + mRadius1[itube] * (1 - TMath::Cos(mAngle1[itube] * TMath::DegToRad())) + + mLpartial1[itube] / 2 * TMath::Sin(mAngle1[itube] * TMath::DegToRad()); + transformation = new TGeoCombiTrans(yPos1[itube], 0., + mSupportXDimensions[1][0] / 2. + + mMoreLength01 - xPos1[itube], + rotation); cooling->AddNode(pipeTube2, ivolume++, transformation); - mRadiusCentralTore[itube] = (mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[itube] - mLpartial1[itube] / 2 * TMath::Cos(mAngle1[itube] * TMath::DegToRad())) / TMath::Sin(mAngle1[itube] * TMath::DegToRad()); - TGeoVolume* pipeTorusCentral = gGeoManager->MakeTorus(Form("pipeTorusCentral%d_D1_H%d", itube, half), mPipe, mRadiusCentralTore[itube], mRWater, mRWater + mDRPipe, - -mAngle1[itube], 2. * mAngle1[itube]); + mRadiusCentralTore[itube] = + (mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[itube] - + mLpartial1[itube] / 2 * + TMath::Cos(mAngle1[itube] * TMath::DegToRad())) / + TMath::Sin(mAngle1[itube] * TMath::DegToRad()); + TGeoVolume* pipeTorusCentral = gGeoManager->MakeTorus( + Form("pipeTorusCentral%d_D1_H%d", itube, half), mPipe, + mRadiusCentralTore[itube], mRWater, mRWater + mDRPipe, -mAngle1[itube], + 2. * mAngle1[itube]); rotation = new TGeoRotation("rotation", 0., 90., 0.); - transformation = new TGeoCombiTrans(yPos1[itube] + mLpartial1[itube] / 2 * TMath::Sin(mAngle1[itube] * TMath::DegToRad()) - mRadiusCentralTore[itube] * TMath::Cos(mAngle1[itube] * TMath::DegToRad()), 0., 0., rotation); + transformation = new TGeoCombiTrans( + yPos1[itube] + + mLpartial1[itube] / 2 * + TMath::Sin(mAngle1[itube] * TMath::DegToRad()) - + mRadiusCentralTore[itube] * + TMath::Cos(mAngle1[itube] * TMath::DegToRad()), + 0., 0., rotation); cooling->AddNode(pipeTorusCentral, ivolume++, transformation); - TGeoVolume* pipeTube3 = gGeoManager->MakeTube(Form("pipeTube3%d_D1_H%d", 2, half), mPipe, mRWater, mRWater + mDRPipe, mLpartial1[itube] / 2.); + TGeoVolume* pipeTube3 = gGeoManager->MakeTube( + Form("pipeTube3%d_D1_H%d", 2, half), mPipe, mRWater, mRWater + mDRPipe, + mLpartial1[itube] / 2.); rotation = new TGeoRotation("rotation", -90., 0 - mAngle1[itube], 0.); - transformation = new TGeoCombiTrans(yPos1[itube], 0., -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[itube]), rotation); + transformation = new TGeoCombiTrans( + yPos1[itube], 0., + -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[itube]), + rotation); cooling->AddNode(pipeTube3, ivolume++, transformation); - TGeoVolume* pipeTorus2 = gGeoManager->MakeTorus(Form("pipeTorus2%d_D1_H%d", itube, half), mPipe, mRadius1[itube], mRWater, mRWater + mDRPipe, 0., mAngle1[itube]); + TGeoVolume* pipeTorus2 = gGeoManager->MakeTorus( + Form("pipeTorus2%d_D1_H%d", itube, half), mPipe, mRadius1[itube], + mRWater, mRWater + mDRPipe, 0., mAngle1[itube]); rotation = new TGeoRotation("rotation", 180., 90., 0.); - transformation = new TGeoCombiTrans(mRadius1[itube] + mXPosition1[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[itube]), rotation); + transformation = new TGeoCombiTrans( + mRadius1[itube] + mXPosition1[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[itube]), + rotation); cooling->AddNode(pipeTorus2, ivolume++, transformation); - TGeoVolume* pipeTube4 = gGeoManager->MakeTube(Form("pipeTube4%d_D1_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLWater1[itube] / 2.); - translation = new TGeoTranslation(mXPosition1[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[itube] / 2.)); + TGeoVolume* pipeTube4 = + gGeoManager->MakeTube(Form("pipeTube4%d_D1_H%d", itube, half), mPipe, + mRWater, mRWater + mDRPipe, mLWater1[itube] / 2.); + translation = new TGeoTranslation(mXPosition1[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[1][0] / 2. + + mMoreLength01 - mLWater1[itube] / 2.)); cooling->AddNode(pipeTube4, ivolume++, translation); } // *********************************************************************************************** - Double_t deltaz = mHeatExchangerThickness - Geometry::sKaptonOnCarbonThickness * 4 - Geometry::sKaptonGlueThickness * 4 - 2 * mCarbonThickness; + Double_t deltaz = mHeatExchangerThickness - + Geometry::sKaptonOnCarbonThickness * 4 - + Geometry::sKaptonGlueThickness * 4 - 2 * mCarbonThickness; rotation = new TGeoRotation("rotation", -90., 90., 0.); - transformation = - new TGeoCombiTrans(0., 0., mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - 2 * Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - + 2 * Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(cooling, 0, transformation); - transformation = - new TGeoCombiTrans(0., 0., mZPlan[disk] - deltaz / 2. + mCarbonThickness + mRWater + mDRPipe + 2 * Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + mZPlan[disk] - deltaz / 2. + mCarbonThickness + mRWater + mDRPipe + + 2 * Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(cooling, 1, transformation); - // **************************************** Carbon Plates **************************************** - + // **************************************** Carbon Plates + // **************************************** auto* carbonPlate = new TGeoVolumeAssembly(Form("carbonPlate_D1_H%d", half)); - auto* carbonBase1 = new TGeoBBox(Form("carbonBase1_D1_H%d", half), (mSupportXDimensions[disk][0]) / 2. + mMoreLength01, - (mSupportYDimensions[disk][0]) / 2., mCarbonThickness); - auto* t11 = new TGeoTranslation("t11", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto& mftBaseParam = MFTBaseParam::Instance(); + Double_t mReducedX = 0.; + if (mftBaseParam.buildAlignment) { + mReducedX = 0.6; + } + + auto* carbonBase1 = new TGeoBBox( + Form("carbonBase1_D1_H%d", half), + (mSupportXDimensions[disk][0]) / 2. + mMoreLength01 - mReducedX, + (mSupportYDimensions[disk][0]) / 2., mCarbonThickness); + auto* t11 = new TGeoTranslation( + "t11", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); t11->RegisterYourself(); auto* holeCarbon1 = - new TGeoTubeSeg(Form("holeCarbon1_D1_H%d", half), 0., mRMin[disk], mCarbonThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holeCarbon1_D1_H%d", half), 0., mRMin[disk], + mCarbonThickness + 0.000001, 0, 180.); auto* t12 = new TGeoTranslation("t12", 0., -mHalfDiskGap, 0.); t12->RegisterYourself(); auto* carbonhole1 = new TGeoSubtraction(carbonBase1, holeCarbon1, t11, t12); auto* ch1 = new TGeoCompositeShape(Form("Carbon1_D1_H%d", half), carbonhole1); - auto* carbonBaseWithHole1 = new TGeoVolume(Form("carbonBaseWithHole_D1_H%d", half), ch1, mCarbon); + auto* carbonBaseWithHole1 = + new TGeoVolume(Form("carbonBaseWithHole_D1_H%d", half), ch1, mCarbon); carbonBaseWithHole1->SetLineColor(kGray + 3); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - carbonPlate->AddNode(carbonBaseWithHole1, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + carbonPlate->AddNode(carbonBaseWithHole1, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t ty = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { ty += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partCarbon = - gGeoManager->MakeBox(Form("partCarbon_D1_H%d_%d", half, ipart), mCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., mCarbonThickness); + TGeoVolume* partCarbon = gGeoManager->MakeBox( + Form("partCarbon_D1_H%d_%d", half, ipart), mCarbon, + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., mCarbonThickness); partCarbon->SetLineColor(kGray + 3); auto* t = new TGeoTranslation("t", 0, ty + mHalfDiskGap, mZPlan[disk]); carbonPlate->AddNode(partCarbon, ipart, t); @@ -1587,39 +2276,56 @@ void HeatExchanger::createHalfDisk1(Int_t half) transformation = new TGeoCombiTrans(0., 0., -deltaz / 2., rotation); mHalfDisk->AddNode(carbonPlate, 1, transformation); - // **************************************** Glue Bwtween Carbon Plate and Rohacell Plate **************************************** + // **************************************** Glue Bwtween Carbon Plate and + // Rohacell Plate **************************************** TGeoMedium* mGlueRohacellCarbon = gGeoManager->GetMedium("MFT_Epoxy$"); - auto* glueRohacellCarbon = new TGeoVolumeAssembly(Form("glueRohacellCarbon_D0_H%d", half)); + auto* glueRohacellCarbon = + new TGeoVolumeAssembly(Form("glueRohacellCarbon_D0_H%d", half)); - auto* glueRohacellCarbonBase0 = new TGeoBBox(Form("glueRohacellCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2., - (mSupportYDimensions[disk][0]) / 2., Geometry::sGlueRohacellCarbonThickness); + auto* glueRohacellCarbonBase0 = + new TGeoBBox(Form("glueRohacellCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. - mReducedX, + (mSupportYDimensions[disk][0]) / 2., + Geometry::sGlueRohacellCarbonThickness); - auto* translation_gluRC01 = new TGeoTranslation("translation_gluRC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* translation_gluRC01 = new TGeoTranslation( + "translation_gluRC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_gluRC01->RegisterYourself(); - auto* translation_gluRC02 = new TGeoTranslation("translation_gluRC02", 0., -mHalfDiskGap, 0.); + auto* translation_gluRC02 = + new TGeoTranslation("translation_gluRC02", 0., -mHalfDiskGap, 0.); translation_gluRC02->RegisterYourself(); - auto* holeglueRohacellCarbon0 = - new TGeoTubeSeg(Form("holeglueRohacellCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sGlueRohacellCarbonThickness + 0.000001, 0, 180.); + auto* holeglueRohacellCarbon0 = new TGeoTubeSeg( + Form("holeglueRohacellCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sGlueRohacellCarbonThickness + 0.000001, 0, 180.); - auto* glueRohacellCarbonhole0 = new TGeoSubtraction(glueRohacellCarbonBase0, holeglueRohacellCarbon0, translation_gluRC01, translation_gluRC02); - auto* gRC0 = new TGeoCompositeShape(Form("glueRohacellCarbon0_D0_H%d", half), glueRohacellCarbonhole0); - auto* glueRohacellCarbonBaseWithHole0 = new TGeoVolume(Form("glueRohacellCarbonWithHole_D0_H%d", half), gRC0, mGlueRohacellCarbon); + auto* glueRohacellCarbonhole0 = + new TGeoSubtraction(glueRohacellCarbonBase0, holeglueRohacellCarbon0, + translation_gluRC01, translation_gluRC02); + auto* gRC0 = new TGeoCompositeShape(Form("glueRohacellCarbon0_D0_H%d", half), + glueRohacellCarbonhole0); + auto* glueRohacellCarbonBaseWithHole0 = + new TGeoVolume(Form("glueRohacellCarbonWithHole_D0_H%d", half), gRC0, + mGlueRohacellCarbon); glueRohacellCarbonBaseWithHole0->SetLineColor(kGreen); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - glueRohacellCarbon->AddNode(glueRohacellCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + glueRohacellCarbon->AddNode(glueRohacellCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyGRC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyGRC += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partGlueRohacellCarbon = - gGeoManager->MakeBox(Form("partGlueRohacellCarbon_D0_H%d_%d", half, ipart), mGlueRohacellCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sGlueRohacellCarbonThickness); + TGeoVolume* partGlueRohacellCarbon = gGeoManager->MakeBox( + Form("partGlueRohacellCarbon_D0_H%d_%d", half, ipart), + mGlueRohacellCarbon, mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., + Geometry::sGlueRohacellCarbonThickness); partGlueRohacellCarbon->SetLineColor(kGreen); auto* t = new TGeoTranslation("t", 0, tyGRC + mHalfDiskGap, mZPlan[disk]); glueRohacellCarbon->AddNode(partGlueRohacellCarbon, ipart, t); @@ -1627,41 +2333,62 @@ void HeatExchanger::createHalfDisk1(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(glueRohacellCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness), rotation); + transformation = new TGeoCombiTrans(0., 0., + -(deltaz / 2. - mCarbonThickness - + Geometry::sGlueRohacellCarbonThickness), + rotation); mHalfDisk->AddNode(glueRohacellCarbon, 4, transformation); - // **************************************** Kapton on Carbon Plate **************************************** + // **************************************** Kapton on Carbon Plate + // **************************************** TGeoMedium* mKaptonOnCarbon = gGeoManager->GetMedium("MFT_Kapton$"); - auto* kaptonOnCarbon = new TGeoVolumeAssembly(Form("kaptonOnCarbon_D0_H%d", half)); - auto* kaptonOnCarbonBase0 = new TGeoBBox(Form("kaptonOnCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2. + mMoreLength01, - (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonOnCarbonThickness); - - auto* translation_KC01 = new TGeoTranslation("translation_KC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* kaptonOnCarbon = + new TGeoVolumeAssembly(Form("kaptonOnCarbon_D0_H%d", half)); + auto* kaptonOnCarbonBase0 = new TGeoBBox( + Form("kaptonOnCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. + mMoreLength01 - mReducedX, + (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonOnCarbonThickness); + + auto* translation_KC01 = new TGeoTranslation( + "translation_KC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_KC01->RegisterYourself(); - auto* translation_KC02 = new TGeoTranslation("translation_KC02", 0., -mHalfDiskGap, 0.); + auto* translation_KC02 = + new TGeoTranslation("translation_KC02", 0., -mHalfDiskGap, 0.); translation_KC02->RegisterYourself(); auto* holekaptonOnCarbon0 = - new TGeoTubeSeg(Form("holekaptonOnCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sKaptonOnCarbonThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holekaptonOnCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sKaptonOnCarbonThickness + 0.000001, 0, 180.); - auto* kaptonOnCarbonhole0 = new TGeoSubtraction(kaptonOnCarbonBase0, holekaptonOnCarbon0, translation_KC01, translation_KC02); - auto* KC0 = new TGeoCompositeShape(Form("kaptonOnCarbon_D0_H%d", half), kaptonOnCarbonhole0); - auto* kaptonOnCarbonBaseWithHole0 = new TGeoVolume(Form("kaptonOnCarbonWithHole_D0_H%d", half), KC0, mKaptonOnCarbon); + auto* kaptonOnCarbonhole0 = + new TGeoSubtraction(kaptonOnCarbonBase0, holekaptonOnCarbon0, + translation_KC01, translation_KC02); + auto* KC0 = new TGeoCompositeShape(Form("kaptonOnCarbon_D0_H%d", half), + kaptonOnCarbonhole0); + auto* kaptonOnCarbonBaseWithHole0 = new TGeoVolume( + Form("kaptonOnCarbonWithHole_D0_H%d", half), KC0, mKaptonOnCarbon); kaptonOnCarbonBaseWithHole0->SetLineColor(kMagenta); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - kaptonOnCarbon->AddNode(kaptonOnCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + kaptonOnCarbon->AddNode(kaptonOnCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyKC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyKC += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partkaptonOnCarbonBase = - gGeoManager->MakeBox(Form("partkaptonOnCarbon_D0_H%d_%d", half, ipart), mKaptonOnCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonOnCarbonThickness); + TGeoVolume* partkaptonOnCarbonBase = gGeoManager->MakeBox( + Form("partkaptonOnCarbon_D0_H%d_%d", half, ipart), mKaptonOnCarbon, + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., + Geometry::sKaptonOnCarbonThickness); partkaptonOnCarbonBase->SetLineColor(kMagenta); auto* t = new TGeoTranslation("t", 0, tyKC + mHalfDiskGap, mZPlan[disk]); kaptonOnCarbon->AddNode(partkaptonOnCarbonBase, ipart, t); @@ -1669,41 +2396,63 @@ void HeatExchanger::createHalfDisk1(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + Geometry::sKaptonGlueThickness * 2, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + + Geometry::sKaptonGlueThickness * 2, + rotation); mHalfDisk->AddNode(kaptonOnCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + Geometry::sKaptonGlueThickness * 2), rotation); + transformation = new TGeoCombiTrans( + 0., 0., + -(deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + + Geometry::sKaptonGlueThickness * 2), + rotation); mHalfDisk->AddNode(kaptonOnCarbon, 4, transformation); - // **************************************** Kapton glue on the carbon plate **************************************** + // **************************************** Kapton glue on the carbon plate + // **************************************** TGeoMedium* mGlueKaptonCarbon = gGeoManager->GetMedium("MFT_Epoxy$"); - auto* glueKaptonCarbon = new TGeoVolumeAssembly(Form("glueKaptonCarbon_D0_H%d", half)); - auto* glueKaptonCarbonBase0 = new TGeoBBox(Form("glueKaptonCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2., - (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonGlueThickness); - - auto* translation_gluKC01 = new TGeoTranslation("translation_gluKC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* glueKaptonCarbon = + new TGeoVolumeAssembly(Form("glueKaptonCarbon_D0_H%d", half)); + auto* glueKaptonCarbonBase0 = new TGeoBBox( + Form("glueKaptonCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. - mReducedX, + (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonGlueThickness); + + auto* translation_gluKC01 = new TGeoTranslation( + "translation_gluKC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_gluKC01->RegisterYourself(); - auto* translation_gluKC02 = new TGeoTranslation("translation_gluKC02", 0., -mHalfDiskGap, 0.); + auto* translation_gluKC02 = + new TGeoTranslation("translation_gluKC02", 0., -mHalfDiskGap, 0.); translation_gluKC02->RegisterYourself(); - auto* holeglueKaptonCarbon0 = - new TGeoTubeSeg(Form("holeglueKaptonCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sKaptonGlueThickness + 0.000001, 0, 180.); + auto* holeglueKaptonCarbon0 = new TGeoTubeSeg( + Form("holeglueKaptonCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sKaptonGlueThickness + 0.000001, 0, 180.); - auto* glueKaptonCarbonhole0 = new TGeoSubtraction(glueKaptonCarbonBase0, holeglueKaptonCarbon0, translation_gluKC01, translation_gluKC02); - auto* gKC0 = new TGeoCompositeShape(Form("glueKaptonCarbon0_D0_H%d", half), glueKaptonCarbonhole0); - auto* glueKaptonCarbonBaseWithHole0 = new TGeoVolume(Form("glueKaptonCarbonWithHole_D0_H%d", half), gKC0, mGlueKaptonCarbon); + auto* glueKaptonCarbonhole0 = + new TGeoSubtraction(glueKaptonCarbonBase0, holeglueKaptonCarbon0, + translation_gluKC01, translation_gluKC02); + auto* gKC0 = new TGeoCompositeShape(Form("glueKaptonCarbon0_D0_H%d", half), + glueKaptonCarbonhole0); + auto* glueKaptonCarbonBaseWithHole0 = new TGeoVolume( + Form("glueKaptonCarbonWithHole_D0_H%d", half), gKC0, mGlueKaptonCarbon); glueKaptonCarbonBaseWithHole0->SetLineColor(kGreen); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - glueKaptonCarbon->AddNode(glueKaptonCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + glueKaptonCarbon->AddNode(glueKaptonCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyGKC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyGKC += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partGlueKaptonCarbon = - gGeoManager->MakeBox(Form("partGlueKaptonCarbon_D0_H%d_%d", half, ipart), mGlueKaptonCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonGlueThickness); + TGeoVolume* partGlueKaptonCarbon = gGeoManager->MakeBox( + Form("partGlueKaptonCarbon_D0_H%d_%d", half, ipart), mGlueKaptonCarbon, + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonGlueThickness); partGlueKaptonCarbon->SetLineColor(kGreen); auto* t = new TGeoTranslation("t", 0, tyGKC + mHalfDiskGap, mZPlan[disk]); glueKaptonCarbon->AddNode(partGlueKaptonCarbon, ipart, t); @@ -1711,18 +2460,28 @@ void HeatExchanger::createHalfDisk1(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness, + rotation); mHalfDisk->AddNode(glueKaptonCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness), rotation); + transformation = new TGeoCombiTrans( + 0., 0., + -(deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness), + rotation); mHalfDisk->AddNode(glueKaptonCarbon, 4, transformation); - // **************************************** Rohacell Plate **************************************** - auto* rohacellPlate = new TGeoVolumeAssembly(Form("rohacellPlate_D1_H%d", half)); - auto* rohacellBase1 = new TGeoBBox("rohacellBase1", (mSupportXDimensions[disk][0]) / 2., - (mSupportYDimensions[disk][0]) / 2., mRohacellThickness); - auto* holeRohacell1 = new TGeoTubeSeg("holeRohacell1", 0., mRMin[disk], mRohacellThickness + 0.000001, 0, 180.); - - // **************************************** GROOVES ************************************************* + // **************************************** Rohacell Plate + // **************************************** + auto* rohacellPlate = + new TGeoVolumeAssembly(Form("rohacellPlate_D1_H%d", half)); + auto* rohacellBase1 = + new TGeoBBox("rohacellBase1", (mSupportXDimensions[disk][0]) / 2., + (mSupportYDimensions[disk][0]) / 2., mRohacellThickness); + auto* holeRohacell1 = new TGeoTubeSeg("holeRohacell1", 0., mRMin[disk], + mRohacellThickness + 0.000001, 0, 180.); + + // **************************************** GROOVES + // ************************************************* Double_t diameter = 0.21; // groove diameter Double_t epsilon = 0.06; // outside shift of the goove Int_t iCount = 0; @@ -1734,20 +2493,31 @@ void HeatExchanger::createHalfDisk1(Int_t half) TGeoCompositeShape* rohacellGroove[300]; for (Int_t igroove = 0; igroove < 3; igroove++) { - grooveTube[0][igroove] = new TGeoTube("linear", 0., diameter, mLWater1[igroove] / 2.); - grooveTorus[1][igroove] = new TGeoTorus("SideTorus", mRadius1[igroove], 0., diameter, 0., mAngle1[igroove]); - grooveTube[2][igroove] = new TGeoTube("tiltedLinear", 0., diameter, mLpartial1[igroove] / 2.); - grooveTorus[3][igroove] = new TGeoTorus("centralTorus", mRadiusCentralTore[igroove], 0., diameter, -mAngle1[igroove], 2. * mAngle1[igroove]); - grooveTube[4][igroove] = new TGeoTube("tiltedLinear", 0., diameter, mLpartial1[igroove] / 2.); - grooveTorus[5][igroove] = new TGeoTorus("SideTorus", mRadius1[igroove], 0., diameter, 0., mAngle1[igroove]); - grooveTube[6][igroove] = new TGeoTube("linear", 0., diameter, mLWater1[igroove] / 2.); + grooveTube[0][igroove] = + new TGeoTube("linear", 0., diameter, mLWater1[igroove] / 2.); + grooveTorus[1][igroove] = new TGeoTorus("SideTorus", mRadius1[igroove], 0., + diameter, 0., mAngle1[igroove]); + grooveTube[2][igroove] = + new TGeoTube("tiltedLinear", 0., diameter, mLpartial1[igroove] / 2.); + grooveTorus[3][igroove] = + new TGeoTorus("centralTorus", mRadiusCentralTore[igroove], 0., diameter, + -mAngle1[igroove], 2. * mAngle1[igroove]); + grooveTube[4][igroove] = + new TGeoTube("tiltedLinear", 0., diameter, mLpartial1[igroove] / 2.); + grooveTorus[5][igroove] = new TGeoTorus("SideTorus", mRadius1[igroove], 0., + diameter, 0., mAngle1[igroove]); + grooveTube[6][igroove] = + new TGeoTube("linear", 0., diameter, mLWater1[igroove] / 2.); } // Rotation matrix TGeoRotation* rotationLinear = new TGeoRotation("rotation", -90., 90., 0.); - TGeoRotation* rotationSideTorusL = new TGeoRotation("rotationSideTorusLeft", -90., 0., 0.); - TGeoRotation* rotationSideTorusR = new TGeoRotation("rotationSideTorusRight", 90., 180., 180.); - TGeoRotation* rotationCentralTorus = new TGeoRotation("rotationCentralTorus", 90., 0., 0.); + TGeoRotation* rotationSideTorusL = + new TGeoRotation("rotationSideTorusLeft", -90., 0., 0.); + TGeoRotation* rotationSideTorusR = + new TGeoRotation("rotationSideTorusRight", 90., 180., 180.); + TGeoRotation* rotationCentralTorus = + new TGeoRotation("rotationCentralTorus", 90., 0., 0.); TGeoRotation* rotationTiltedLinearR; TGeoRotation* rotationTiltedLinearL; @@ -1755,52 +2525,95 @@ void HeatExchanger::createHalfDisk1(Int_t half) if (Geometry::sGrooves == 1) { for (Int_t iface = 1; iface > -2; iface -= 2) { // front and rear for (Int_t igroove = 0; igroove < 3; igroove++) { // 3 grooves - mPosition[igroove] = mXPosition1[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap; + mPosition[igroove] = mXPosition1[igroove] - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap; for (Int_t ip = 0; ip < 7; ip++) { // each groove is made of 7 parts switch (ip) { case 0: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[igroove] / 2., mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[1][0] / 2. + mMoreLength01 - + mLWater1[igroove] / 2., + mPosition[igroove], iface * (mRohacellThickness + epsilon), + rotationLinear); if (igroove == 0 && iface == 1) { - rohacellBaseGroove[0] = new TGeoSubtraction(rohacellBase1, grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); - rohacellGroove[0] = new TGeoCompositeShape(Form("rohacell1Groove%d_G%d_F%d_H%d", ip, igroove, iface, half), rohacellBaseGroove[0]); + rohacellBaseGroove[0] = + new TGeoSubtraction(rohacellBase1, grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); + rohacellGroove[0] = + new TGeoCompositeShape(Form("rohacell1Groove%d_G%d_F%d_H%d", + ip, igroove, iface, half), + rohacellBaseGroove[0]); }; break; case 1: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[igroove], mRadius1[igroove] + mXPosition1[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, iface * (mRohacellThickness + epsilon), rotationSideTorusR); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[1][0] / 2. + mMoreLength01 - + mLWater1[igroove], + mRadius1[igroove] + mXPosition1[igroove] - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationSideTorusR); break; case 2: // Linear tilted - rotationTiltedLinearR = new TGeoRotation("rotationTiltedLinearRight", 90. - mAngle1[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[igroove], yPos1[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); + rotationTiltedLinearR = new TGeoRotation( + "rotationTiltedLinearRight", 90. - mAngle1[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[igroove], + yPos1[igroove] - mSupportYDimensions[disk][0] / 2. - + mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); break; case 3: // Central Torus - transfo[ip][igroove] = new TGeoCombiTrans(0., yPos1[igroove] + mLpartial1[igroove] / 2 * TMath::Sin(mAngle1[igroove] * TMath::DegToRad()) - mRadiusCentralTore[igroove] * TMath::Cos(mAngle1[igroove] * TMath::DegToRad()) - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationCentralTorus); + transfo[ip][igroove] = new TGeoCombiTrans( + 0., + yPos1[igroove] + + mLpartial1[igroove] / 2 * + TMath::Sin(mAngle1[igroove] * TMath::DegToRad()) - + mRadiusCentralTore[igroove] * + TMath::Cos(mAngle1[igroove] * TMath::DegToRad()) - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationCentralTorus); break; case 4: // Linear tilted - rotationTiltedLinearL = new TGeoRotation("rotationTiltedLinearLeft", 90. + mAngle1[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[1][0] / 2. + mMoreLength01 - xPos1[igroove]), yPos1[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); + rotationTiltedLinearL = new TGeoRotation( + "rotationTiltedLinearLeft", 90. + mAngle1[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - + xPos1[igroove]), + yPos1[igroove] - mSupportYDimensions[disk][0] / 2. - + mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); break; case 5: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[igroove]), mRadius1[igroove] + mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationSideTorusL); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - + mLWater1[igroove]), + mRadius1[igroove] + mPosition[igroove], + iface * (mRohacellThickness + epsilon), rotationSideTorusL); break; case 6: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[1][0] / 2. + mMoreLength01 - mLWater1[igroove] / 2.), mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[1][0] / 2. + mMoreLength01 - + mLWater1[igroove] / 2.), + mPosition[igroove], iface * (mRohacellThickness + epsilon), + rotationLinear); break; } if (!(ip == 0 && igroove == 0 && iface == 1)) { if (ip & 1) { - rohacellBaseGroove[iCount] = new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, + transfo[ip][igroove]); } else { - rohacellBaseGroove[iCount] = new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, + transfo[ip][igroove]); } - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell1Groove%d_G%d_F%d_H%d", iCount, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell1Groove%d_G%d_F%d_H%d", + iCount, igroove, iface, half), + rohacellBaseGroove[iCount]); } iCount++; } @@ -1815,16 +2628,20 @@ void HeatExchanger::createHalfDisk1(Int_t half) rohacellBase = new TGeoSubtraction(rohacellBase1, holeRohacell1, t11, t12); } if (Geometry::sGrooves == 1) { - rohacellBase = new TGeoSubtraction(rohacellGroove[iCount - 1], holeRohacell1, t11, t12); + rohacellBase = new TGeoSubtraction(rohacellGroove[iCount - 1], + holeRohacell1, t11, t12); } - auto* rh1 = new TGeoCompositeShape(Form("rohacellBase1_D1_H%d", half), rohacellBase); - auto* rohacellBaseWithHole = new TGeoVolume(Form("rohacellBaseWithHole_D1_H%d", half), rh1, mRohacell); + auto* rh1 = + new TGeoCompositeShape(Form("rohacellBase1_D1_H%d", half), rohacellBase); + auto* rohacellBaseWithHole = + new TGeoVolume(Form("rohacellBaseWithHole_D1_H%d", half), rh1, mRohacell); TGeoVolume* partRohacell; rohacellBaseWithHole->SetLineColor(kGray); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - rohacellPlate->AddNode(rohacellBaseWithHole, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + rohacellPlate->AddNode(rohacellBaseWithHole, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); ty = mSupportYDimensions[disk][0]; @@ -1835,74 +2652,129 @@ void HeatExchanger::createHalfDisk1(Int_t half) //=========================================================================================================== //=========================================================================================================== auto* partRohacell0 = - new TGeoBBox(Form("rohacellBase0_D1_H%d_%d", half, ipart), mSupportXDimensions[disk][ipart] / 2., + new TGeoBBox(Form("rohacellBase0_D1_H%d_%d", half, ipart), + mSupportXDimensions[disk][ipart] / 2., mSupportYDimensions[disk][ipart] / 2., mRohacellThickness); if (Geometry::sGrooves == 1) { - // ***************** Creating grooves for the other parts of the rohacell plate ********************** + // ***************** Creating grooves for the other parts of the rohacell + // plate ********************** Double_t mShift; for (Int_t iface = 1; iface > -2; iface -= 2) { // front and rear for (Int_t igroove = 0; igroove < 3; igroove++) { // 3 grooves if (ipart == 1) { - mPosition[ipart] = mXPosition1[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1]; + mPosition[ipart] = + mXPosition1[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1]; mShift = -mSupportYDimensions[disk][ipart - 1]; }; if (ipart == 2) { - mPosition[ipart] = mXPosition1[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2]; - mShift = -mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2]; + mPosition[ipart] = + mXPosition1[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2]; + mShift = -mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2]; }; if (ipart == 3) { - mPosition[ipart] = mXPosition1[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2] - mSupportYDimensions[disk][ipart - 3]; - mShift = -mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2] - mSupportYDimensions[disk][ipart - 3]; + mPosition[ipart] = + mXPosition1[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2] - + mSupportYDimensions[disk][ipart - 3]; + mShift = -mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2] - + mSupportYDimensions[disk][ipart - 3]; }; for (Int_t ip = 0; ip < 7; ip++) { // each groove is made of 7 parts switch (ip) { case 0: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - mLWater1[igroove] / 2., mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2. + mMoreLength01 - + mLWater1[igroove] / 2., + mPosition[ipart], iface * (mRohacellThickness + epsilon), + rotationLinear); if (igroove == 0 && iface == 1) { - rohacellBaseGroove[iCount] = new TGeoSubtraction(partRohacell0, grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell1Groove%d_G%d_F%d_H%d", ip, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellBaseGroove[iCount] = + new TGeoSubtraction(partRohacell0, grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell1Groove%d_G%d_F%d_H%d", + ip, igroove, iface, half), + rohacellBaseGroove[iCount]); }; break; case 1: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - mLWater1[igroove], mPosition[ipart] + mRadius1[igroove], - iface * (mRohacellThickness + epsilon), rotationSideTorusR); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2. + mMoreLength01 - + mLWater1[igroove], + mPosition[ipart] + mRadius1[igroove], + iface * (mRohacellThickness + epsilon), rotationSideTorusR); break; case 2: // Linear tilted - rotationTiltedLinearR = new TGeoRotation("rotationTiltedLinearRight", 90. - mAngle1[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - xPos1[igroove], yPos1[igroove] + mShift - mHalfDiskGap - mSupportYDimensions[disk][ipart] / 2., iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); + rotationTiltedLinearR = new TGeoRotation( + "rotationTiltedLinearRight", 90. - mAngle1[igroove], 90., 0.); + transfo[ip][igroove] = + new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + + mMoreLength01 - xPos1[igroove], + yPos1[igroove] + mShift - mHalfDiskGap - + mSupportYDimensions[disk][ipart] / 2., + iface * (mRohacellThickness + epsilon), + rotationTiltedLinearR); break; case 3: // Central Torus - transfo[ip][igroove] = new TGeoCombiTrans(0., mPosition[ipart] + yPos1[igroove] + mLpartial1[igroove] / 2 * TMath::Sin(mAngle1[igroove] * TMath::DegToRad()) - mRadiusCentralTore[igroove] * TMath::Cos(mAngle1[igroove] * TMath::DegToRad()) - mXPosition1[igroove], - iface * (mRohacellThickness + epsilon), rotationCentralTorus); + transfo[ip][igroove] = new TGeoCombiTrans( + 0., + mPosition[ipart] + yPos1[igroove] + + mLpartial1[igroove] / 2 * + TMath::Sin(mAngle1[igroove] * TMath::DegToRad()) - + mRadiusCentralTore[igroove] * + TMath::Cos(mAngle1[igroove] * TMath::DegToRad()) - + mXPosition1[igroove], + iface * (mRohacellThickness + epsilon), rotationCentralTorus); break; case 4: // Linear tilted - rotationTiltedLinearL = new TGeoRotation("rotationTiltedLinearLeft", 90. + mAngle1[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - xPos1[igroove]), yPos1[igroove] + mPosition[ipart] - mXPosition1[igroove], - iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); + rotationTiltedLinearL = new TGeoRotation( + "rotationTiltedLinearLeft", 90. + mAngle1[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - + xPos1[igroove]), + yPos1[igroove] + mPosition[ipart] - mXPosition1[igroove], + iface * (mRohacellThickness + epsilon), + rotationTiltedLinearL); break; case 5: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - mLWater1[igroove]), mRadius1[igroove] + mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationSideTorusL); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - + mLWater1[igroove]), + mRadius1[igroove] + mPosition[ipart], + iface * (mRohacellThickness + epsilon), rotationSideTorusL); break; case 6: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - mLWater1[igroove] / 2.), mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[disk][0] / 2. + mMoreLength01 - + mLWater1[igroove] / 2.), + mPosition[ipart], iface * (mRohacellThickness + epsilon), + rotationLinear); break; } if (!(ip == 0 && igroove == 0 && iface == 1)) { if (ip & 1) { - rohacellBaseGroove[iCount] = - new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTorus[ip][igroove], + nullptr, transfo[ip][igroove]); } else { - rohacellBaseGroove[iCount] = - new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); } - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell1Groove%d_G%d_F%d_H%d", iCount, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell1Groove%d_G%d_F%d_H%d", + iCount, igroove, iface, half), + rohacellBaseGroove[iCount]); } iCount++; } @@ -1915,30 +2787,42 @@ void HeatExchanger::createHalfDisk1(Int_t half) TGeoBBox* notchRohacell1; TGeoTranslation* tnotch1; if (ipart == (mNPart[disk] - 1)) { - notchRohacell1 = new TGeoBBox(Form("notchRohacell1_D1_H%d", half), 1.1, 0.4, mRohacellThickness + 0.000001); - tnotch1 = new TGeoTranslation("tnotch1", 0., mSupportYDimensions[disk][ipart] / 2., 0.); + notchRohacell1 = new TGeoBBox(Form("notchRohacell1_D1_H%d", half), 1.1, + 0.4, mRohacellThickness + 0.000001); + tnotch1 = new TGeoTranslation("tnotch1", 0., + mSupportYDimensions[disk][ipart] / 2., 0.); tnotch1->RegisterYourself(); } //============================================================= if (Geometry::sGrooves == 0) { if (ipart == (mNPart[disk] - 1)) { - partRohacellini = new TGeoSubtraction(partRohacell0, notchRohacell1, nullptr, tnotch1); - auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D1_H%d", 0, half), partRohacellini); - partRohacell = new TGeoVolume(Form("partRohacelli_D1_H%d_%d", half, ipart), rhinit, mRohacell); + partRohacellini = new TGeoSubtraction(partRohacell0, notchRohacell1, + nullptr, tnotch1); + auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D1_H%d", 0, half), + partRohacellini); + partRohacell = new TGeoVolume( + Form("partRohacelli_D1_H%d_%d", half, ipart), rhinit, mRohacell); } if (ipart < (mNPart[disk] - 1)) { - partRohacell = new TGeoVolume(Form("partRohacelli_D1_H%d_%d", half, ipart), partRohacell0, mRohacell); + partRohacell = + new TGeoVolume(Form("partRohacelli_D1_H%d_%d", half, ipart), + partRohacell0, mRohacell); } } if (Geometry::sGrooves == 1) { if (ipart == (mNPart[disk] - 1)) { - partRohacellini = new TGeoSubtraction(rohacellGroove[iCount - 1], notchRohacell1, nullptr, tnotch1); - auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D1_H%d", 0, half), partRohacellini); - partRohacell = new TGeoVolume(Form("partRohacelli_D1_H%d_%d", half, ipart), rhinit, mRohacell); + partRohacellini = new TGeoSubtraction(rohacellGroove[iCount - 1], + notchRohacell1, nullptr, tnotch1); + auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D1_H%d", 0, half), + partRohacellini); + partRohacell = new TGeoVolume( + Form("partRohacelli_D1_H%d_%d", half, ipart), rhinit, mRohacell); } if (ipart < (mNPart[disk] - 1)) { - partRohacell = new TGeoVolume(Form("partRohacelli_D1_H%d_%d", half, ipart), rohacellGroove[iCount - 1], mRohacell); + partRohacell = + new TGeoVolume(Form("partRohacelli_D1_H%d_%d", half, ipart), + rohacellGroove[iCount - 1], mRohacell); } } @@ -1948,11 +2832,15 @@ void HeatExchanger::createHalfDisk1(Int_t half) rohacellPlate->AddNode(partRohacell, ipart, t); ty += mSupportYDimensions[disk][ipart] / 2.; - //========== insert to locate the rohacell plate compare to the disk support ============= + //========== insert to locate the rohacell plate compare to the disk support + //============= if (ipart == (mNPart[disk] - 1)) { TGeoTranslation* tinsert1; - TGeoVolume* insert1 = gGeoManager->MakeBox(Form("insert1_H%d_%d", half, ipart), mPeek, 1.0, 0.35 / 2., mRohacellThickness); - Double_t ylocation = mSupportYDimensions[disk][0] + mHalfDiskGap - 0.35 / 2.; + TGeoVolume* insert1 = + gGeoManager->MakeBox(Form("insert1_H%d_%d", half, ipart), mPeek, 1.0, + 0.35 / 2., mRohacellThickness); + Double_t ylocation = + mSupportYDimensions[disk][0] + mHalfDiskGap - 0.35 / 2.; for (Int_t ip = 1; ip < mNPart[disk]; ip++) { ylocation = ylocation + mSupportYDimensions[disk][ip]; } @@ -1997,124 +2885,240 @@ void HeatExchanger::createHalfDisk2(Int_t half) TGeoRotation* rotation = nullptr; TGeoCombiTrans* transformation = nullptr; - // **************************************** Water part **************************************** - // ********************** Four parameters mLwater2, mRadius2, mAngle2, mLpartial2 ************* + // **************************************** Water part + // **************************************** + // ********************** Four parameters mLwater2, mRadius2, mAngle2, + // mLpartial2 ************* Double_t ivolume = 200; // offset chamber 2 Double_t mRadiusCentralTore[4]; Double_t xPos2[4]; Double_t yPos2[4]; for (Int_t itube = 0; itube < 3; itube++) { - TGeoVolume* waterTube1 = gGeoManager->MakeTube(Form("waterTube1%d_D2_H%d", itube, half), mWater, 0., mRWater, mLWater2[itube] / 2.); - translation = new TGeoTranslation(mXPosition2[itube] - mHalfDiskGap, 0., mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube] / 2.); + TGeoVolume* waterTube1 = + gGeoManager->MakeTube(Form("waterTube1%d_D2_H%d", itube, half), mWater, + 0., mRWater, mLWater2[itube] / 2.); + translation = new TGeoTranslation(mXPosition2[itube] - mHalfDiskGap, 0., + mSupportXDimensions[2][0] / 2. + + mMoreLength - mLWater2[itube] / 2.); cooling->AddNode(waterTube1, ivolume++, translation); - TGeoVolume* waterTorus1 = gGeoManager->MakeTorus(Form("waterTorus1%d_D2_H%d", itube, half), mWater, mRadius2[itube], 0., mRWater, 0., mAngle2[itube]); + TGeoVolume* waterTorus1 = gGeoManager->MakeTorus( + Form("waterTorus1%d_D2_H%d", itube, half), mWater, mRadius2[itube], 0., + mRWater, 0., mAngle2[itube]); rotation = new TGeoRotation("rotation", 180., -90., 0.); - transformation = new TGeoCombiTrans(mRadius2[itube] + mXPosition2[itube] - mHalfDiskGap, 0., mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube], rotation); + transformation = new TGeoCombiTrans( + mRadius2[itube] + mXPosition2[itube] - mHalfDiskGap, 0., + mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube], + rotation); cooling->AddNode(waterTorus1, ivolume++, transformation); - TGeoVolume* waterTube2 = gGeoManager->MakeTube(Form("waterTube2%d_D2_H%d", itube, half), mWater, 0., mRWater, mLpartial2[itube] / 2.); + TGeoVolume* waterTube2 = + gGeoManager->MakeTube(Form("waterTube2%d_D2_H%d", itube, half), mWater, + 0., mRWater, mLpartial2[itube] / 2.); rotation = new TGeoRotation("rotation", 90., 180 - mAngle2[itube], 0.); - xPos2[itube] = mLWater2[itube] + mRadius2[itube] * TMath::Sin(mAngle2[itube] * TMath::DegToRad()) + mLpartial2[itube] / 2 * TMath::Cos(mAngle2[itube] * TMath::DegToRad()); - yPos2[itube] = mXPosition2[itube] - mHalfDiskGap + mRadius2[itube] * (1 - TMath::Cos(mAngle2[itube] * TMath::DegToRad())) + mLpartial2[itube] / 2 * TMath::Sin(mAngle2[itube] * TMath::DegToRad()); - transformation = new TGeoCombiTrans(yPos2[itube], 0., mSupportXDimensions[2][0] / 2. + mMoreLength - xPos2[itube], rotation); + xPos2[itube] = + mLWater2[itube] + + mRadius2[itube] * TMath::Sin(mAngle2[itube] * TMath::DegToRad()) + + mLpartial2[itube] / 2 * TMath::Cos(mAngle2[itube] * TMath::DegToRad()); + yPos2[itube] = + mXPosition2[itube] - mHalfDiskGap + + mRadius2[itube] * (1 - TMath::Cos(mAngle2[itube] * TMath::DegToRad())) + + mLpartial2[itube] / 2 * TMath::Sin(mAngle2[itube] * TMath::DegToRad()); + transformation = new TGeoCombiTrans( + yPos2[itube], 0., + mSupportXDimensions[2][0] / 2. + mMoreLength - xPos2[itube], rotation); cooling->AddNode(waterTube2, ivolume++, transformation); - mRadiusCentralTore[itube] = (mSupportXDimensions[2][0] / 2. + mMoreLength - xPos2[itube] - mLpartial2[itube] / 2 * TMath::Cos(mAngle2[itube] * TMath::DegToRad())) / TMath::Sin(mAngle2[itube] * TMath::DegToRad()); - TGeoVolume* waterTorusCentral = gGeoManager->MakeTorus(Form("waterTorusCentral%d_D2_H%d", itube, half), mWater, mRadiusCentralTore[itube], 0., mRWater, -mAngle2[itube], 2. * mAngle2[itube]); + mRadiusCentralTore[itube] = + (mSupportXDimensions[2][0] / 2. + mMoreLength - xPos2[itube] - + mLpartial2[itube] / 2 * + TMath::Cos(mAngle2[itube] * TMath::DegToRad())) / + TMath::Sin(mAngle2[itube] * TMath::DegToRad()); + TGeoVolume* waterTorusCentral = + gGeoManager->MakeTorus(Form("waterTorusCentral%d_D2_H%d", itube, half), + mWater, mRadiusCentralTore[itube], 0., mRWater, + -mAngle2[itube], 2. * mAngle2[itube]); rotation = new TGeoRotation("rotation", 0., 90., 0.); - transformation = new TGeoCombiTrans(yPos2[itube] + mLpartial2[itube] / 2 * TMath::Sin(mAngle2[itube] * TMath::DegToRad()) - mRadiusCentralTore[itube] * TMath::Cos(mAngle2[itube] * TMath::DegToRad()), 0., 0., rotation); + transformation = new TGeoCombiTrans( + yPos2[itube] + + mLpartial2[itube] / 2 * + TMath::Sin(mAngle2[itube] * TMath::DegToRad()) - + mRadiusCentralTore[itube] * + TMath::Cos(mAngle2[itube] * TMath::DegToRad()), + 0., 0., rotation); cooling->AddNode(waterTorusCentral, ivolume++, transformation); - TGeoVolume* waterTube3 = gGeoManager->MakeTube(Form("waterTube3%d_D2_H%d", 2, half), mWater, 0., mRWater, mLpartial2[itube] / 2.); + TGeoVolume* waterTube3 = + gGeoManager->MakeTube(Form("waterTube3%d_D2_H%d", 2, half), mWater, 0., + mRWater, mLpartial2[itube] / 2.); rotation = new TGeoRotation("rotation", -90., 0 - mAngle2[itube], 0.); - transformation = new TGeoCombiTrans(yPos2[itube], 0., -(mSupportXDimensions[2][0] / 2. + mMoreLength - xPos2[itube]), rotation); + transformation = new TGeoCombiTrans( + yPos2[itube], 0., + -(mSupportXDimensions[2][0] / 2. + mMoreLength - xPos2[itube]), + rotation); cooling->AddNode(waterTube3, ivolume++, transformation); - TGeoVolume* waterTorus2 = gGeoManager->MakeTorus(Form("waterTorus2%d_D2_H%d", itube, half), mWater, mRadius2[itube], 0., mRWater, 0., mAngle2[itube]); + TGeoVolume* waterTorus2 = gGeoManager->MakeTorus( + Form("waterTorus2%d_D2_H%d", itube, half), mWater, mRadius2[itube], 0., + mRWater, 0., mAngle2[itube]); rotation = new TGeoRotation("rotation", 180., 90., 0.); - transformation = new TGeoCombiTrans(mRadius2[itube] + mXPosition2[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube]), rotation); + transformation = new TGeoCombiTrans( + mRadius2[itube] + mXPosition2[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube]), + rotation); cooling->AddNode(waterTorus2, ivolume++, transformation); - TGeoVolume* waterTube4 = gGeoManager->MakeTube(Form("waterTube4%d_D2_H%d", itube, half), mWater, 0., mRWater, mLWater2[itube] / 2.); - translation = new TGeoTranslation(mXPosition2[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube] / 2.)); + TGeoVolume* waterTube4 = + gGeoManager->MakeTube(Form("waterTube4%d_D2_H%d", itube, half), mWater, + 0., mRWater, mLWater2[itube] / 2.); + translation = new TGeoTranslation( + mXPosition2[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube] / 2.)); cooling->AddNode(waterTube4, ivolume++, translation); } - // **************************************************** Tube part ************************************************ - // ****************************** Four parameters mLwater2, mRadius2, mAngle2, mLpartial2 ************************ + // **************************************************** Tube part + // ************************************************ + // ****************************** Four parameters mLwater2, mRadius2, mAngle2, + // mLpartial2 ************************ for (Int_t itube = 0; itube < 3; itube++) { - TGeoVolume* pipeTube1 = gGeoManager->MakeTube(Form("pipeTube1%d_D2_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLWater2[itube] / 2.); - translation = new TGeoTranslation(mXPosition2[itube] - mHalfDiskGap, 0., mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube] / 2.); + TGeoVolume* pipeTube1 = + gGeoManager->MakeTube(Form("pipeTube1%d_D2_H%d", itube, half), mPipe, + mRWater, mRWater + mDRPipe, mLWater2[itube] / 2.); + translation = new TGeoTranslation(mXPosition2[itube] - mHalfDiskGap, 0., + mSupportXDimensions[2][0] / 2. + + mMoreLength - mLWater2[itube] / 2.); cooling->AddNode(pipeTube1, ivolume++, translation); - TGeoVolume* pipeTorus1 = gGeoManager->MakeTorus(Form("pipeTorus1%d_D2_H%d", itube, half), mPipe, mRadius2[itube], mRWater, mRWater + mDRPipe, 0., mAngle2[itube]); + TGeoVolume* pipeTorus1 = gGeoManager->MakeTorus( + Form("pipeTorus1%d_D2_H%d", itube, half), mPipe, mRadius2[itube], + mRWater, mRWater + mDRPipe, 0., mAngle2[itube]); rotation = new TGeoRotation("rotation", 180., -90., 0.); - transformation = new TGeoCombiTrans(mRadius2[itube] + mXPosition2[itube] - mHalfDiskGap, 0., mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube], rotation); + transformation = new TGeoCombiTrans( + mRadius2[itube] + mXPosition2[itube] - mHalfDiskGap, 0., + mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube], + rotation); cooling->AddNode(pipeTorus1, ivolume++, transformation); - TGeoVolume* pipeTube2 = gGeoManager->MakeTube(Form("pipeTube2%d_D2_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLpartial2[itube] / 2.); + TGeoVolume* pipeTube2 = gGeoManager->MakeTube( + Form("pipeTube2%d_D2_H%d", itube, half), mPipe, mRWater, + mRWater + mDRPipe, mLpartial2[itube] / 2.); rotation = new TGeoRotation("rotation", 90., 180 - mAngle2[itube], 0.); - xPos2[itube] = mLWater2[itube] + mRadius2[itube] * TMath::Sin(mAngle2[itube] * TMath::DegToRad()) + mLpartial2[itube] / 2 * TMath::Cos(mAngle2[itube] * TMath::DegToRad()); - yPos2[itube] = mXPosition2[itube] - mHalfDiskGap + mRadius2[itube] * (1 - TMath::Cos(mAngle2[itube] * TMath::DegToRad())) + mLpartial2[itube] / 2 * TMath::Sin(mAngle2[itube] * TMath::DegToRad()); - transformation = new TGeoCombiTrans(yPos2[itube], 0., mSupportXDimensions[2][0] / 2. + mMoreLength - xPos2[itube], rotation); + xPos2[itube] = + mLWater2[itube] + + mRadius2[itube] * TMath::Sin(mAngle2[itube] * TMath::DegToRad()) + + mLpartial2[itube] / 2 * TMath::Cos(mAngle2[itube] * TMath::DegToRad()); + yPos2[itube] = + mXPosition2[itube] - mHalfDiskGap + + mRadius2[itube] * (1 - TMath::Cos(mAngle2[itube] * TMath::DegToRad())) + + mLpartial2[itube] / 2 * TMath::Sin(mAngle2[itube] * TMath::DegToRad()); + transformation = new TGeoCombiTrans( + yPos2[itube], 0., + mSupportXDimensions[2][0] / 2. + mMoreLength - xPos2[itube], rotation); cooling->AddNode(pipeTube2, ivolume++, transformation); - mRadiusCentralTore[itube] = (mSupportXDimensions[2][0] / 2. + mMoreLength - xPos2[itube] - mLpartial2[itube] / 2 * TMath::Cos(mAngle2[itube] * TMath::DegToRad())) / TMath::Sin(mAngle2[itube] * TMath::DegToRad()); - TGeoVolume* pipeTorusCentral = gGeoManager->MakeTorus(Form("pipeTorusCentral%d_D2_H%d", itube, half), mPipe, mRadiusCentralTore[itube], mRWater, mRWater + mDRPipe, - -mAngle2[itube], 2. * mAngle2[itube]); + mRadiusCentralTore[itube] = + (mSupportXDimensions[2][0] / 2. + mMoreLength - xPos2[itube] - + mLpartial2[itube] / 2 * + TMath::Cos(mAngle2[itube] * TMath::DegToRad())) / + TMath::Sin(mAngle2[itube] * TMath::DegToRad()); + TGeoVolume* pipeTorusCentral = gGeoManager->MakeTorus( + Form("pipeTorusCentral%d_D2_H%d", itube, half), mPipe, + mRadiusCentralTore[itube], mRWater, mRWater + mDRPipe, -mAngle2[itube], + 2. * mAngle2[itube]); rotation = new TGeoRotation("rotation", 0., 90., 0.); - transformation = new TGeoCombiTrans(yPos2[itube] + mLpartial2[itube] / 2 * TMath::Sin(mAngle2[itube] * TMath::DegToRad()) - mRadiusCentralTore[itube] * TMath::Cos(mAngle2[itube] * TMath::DegToRad()), 0., 0., rotation); + transformation = new TGeoCombiTrans( + yPos2[itube] + + mLpartial2[itube] / 2 * + TMath::Sin(mAngle2[itube] * TMath::DegToRad()) - + mRadiusCentralTore[itube] * + TMath::Cos(mAngle2[itube] * TMath::DegToRad()), + 0., 0., rotation); cooling->AddNode(pipeTorusCentral, ivolume++, transformation); - TGeoVolume* pipeTube3 = gGeoManager->MakeTube(Form("pipeTube3%d_D2_H%d", 2, half), mPipe, mRWater, mRWater + mDRPipe, mLpartial2[itube] / 2.); + TGeoVolume* pipeTube3 = gGeoManager->MakeTube( + Form("pipeTube3%d_D2_H%d", 2, half), mPipe, mRWater, mRWater + mDRPipe, + mLpartial2[itube] / 2.); rotation = new TGeoRotation("rotation", -90., 0 - mAngle2[itube], 0.); - transformation = new TGeoCombiTrans(yPos2[itube], 0., -(mSupportXDimensions[2][0] / 2. + mMoreLength - xPos2[itube]), rotation); + transformation = new TGeoCombiTrans( + yPos2[itube], 0., + -(mSupportXDimensions[2][0] / 2. + mMoreLength - xPos2[itube]), + rotation); cooling->AddNode(pipeTube3, ivolume++, transformation); - TGeoVolume* pipeTorus2 = gGeoManager->MakeTorus(Form("pipeTorus2%d_D2_H%d", itube, half), mPipe, mRadius2[itube], mRWater, mRWater + mDRPipe, 0., mAngle2[itube]); + TGeoVolume* pipeTorus2 = gGeoManager->MakeTorus( + Form("pipeTorus2%d_D2_H%d", itube, half), mPipe, mRadius2[itube], + mRWater, mRWater + mDRPipe, 0., mAngle2[itube]); rotation = new TGeoRotation("rotation", 180., 90., 0.); - transformation = new TGeoCombiTrans(mRadius2[itube] + mXPosition2[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube]), rotation); + transformation = new TGeoCombiTrans( + mRadius2[itube] + mXPosition2[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube]), + rotation); cooling->AddNode(pipeTorus2, ivolume++, transformation); - TGeoVolume* pipeTube4 = gGeoManager->MakeTube(Form("pipeTube4%d_D2_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLWater2[itube] / 2.); - translation = new TGeoTranslation(mXPosition2[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube] / 2.)); + TGeoVolume* pipeTube4 = + gGeoManager->MakeTube(Form("pipeTube4%d_D2_H%d", itube, half), mPipe, + mRWater, mRWater + mDRPipe, mLWater2[itube] / 2.); + translation = new TGeoTranslation( + mXPosition2[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[itube] / 2.)); cooling->AddNode(pipeTube4, ivolume++, translation); } // *********************************************************************************************** - Double_t deltaz = mHeatExchangerThickness - Geometry::sKaptonOnCarbonThickness * 4 - Geometry::sKaptonGlueThickness * 4 - 2 * mCarbonThickness; + Double_t deltaz = mHeatExchangerThickness - + Geometry::sKaptonOnCarbonThickness * 4 - + Geometry::sKaptonGlueThickness * 4 - 2 * mCarbonThickness; rotation = new TGeoRotation("rotation", -90., 90., 0.); - transformation = - new TGeoCombiTrans(0., 0., mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - 2 * Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - + 2 * Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(cooling, 3, transformation); - transformation = - new TGeoCombiTrans(0., 0., mZPlan[disk] - deltaz / 2. + mCarbonThickness + mRWater + mDRPipe + 2 * Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + mZPlan[disk] - deltaz / 2. + mCarbonThickness + mRWater + mDRPipe + + 2 * Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(cooling, 4, transformation); - // **************************************** Carbon Plates **************************************** - + // **************************************** Carbon Plates + // **************************************** auto* carbonPlate = new TGeoVolumeAssembly(Form("carbonPlate_D2_H%d", half)); - auto* carbonBase2 = new TGeoBBox(Form("carbonBase2_D2_H%d", half), (mSupportXDimensions[disk][0]) / 2. + mMoreLength, - (mSupportYDimensions[disk][0]) / 2., mCarbonThickness); - auto* t21 = new TGeoTranslation("t21", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + + auto& mftBaseParam = MFTBaseParam::Instance(); + Double_t mReducedX = 0.; + if (mftBaseParam.buildAlignment) { + mReducedX = 0.6; + } + + auto* carbonBase2 = new TGeoBBox( + Form("carbonBase2_D2_H%d", half), + (mSupportXDimensions[disk][0]) / 2. + mMoreLength - mReducedX, + (mSupportYDimensions[disk][0]) / 2., mCarbonThickness); + auto* t21 = new TGeoTranslation( + "t21", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); t21->RegisterYourself(); auto* holeCarbon2 = - new TGeoTubeSeg(Form("holeCarbon2_D2_H%d", half), 0., mRMin[disk], mCarbonThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holeCarbon2_D2_H%d", half), 0., mRMin[disk], + mCarbonThickness + 0.000001, 0, 180.); auto* t22 = new TGeoTranslation("t22", 0., -mHalfDiskGap, 0.); t22->RegisterYourself(); auto* carbonhole2 = new TGeoSubtraction(carbonBase2, holeCarbon2, t21, t22); auto* cs2 = new TGeoCompositeShape(Form("Carbon2_D2_H%d", half), carbonhole2); - auto* carbonBaseWithHole2 = new TGeoVolume(Form("carbonBaseWithHole_D2_H%d", half), cs2, mCarbon); + auto* carbonBaseWithHole2 = + new TGeoVolume(Form("carbonBaseWithHole_D2_H%d", half), cs2, mCarbon); carbonBaseWithHole2->SetLineColor(kGray + 3); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - carbonPlate->AddNode(carbonBaseWithHole2, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + carbonPlate->AddNode(carbonBaseWithHole2, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t ty = mSupportYDimensions[disk][0]; @@ -2122,7 +3126,8 @@ void HeatExchanger::createHalfDisk2(Int_t half) ty += mSupportYDimensions[disk][ipart] / 2.; auto* partCarbon0 = - new TGeoBBox(Form("partCarbon0_D2_H%d_%d", half, ipart), mSupportXDimensions[disk][ipart] / 2., + new TGeoBBox(Form("partCarbon0_D2_H%d_%d", half, ipart), + mSupportXDimensions[disk][ipart] / 2., mSupportYDimensions[disk][ipart] / 2., mCarbonThickness); auto* t = new TGeoTranslation("t", 0, ty + mHalfDiskGap, mZPlan[disk]); @@ -2133,18 +3138,24 @@ void HeatExchanger::createHalfDisk2(Int_t half) TGeoBBox* notchCarbon2; TGeoTranslation* tnotch2; if (ipart == (mNPart[disk] - 1)) { - notchCarbon2 = new TGeoBBox(Form("notchCarbon2_D2_H%d", half), 2.3, 0.6, mCarbonThickness + 0.000001); - tnotch2 = new TGeoTranslation("tnotch2", 0., mSupportYDimensions[disk][ipart] / 2., 0.); + notchCarbon2 = new TGeoBBox(Form("notchCarbon2_D2_H%d", half), 2.3, 0.6, + mCarbonThickness + 0.000001); + tnotch2 = new TGeoTranslation("tnotch2", 0., + mSupportYDimensions[disk][ipart] / 2., 0.); tnotch2->RegisterYourself(); - partCarbonini = new TGeoSubtraction(partCarbon0, notchCarbon2, nullptr, tnotch2); - auto* carbinit = new TGeoCompositeShape(Form("carbinit%d_D2_H%d", 0, half), partCarbonini); - partCarbonNotch = new TGeoVolume(Form("partCarbonNotch_D2_H%d_%d", half, ipart), carbinit, mCarbon); + partCarbonini = + new TGeoSubtraction(partCarbon0, notchCarbon2, nullptr, tnotch2); + auto* carbinit = new TGeoCompositeShape( + Form("carbinit%d_D2_H%d", 0, half), partCarbonini); + partCarbonNotch = new TGeoVolume( + Form("partCarbonNotch_D2_H%d_%d", half, ipart), carbinit, mCarbon); partCarbonNotch->SetLineColor(kGray + 3); carbonPlate->AddNode(partCarbonNotch, ipart, t); } if (ipart < (mNPart[disk] - 1)) { - auto* partCarbon = new TGeoVolume(Form("partCarbonNotch_D2_H%d_%d", half, ipart), partCarbon0, mCarbon); + auto* partCarbon = new TGeoVolume( + Form("partCarbonNotch_D2_H%d_%d", half, ipart), partCarbon0, mCarbon); partCarbon->SetLineColor(kGray + 3); carbonPlate->AddNode(partCarbon, ipart, t); } @@ -2158,36 +3169,54 @@ void HeatExchanger::createHalfDisk2(Int_t half) transformation = new TGeoCombiTrans(0., 0., -deltaz / 2., rotation); mHalfDisk->AddNode(carbonPlate, 4, transformation); - // **************************************** Glue Bwtween Carbon Plate and Rohacell Plate **************************************** + // **************************************** Glue Bwtween Carbon Plate and + // Rohacell Plate **************************************** TGeoMedium* mGlueRohacellCarbon = gGeoManager->GetMedium("MFT_Epoxy$"); - auto* glueRohacellCarbon = new TGeoVolumeAssembly(Form("glueRohacellCarbon_D0_H%d", half)); - auto* glueRohacellCarbonBase0 = new TGeoBBox(Form("glueRohacellCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2., - (mSupportYDimensions[disk][0]) / 2., Geometry::sGlueRohacellCarbonThickness); - - auto* translation_gluRC01 = new TGeoTranslation("translation_gluRC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* glueRohacellCarbon = + new TGeoVolumeAssembly(Form("glueRohacellCarbon_D0_H%d", half)); + auto* glueRohacellCarbonBase0 = + new TGeoBBox(Form("glueRohacellCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. - mReducedX, + (mSupportYDimensions[disk][0]) / 2., + Geometry::sGlueRohacellCarbonThickness); + + auto* translation_gluRC01 = new TGeoTranslation( + "translation_gluRC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_gluRC01->RegisterYourself(); - auto* translation_gluRC02 = new TGeoTranslation("translation_gluRC02", 0., -mHalfDiskGap, 0.); + auto* translation_gluRC02 = + new TGeoTranslation("translation_gluRC02", 0., -mHalfDiskGap, 0.); translation_gluRC02->RegisterYourself(); - auto* holeglueRohacellCarbon0 = - new TGeoTubeSeg(Form("holeglueRohacellCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sGlueRohacellCarbonThickness + 0.000001, 0, 180.); + auto* holeglueRohacellCarbon0 = new TGeoTubeSeg( + Form("holeglueRohacellCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sGlueRohacellCarbonThickness + 0.000001, 0, 180.); - auto* glueRohacellCarbonhole0 = new TGeoSubtraction(glueRohacellCarbonBase0, holeglueRohacellCarbon0, translation_gluRC01, translation_gluRC02); - auto* gRC0 = new TGeoCompositeShape(Form("glueRohacellCarbon0_D0_H%d", half), glueRohacellCarbonhole0); + auto* glueRohacellCarbonhole0 = + new TGeoSubtraction(glueRohacellCarbonBase0, holeglueRohacellCarbon0, + translation_gluRC01, translation_gluRC02); + auto* gRC0 = new TGeoCompositeShape(Form("glueRohacellCarbon0_D0_H%d", half), + glueRohacellCarbonhole0); - auto* glueRohacellCarbonBaseWithHole0 = new TGeoVolume(Form("glueRohacellCarbonWithHole_D0_H%d", half), gRC0, mGlueRohacellCarbon); + auto* glueRohacellCarbonBaseWithHole0 = + new TGeoVolume(Form("glueRohacellCarbonWithHole_D0_H%d", half), gRC0, + mGlueRohacellCarbon); glueRohacellCarbonBaseWithHole0->SetLineColor(kGreen); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - glueRohacellCarbon->AddNode(glueRohacellCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + glueRohacellCarbon->AddNode(glueRohacellCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyGRC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyGRC += mSupportYDimensions[disk][ipart] / 2.; - auto* partGlueRohacellCarbon = new TGeoBBox(Form("partGlueRohacellCarbon_D0_H%d_%d", half, ipart), mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sGlueRohacellCarbonThickness); + auto* partGlueRohacellCarbon = + new TGeoBBox(Form("partGlueRohacellCarbon_D0_H%d_%d", half, ipart), + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., + Geometry::sGlueRohacellCarbonThickness); //======== notch of the glue, fm === TGeoVolume* partGlueCarbonNotch; @@ -2195,13 +3224,20 @@ void HeatExchanger::createHalfDisk2(Int_t half) TGeoBBox* notchGlueCarbon2; TGeoTranslation* tnotch2; if (ipart == (mNPart[disk] - 1)) { - notchGlueCarbon2 = new TGeoBBox(Form("notchGlueCarbon2_D2_H%d", half), 2.3, 0.6, Geometry::sGlueRohacellCarbonThickness + 0.000001); - tnotch2 = new TGeoTranslation("tnotch2", 0., mSupportYDimensions[disk][ipart] / 2., 0.); + notchGlueCarbon2 = + new TGeoBBox(Form("notchGlueCarbon2_D2_H%d", half), 2.3, 0.6, + Geometry::sGlueRohacellCarbonThickness + 0.000001); + tnotch2 = new TGeoTranslation("tnotch2", 0., + mSupportYDimensions[disk][ipart] / 2., 0.); tnotch2->RegisterYourself(); - partGlueCarbonini = new TGeoSubtraction(partGlueRohacellCarbon, notchGlueCarbon2, nullptr, tnotch2); - auto* gluecarbinit = new TGeoCompositeShape(Form("gluecarbinit%d_D2_H%d", 0, half), partGlueCarbonini); - partGlueCarbonNotch = new TGeoVolume(Form("partGlueCarbonNotch_D2_H%d_%d", half, ipart), gluecarbinit, mGlueRohacellCarbon); + partGlueCarbonini = new TGeoSubtraction( + partGlueRohacellCarbon, notchGlueCarbon2, nullptr, tnotch2); + auto* gluecarbinit = new TGeoCompositeShape( + Form("gluecarbinit%d_D2_H%d", 0, half), partGlueCarbonini); + partGlueCarbonNotch = + new TGeoVolume(Form("partGlueCarbonNotch_D2_H%d_%d", half, ipart), + gluecarbinit, mGlueRohacellCarbon); partGlueCarbonNotch->SetLineColor(kGray + 3); } @@ -2211,7 +3247,9 @@ void HeatExchanger::createHalfDisk2(Int_t half) glueRohacellCarbon->AddNode(partGlueCarbonNotch, ipart, t); } if (ipart < (mNPart[disk] - 1)) { - auto* partGlueCarbon = new TGeoVolume(Form("partGlueCarbon_D2_H%d_%d", half, ipart), partGlueRohacellCarbon, mGlueRohacellCarbon); + auto* partGlueCarbon = + new TGeoVolume(Form("partGlueCarbon_D2_H%d_%d", half, ipart), + partGlueRohacellCarbon, mGlueRohacellCarbon); partGlueCarbon->SetLineColor(kGreen); glueRohacellCarbon->AddNode(partGlueCarbon, ipart, t); } @@ -2220,42 +3258,64 @@ void HeatExchanger::createHalfDisk2(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(glueRohacellCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness), rotation); + transformation = new TGeoCombiTrans(0., 0., + -(deltaz / 2. - mCarbonThickness - + Geometry::sGlueRohacellCarbonThickness), + rotation); mHalfDisk->AddNode(glueRohacellCarbon, 4, transformation); - // **************************************** Kapton on Carbon Plate **************************************** + // **************************************** Kapton on Carbon Plate + // **************************************** TGeoMedium* mKaptonOnCarbon = gGeoManager->GetMedium("MFT_Kapton$"); - auto* kaptonOnCarbon = new TGeoVolumeAssembly(Form("kaptonOnCarbon_D0_H%d", half)); - auto* kaptonOnCarbonBase0 = new TGeoBBox(Form("kaptonOnCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2. + mMoreLength, - (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonOnCarbonThickness); + auto* kaptonOnCarbon = + new TGeoVolumeAssembly(Form("kaptonOnCarbon_D0_H%d", half)); + auto* kaptonOnCarbonBase0 = new TGeoBBox( + Form("kaptonOnCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. + mMoreLength - mReducedX, + (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonOnCarbonThickness); - auto* translation_KC01 = new TGeoTranslation("translation_KC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* translation_KC01 = new TGeoTranslation( + "translation_KC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_KC01->RegisterYourself(); - auto* translation_KC02 = new TGeoTranslation("translation_KC02", 0., -mHalfDiskGap, 0.); + auto* translation_KC02 = + new TGeoTranslation("translation_KC02", 0., -mHalfDiskGap, 0.); translation_KC02->RegisterYourself(); auto* holekaptonOnCarbon0 = - new TGeoTubeSeg(Form("holekaptonOnCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sKaptonOnCarbonThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holekaptonOnCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sKaptonOnCarbonThickness + 0.000001, 0, 180.); - auto* kaptonOnCarbonhole0 = new TGeoSubtraction(kaptonOnCarbonBase0, holekaptonOnCarbon0, translation_KC01, translation_KC02); - auto* KC0 = new TGeoCompositeShape(Form("kaptonOnCarbon_D0_H%d", half), kaptonOnCarbonhole0); - auto* kaptonOnCarbonBaseWithHole0 = new TGeoVolume(Form("kaptonOnCarbonWithHole_D0_H%d", half), KC0, mKaptonOnCarbon); + auto* kaptonOnCarbonhole0 = + new TGeoSubtraction(kaptonOnCarbonBase0, holekaptonOnCarbon0, + translation_KC01, translation_KC02); + auto* KC0 = new TGeoCompositeShape(Form("kaptonOnCarbon_D0_H%d", half), + kaptonOnCarbonhole0); + auto* kaptonOnCarbonBaseWithHole0 = new TGeoVolume( + Form("kaptonOnCarbonWithHole_D0_H%d", half), KC0, mKaptonOnCarbon); kaptonOnCarbonBaseWithHole0->SetLineColor(kMagenta); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - kaptonOnCarbon->AddNode(kaptonOnCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + kaptonOnCarbon->AddNode(kaptonOnCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyKC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyKC += mSupportYDimensions[disk][ipart] / 2.; - auto* partKaptonOnCarbonBase = new TGeoBBox(Form("partKaptonOnCarbon_D0_H%d_%d", half, ipart), mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonOnCarbonThickness); + auto* partKaptonOnCarbonBase = + new TGeoBBox(Form("partKaptonOnCarbon_D0_H%d_%d", half, ipart), + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., + Geometry::sKaptonOnCarbonThickness); //======== notch of the kapton, fm === TGeoVolume* partKaptonNotch; @@ -2263,13 +3323,20 @@ void HeatExchanger::createHalfDisk2(Int_t half) TGeoBBox* notchKapton2; TGeoTranslation* tnotch2; if (ipart == (mNPart[disk] - 1)) { - notchKapton2 = new TGeoBBox(Form("notchKapton2_D2_H%d", half), 2.3, 0.6, Geometry::sKaptonOnCarbonThickness + 0.000001); - tnotch2 = new TGeoTranslation("tnotch2", 0., mSupportYDimensions[disk][ipart] / 2., 0.); + notchKapton2 = + new TGeoBBox(Form("notchKapton2_D2_H%d", half), 2.3, 0.6, + Geometry::sKaptonOnCarbonThickness + 0.000001); + tnotch2 = new TGeoTranslation("tnotch2", 0., + mSupportYDimensions[disk][ipart] / 2., 0.); tnotch2->RegisterYourself(); - partKaptonini = new TGeoSubtraction(partKaptonOnCarbonBase, notchKapton2, nullptr, tnotch2); - auto* kaptinit = new TGeoCompositeShape(Form("kaptinit%d_D2_H%d", 0, half), partKaptonini); - partKaptonNotch = new TGeoVolume(Form("partKaptonNotch_D2_H%d_%d", half, ipart), kaptinit, mKaptonOnCarbon); + partKaptonini = new TGeoSubtraction(partKaptonOnCarbonBase, notchKapton2, + nullptr, tnotch2); + auto* kaptinit = new TGeoCompositeShape( + Form("kaptinit%d_D2_H%d", 0, half), partKaptonini); + partKaptonNotch = + new TGeoVolume(Form("partKaptonNotch_D2_H%d_%d", half, ipart), + kaptinit, mKaptonOnCarbon); } auto* t = new TGeoTranslation("t", 0, tyKC + mHalfDiskGap, mZPlan[disk]); @@ -2278,7 +3345,9 @@ void HeatExchanger::createHalfDisk2(Int_t half) kaptonOnCarbon->AddNode(partKaptonNotch, ipart, t); } if (ipart < (mNPart[disk] - 1)) { - auto* partKapton = new TGeoVolume(Form("partKapton_D2_H%d_%d", half, ipart), partKaptonOnCarbonBase, mKaptonOnCarbon); + auto* partKapton = + new TGeoVolume(Form("partKapton_D2_H%d_%d", half, ipart), + partKaptonOnCarbonBase, mKaptonOnCarbon); partKapton->SetLineColor(kMagenta); kaptonOnCarbon->AddNode(partKapton, ipart, t); } @@ -2287,41 +3356,64 @@ void HeatExchanger::createHalfDisk2(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + Geometry::sKaptonGlueThickness * 2, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + + Geometry::sKaptonGlueThickness * 2, + rotation); mHalfDisk->AddNode(kaptonOnCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + Geometry::sKaptonGlueThickness * 2), rotation); + transformation = new TGeoCombiTrans( + 0., 0., + -(deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + + Geometry::sKaptonGlueThickness * 2), + rotation); mHalfDisk->AddNode(kaptonOnCarbon, 4, transformation); - // **************************************** Kapton glue on the carbon plate **************************************** + // **************************************** Kapton glue on the carbon plate + // **************************************** TGeoMedium* mGlueKaptonCarbon = gGeoManager->GetMedium("MFT_Epoxy$"); - auto* glueKaptonCarbon = new TGeoVolumeAssembly(Form("glueKaptonCarbon_D0_H%d", half)); - auto* glueKaptonCarbonBase0 = new TGeoBBox(Form("glueKaptonCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2., - (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonGlueThickness); - - auto* translation_gluKC01 = new TGeoTranslation("translation_gluKC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* glueKaptonCarbon = + new TGeoVolumeAssembly(Form("glueKaptonCarbon_D0_H%d", half)); + auto* glueKaptonCarbonBase0 = new TGeoBBox( + Form("glueKaptonCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. - mReducedX, + (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonGlueThickness); + + auto* translation_gluKC01 = new TGeoTranslation( + "translation_gluKC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_gluKC01->RegisterYourself(); - auto* translation_gluKC02 = new TGeoTranslation("translation_gluKC02", 0., -mHalfDiskGap, 0.); + auto* translation_gluKC02 = + new TGeoTranslation("translation_gluKC02", 0., -mHalfDiskGap, 0.); translation_gluKC02->RegisterYourself(); - auto* holeglueKaptonCarbon0 = - new TGeoTubeSeg(Form("holeglueKaptonCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sKaptonGlueThickness + 0.000001, 0, 180.); + auto* holeglueKaptonCarbon0 = new TGeoTubeSeg( + Form("holeglueKaptonCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sKaptonGlueThickness + 0.000001, 0, 180.); - auto* glueKaptonCarbonhole0 = new TGeoSubtraction(glueKaptonCarbonBase0, holeglueKaptonCarbon0, translation_gluKC01, translation_gluKC02); - auto* gKC0 = new TGeoCompositeShape(Form("glueKaptonCarbon0_D0_H%d", half), glueKaptonCarbonhole0); - auto* glueKaptonCarbonBaseWithHole0 = new TGeoVolume(Form("glueKaptonCarbonWithHole_D0_H%d", half), gKC0, mGlueKaptonCarbon); + auto* glueKaptonCarbonhole0 = + new TGeoSubtraction(glueKaptonCarbonBase0, holeglueKaptonCarbon0, + translation_gluKC01, translation_gluKC02); + auto* gKC0 = new TGeoCompositeShape(Form("glueKaptonCarbon0_D0_H%d", half), + glueKaptonCarbonhole0); + auto* glueKaptonCarbonBaseWithHole0 = new TGeoVolume( + Form("glueKaptonCarbonWithHole_D0_H%d", half), gKC0, mGlueKaptonCarbon); glueKaptonCarbonBaseWithHole0->SetLineColor(kGreen); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - glueKaptonCarbon->AddNode(glueKaptonCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + glueKaptonCarbon->AddNode(glueKaptonCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyGKC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyGKC += mSupportYDimensions[disk][ipart] / 2.; - auto* partGlueKaptonCarbon = new TGeoBBox(Form("partGlueKaptonCarbon_D0_H%d_%d", half, ipart), mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonGlueThickness); + auto* partGlueKaptonCarbon = new TGeoBBox( + Form("partGlueKaptonCarbon_D0_H%d_%d", half, ipart), + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonGlueThickness); //======== notch of the glue, fm === TGeoVolume* partGlueKaptonNotch; @@ -2329,13 +3421,20 @@ void HeatExchanger::createHalfDisk2(Int_t half) TGeoBBox* notchGlueKapton2; TGeoTranslation* tnotch2; if (ipart == (mNPart[disk] - 1)) { - notchGlueKapton2 = new TGeoBBox(Form("notchGlueKapton2_D2_H%d", half), 2.3, 0.6, Geometry::sKaptonGlueThickness + 0.000001); - tnotch2 = new TGeoTranslation("tnotch2", 0., mSupportYDimensions[disk][ipart] / 2., 0.); + notchGlueKapton2 = + new TGeoBBox(Form("notchGlueKapton2_D2_H%d", half), 2.3, 0.6, + Geometry::sKaptonGlueThickness + 0.000001); + tnotch2 = new TGeoTranslation("tnotch2", 0., + mSupportYDimensions[disk][ipart] / 2., 0.); tnotch2->RegisterYourself(); - partGlueKaptonini = new TGeoSubtraction(partGlueKaptonCarbon, notchGlueKapton2, nullptr, tnotch2); - auto* gluekaptinit = new TGeoCompositeShape(Form("gluekaptinit%d_D2_H%d", 0, half), partGlueKaptonini); - partGlueKaptonNotch = new TGeoVolume(Form("partGlueKaptonNotch_D2_H%d_%d", half, ipart), gluekaptinit, mGlueKaptonCarbon); + partGlueKaptonini = new TGeoSubtraction( + partGlueKaptonCarbon, notchGlueKapton2, nullptr, tnotch2); + auto* gluekaptinit = new TGeoCompositeShape( + Form("gluekaptinit%d_D2_H%d", 0, half), partGlueKaptonini); + partGlueKaptonNotch = + new TGeoVolume(Form("partGlueKaptonNotch_D2_H%d_%d", half, ipart), + gluekaptinit, mGlueKaptonCarbon); } auto* t = new TGeoTranslation("t", 0, tyGKC + mHalfDiskGap, mZPlan[disk]); @@ -2345,7 +3444,9 @@ void HeatExchanger::createHalfDisk2(Int_t half) glueKaptonCarbon->AddNode(partGlueKaptonNotch, ipart, t); } if (ipart < (mNPart[disk] - 1)) { - auto* partGlueKapton = new TGeoVolume(Form("partGlueKapton_D2_H%d_%d", half, ipart), partGlueKaptonCarbon, mGlueKaptonCarbon); + auto* partGlueKapton = + new TGeoVolume(Form("partGlueKapton_D2_H%d_%d", half, ipart), + partGlueKaptonCarbon, mGlueKaptonCarbon); partGlueKapton->SetLineColor(kGreen); glueKaptonCarbon->AddNode(partGlueKapton, ipart, t); } @@ -2354,19 +3455,29 @@ void HeatExchanger::createHalfDisk2(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness, + rotation); mHalfDisk->AddNode(glueKaptonCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness), rotation); + transformation = new TGeoCombiTrans( + 0., 0., + -(deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness), + rotation); mHalfDisk->AddNode(glueKaptonCarbon, 4, transformation); - // **************************************** Rohacell Plate **************************************** - auto* rohacellPlate = new TGeoVolumeAssembly(Form("rohacellPlate_D2_H%d", half)); - auto* rohacellBase2 = new TGeoBBox(Form("rohacellBase2_D2_H%d", half), (mSupportXDimensions[disk][0]) / 2., - (mSupportYDimensions[disk][0]) / 2., mRohacellThickness); + // **************************************** Rohacell Plate + // **************************************** + auto* rohacellPlate = + new TGeoVolumeAssembly(Form("rohacellPlate_D2_H%d", half)); + auto* rohacellBase2 = new TGeoBBox( + Form("rohacellBase2_D2_H%d", half), (mSupportXDimensions[disk][0]) / 2., + (mSupportYDimensions[disk][0]) / 2., mRohacellThickness); auto* holeRohacell2 = - new TGeoTubeSeg(Form("holeRohacell2_D2_H%d", half), 0., mRMin[disk], mRohacellThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holeRohacell2_D2_H%d", half), 0., mRMin[disk], + mRohacellThickness + 0.000001, 0, 180.); - // **************************************** GROOVES ************************************************* + // **************************************** GROOVES + // ************************************************* Double_t diameter = 0.21; // groove diameter Double_t epsilon = 0.06; // outside shift of the goove Int_t iCount = 0; @@ -2378,20 +3489,31 @@ void HeatExchanger::createHalfDisk2(Int_t half) TGeoCompositeShape* rohacellGroove[300]; for (Int_t igroove = 0; igroove < 3; igroove++) { - grooveTube[0][igroove] = new TGeoTube("linear", 0., diameter, mLWater2[igroove] / 2.); - grooveTorus[1][igroove] = new TGeoTorus("SideTorus", mRadius2[igroove], 0., diameter, 0., mAngle2[igroove]); - grooveTube[2][igroove] = new TGeoTube("tiltedLinear", 0., diameter, mLpartial2[igroove] / 2.); - grooveTorus[3][igroove] = new TGeoTorus("centralTorus", mRadiusCentralTore[igroove], 0., diameter, -mAngle2[igroove], 2. * mAngle2[igroove]); - grooveTube[4][igroove] = new TGeoTube("tiltedLinear", 0., diameter, mLpartial2[igroove] / 2.); - grooveTorus[5][igroove] = new TGeoTorus("SideTorus", mRadius2[igroove], 0., diameter, 0., mAngle2[igroove]); - grooveTube[6][igroove] = new TGeoTube("linear", 0., diameter, mLWater2[igroove] / 2.); + grooveTube[0][igroove] = + new TGeoTube("linear", 0., diameter, mLWater2[igroove] / 2.); + grooveTorus[1][igroove] = new TGeoTorus("SideTorus", mRadius2[igroove], 0., + diameter, 0., mAngle2[igroove]); + grooveTube[2][igroove] = + new TGeoTube("tiltedLinear", 0., diameter, mLpartial2[igroove] / 2.); + grooveTorus[3][igroove] = + new TGeoTorus("centralTorus", mRadiusCentralTore[igroove], 0., diameter, + -mAngle2[igroove], 2. * mAngle2[igroove]); + grooveTube[4][igroove] = + new TGeoTube("tiltedLinear", 0., diameter, mLpartial2[igroove] / 2.); + grooveTorus[5][igroove] = new TGeoTorus("SideTorus", mRadius2[igroove], 0., + diameter, 0., mAngle2[igroove]); + grooveTube[6][igroove] = + new TGeoTube("linear", 0., diameter, mLWater2[igroove] / 2.); } // Rotation matrix TGeoRotation* rotationLinear = new TGeoRotation("rotation", -90., 90., 0.); - TGeoRotation* rotationSideTorusL = new TGeoRotation("rotationSideTorusLeft", -90., 0., 0.); - TGeoRotation* rotationSideTorusR = new TGeoRotation("rotationSideTorusRight", 90., 180., 180.); - TGeoRotation* rotationCentralTorus = new TGeoRotation("rotationCentralTorus", 90., 0., 0.); + TGeoRotation* rotationSideTorusL = + new TGeoRotation("rotationSideTorusLeft", -90., 0., 0.); + TGeoRotation* rotationSideTorusR = + new TGeoRotation("rotationSideTorusRight", 90., 180., 180.); + TGeoRotation* rotationCentralTorus = + new TGeoRotation("rotationCentralTorus", 90., 0., 0.); TGeoRotation* rotationTiltedLinearR; TGeoRotation* rotationTiltedLinearL; @@ -2399,52 +3521,96 @@ void HeatExchanger::createHalfDisk2(Int_t half) if (Geometry::sGrooves == 1) { for (Int_t iface = 1; iface > -2; iface -= 2) { // front and rear for (Int_t igroove = 0; igroove < 3; igroove++) { // 3 grooves - mPosition[igroove] = mXPosition2[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap; + mPosition[igroove] = mXPosition2[igroove] - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap; for (Int_t ip = 0; ip < 7; ip++) { // each groove is made of 7 parts switch (ip) { case 0: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + mMoreLength - mLWater2[igroove] / 2., mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2. + mMoreLength - + mLWater2[igroove] / 2., + mPosition[igroove], iface * (mRohacellThickness + epsilon), + rotationLinear); if (igroove == 0 && iface == 1) { - rohacellBaseGroove[0] = new TGeoSubtraction(rohacellBase2, grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); - rohacellGroove[0] = new TGeoCompositeShape(Form("rohacell2Groove%d_G%d_F%d_H%d", ip, igroove, iface, half), rohacellBaseGroove[0]); + rohacellBaseGroove[0] = + new TGeoSubtraction(rohacellBase2, grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); + rohacellGroove[0] = + new TGeoCompositeShape(Form("rohacell2Groove%d_G%d_F%d_H%d", + ip, igroove, iface, half), + rohacellBaseGroove[0]); }; break; case 1: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + mMoreLength - mLWater2[igroove], mRadius2[igroove] + mXPosition2[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, iface * (mRohacellThickness + epsilon), rotationSideTorusR); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2. + mMoreLength - + mLWater2[igroove], + mRadius2[igroove] + mXPosition2[igroove] - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationSideTorusR); break; case 2: // Linear tilted - rotationTiltedLinearR = new TGeoRotation("rotationTiltedLinearRight", 90. - mAngle2[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + mMoreLength - xPos2[igroove], yPos2[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); + rotationTiltedLinearR = new TGeoRotation( + "rotationTiltedLinearRight", 90. - mAngle2[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2. + mMoreLength - + xPos2[igroove], + yPos2[igroove] - mSupportYDimensions[disk][0] / 2. - + mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); break; case 3: // Central Torus - transfo[ip][igroove] = new TGeoCombiTrans(0., yPos2[igroove] + mLpartial2[igroove] / 2 * TMath::Sin(mAngle2[igroove] * TMath::DegToRad()) - mRadiusCentralTore[igroove] * TMath::Cos(mAngle2[igroove] * TMath::DegToRad()) - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationCentralTorus); + transfo[ip][igroove] = new TGeoCombiTrans( + 0., + yPos2[igroove] + + mLpartial2[igroove] / 2 * + TMath::Sin(mAngle2[igroove] * TMath::DegToRad()) - + mRadiusCentralTore[igroove] * + TMath::Cos(mAngle2[igroove] * TMath::DegToRad()) - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationCentralTorus); break; case 4: // Linear tilted - rotationTiltedLinearL = new TGeoRotation("rotationTiltedLinearLeft", 90. + mAngle2[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[disk][0] / 2. + mMoreLength - xPos2[igroove]), yPos2[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); + rotationTiltedLinearL = new TGeoRotation( + "rotationTiltedLinearLeft", 90. + mAngle2[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[disk][0] / 2. + mMoreLength - + xPos2[igroove]), + yPos2[igroove] - mSupportYDimensions[disk][0] / 2. - + mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); break; case 5: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[disk][0] / 2. + mMoreLength - mLWater2[igroove]), mRadius2[igroove] + mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationSideTorusL); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[disk][0] / 2. + mMoreLength - + mLWater2[igroove]), + mRadius2[igroove] + mPosition[igroove], + iface * (mRohacellThickness + epsilon), rotationSideTorusL); break; case 6: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[disk][0] / 2. + mMoreLength - mLWater2[igroove] / 2.), mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[disk][0] / 2. + mMoreLength - + mLWater2[igroove] / 2.), + mPosition[igroove], iface * (mRohacellThickness + epsilon), + rotationLinear); break; } if (!(ip == 0 && igroove == 0 && iface == 1)) { if (ip & 1) { - rohacellBaseGroove[iCount] = new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, + transfo[ip][igroove]); } else { - rohacellBaseGroove[iCount] = new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, + transfo[ip][igroove]); } - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell2Groove%d_G%d_F%d_H%d", iCount, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell2Groove%d_G%d_F%d_H%d", + iCount, igroove, iface, half), + rohacellBaseGroove[iCount]); } iCount++; } @@ -2459,16 +3625,20 @@ void HeatExchanger::createHalfDisk2(Int_t half) rohacellBase = new TGeoSubtraction(rohacellBase2, holeRohacell2, t21, t22); } if (Geometry::sGrooves == 1) { - rohacellBase = new TGeoSubtraction(rohacellGroove[iCount - 1], holeRohacell2, t21, t22); + rohacellBase = new TGeoSubtraction(rohacellGroove[iCount - 1], + holeRohacell2, t21, t22); } - auto* rh2 = new TGeoCompositeShape(Form("rohacellTore%d_D2_H%d", 0, half), rohacellBase); - auto* rohacellBaseWithHole = new TGeoVolume(Form("rohacellBaseWithHole_D2_H%d", half), rh2, mRohacell); + auto* rh2 = new TGeoCompositeShape(Form("rohacellTore%d_D2_H%d", 0, half), + rohacellBase); + auto* rohacellBaseWithHole = + new TGeoVolume(Form("rohacellBaseWithHole_D2_H%d", half), rh2, mRohacell); TGeoVolume* partRohacell; rohacellBaseWithHole->SetLineColor(kGray); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - rohacellPlate->AddNode(rohacellBaseWithHole, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + rohacellPlate->AddNode(rohacellBaseWithHole, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); ty = mSupportYDimensions[disk][0]; @@ -2479,74 +3649,129 @@ void HeatExchanger::createHalfDisk2(Int_t half) //=========================================================================================================== //=========================================================================================================== auto* partRohacell0 = - new TGeoBBox(Form("rohacellBase0_D2_H%d_%d", half, ipart), mSupportXDimensions[disk][ipart] / 2., + new TGeoBBox(Form("rohacellBase0_D2_H%d_%d", half, ipart), + mSupportXDimensions[disk][ipart] / 2., mSupportYDimensions[disk][ipart] / 2., mRohacellThickness); if (Geometry::sGrooves == 1) { - // ***************** Creating grooves for the other parts of the rohacell plate ********************** + // ***************** Creating grooves for the other parts of the rohacell + // plate ********************** Double_t mShift; for (Int_t iface = 1; iface > -2; iface -= 2) { // front and rear for (Int_t igroove = 0; igroove < 3; igroove++) { // 3 grooves if (ipart == 1) { - mPosition[ipart] = mXPosition2[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1]; + mPosition[ipart] = + mXPosition2[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1]; mShift = -mSupportYDimensions[disk][ipart - 1]; }; if (ipart == 2) { - mPosition[ipart] = mXPosition2[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2]; - mShift = -mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2]; + mPosition[ipart] = + mXPosition2[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2]; + mShift = -mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2]; }; if (ipart == 3) { - mPosition[ipart] = mXPosition2[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2] - mSupportYDimensions[disk][ipart - 3]; - mShift = -mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2] - mSupportYDimensions[disk][ipart - 3]; + mPosition[ipart] = + mXPosition2[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2] - + mSupportYDimensions[disk][ipart - 3]; + mShift = -mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2] - + mSupportYDimensions[disk][ipart - 3]; }; for (Int_t ip = 0; ip < 7; ip++) { // each groove is made of 7 parts switch (ip) { case 0: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + mMoreLength - mLWater2[igroove] / 2., mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[disk][0] / 2. + mMoreLength - + mLWater2[igroove] / 2., + mPosition[ipart], iface * (mRohacellThickness + epsilon), + rotationLinear); if (igroove == 0 && iface == 1) { - rohacellBaseGroove[iCount] = new TGeoSubtraction(partRohacell0, grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell2Groove%d_G%d_F%d_H%d", ip, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellBaseGroove[iCount] = + new TGeoSubtraction(partRohacell0, grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell2Groove%d_G%d_F%d_H%d", + ip, igroove, iface, half), + rohacellBaseGroove[iCount]); }; break; case 1: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[2][0] / 2. + mMoreLength - mLWater2[igroove], mPosition[ipart] + mRadius2[igroove], - iface * (mRohacellThickness + epsilon), rotationSideTorusR); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[2][0] / 2. + mMoreLength - + mLWater2[igroove], + mPosition[ipart] + mRadius2[igroove], + iface * (mRohacellThickness + epsilon), rotationSideTorusR); break; case 2: // Linear tilted - rotationTiltedLinearR = new TGeoRotation("rotationTiltedLinearRight", 90. - mAngle2[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + mMoreLength - xPos2[igroove], yPos2[igroove] + mShift - mHalfDiskGap - mSupportYDimensions[disk][ipart] / 2., iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); + rotationTiltedLinearR = new TGeoRotation( + "rotationTiltedLinearRight", 90. - mAngle2[igroove], 90., 0.); + transfo[ip][igroove] = + new TGeoCombiTrans(mSupportXDimensions[disk][0] / 2. + + mMoreLength - xPos2[igroove], + yPos2[igroove] + mShift - mHalfDiskGap - + mSupportYDimensions[disk][ipart] / 2., + iface * (mRohacellThickness + epsilon), + rotationTiltedLinearR); break; case 3: // Central Torus - transfo[ip][igroove] = new TGeoCombiTrans(0., mPosition[ipart] + yPos2[igroove] + mLpartial2[igroove] / 2 * TMath::Sin(mAngle2[igroove] * TMath::DegToRad()) - mRadiusCentralTore[igroove] * TMath::Cos(mAngle2[igroove] * TMath::DegToRad()) - mXPosition2[igroove], - iface * (mRohacellThickness + epsilon), rotationCentralTorus); + transfo[ip][igroove] = new TGeoCombiTrans( + 0., + mPosition[ipart] + yPos2[igroove] + + mLpartial2[igroove] / 2 * + TMath::Sin(mAngle2[igroove] * TMath::DegToRad()) - + mRadiusCentralTore[igroove] * + TMath::Cos(mAngle2[igroove] * TMath::DegToRad()) - + mXPosition2[igroove], + iface * (mRohacellThickness + epsilon), rotationCentralTorus); break; case 4: // Linear tilted - rotationTiltedLinearL = new TGeoRotation("rotationTiltedLinearLeft", 90. + mAngle2[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[disk][0] / 2. + mMoreLength - xPos2[igroove]), yPos2[igroove] + mPosition[ipart] - mXPosition2[igroove], - iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); + rotationTiltedLinearL = new TGeoRotation( + "rotationTiltedLinearLeft", 90. + mAngle2[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[disk][0] / 2. + mMoreLength - + xPos2[igroove]), + yPos2[igroove] + mPosition[ipart] - mXPosition2[igroove], + iface * (mRohacellThickness + epsilon), + rotationTiltedLinearL); break; case 5: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[disk][0] / 2. + mMoreLength - mLWater2[igroove]), mRadius2[igroove] + mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationSideTorusL); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[disk][0] / 2. + mMoreLength - + mLWater2[igroove]), + mRadius2[igroove] + mPosition[ipart], + iface * (mRohacellThickness + epsilon), rotationSideTorusL); break; case 6: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[disk][0] / 2. + mMoreLength - mLWater2[igroove] / 2.), mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[disk][0] / 2. + mMoreLength - + mLWater2[igroove] / 2.), + mPosition[ipart], iface * (mRohacellThickness + epsilon), + rotationLinear); break; } if (!(ip == 0 && igroove == 0 && iface == 1)) { if (ip & 1) { - rohacellBaseGroove[iCount] = - new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTorus[ip][igroove], + nullptr, transfo[ip][igroove]); } else { - rohacellBaseGroove[iCount] = - new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); } - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell2Groove%d_G%d_F%d_H%d", iCount, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell2Groove%d_G%d_F%d_H%d", + iCount, igroove, iface, half), + rohacellBaseGroove[iCount]); } iCount++; } @@ -2564,37 +3789,55 @@ void HeatExchanger::createHalfDisk2(Int_t half) TGeoBBox* notchRohacell22; TGeoTranslation* tnotch22; if (ipart == (mNPart[disk] - 1)) { - notchRohacell21 = new TGeoBBox(Form("notchRohacell21_D2_H%d", half), 2.3, 0.6, mRohacellThickness + 0.000001); - tnotch21 = new TGeoTranslation("tnotch21", 0., mSupportYDimensions[disk][ipart] / 2., 0.); + notchRohacell21 = new TGeoBBox(Form("notchRohacell21_D2_H%d", half), 2.3, + 0.6, mRohacellThickness + 0.000001); + tnotch21 = new TGeoTranslation("tnotch21", 0., + mSupportYDimensions[disk][ipart] / 2., 0.); tnotch21->RegisterYourself(); - notchRohacell22 = new TGeoBBox(Form("notchRohacell22_D2_H%d", half), 1.1, 0.6, mRohacellThickness + 0.000001); - tnotch22 = new TGeoTranslation("tnotch22", 0., mSupportYDimensions[disk][ipart] / 2. - 0.4, 0.); + notchRohacell22 = new TGeoBBox(Form("notchRohacell22_D2_H%d", half), 1.1, + 0.6, mRohacellThickness + 0.000001); + tnotch22 = new TGeoTranslation( + "tnotch22", 0., mSupportYDimensions[disk][ipart] / 2. - 0.4, 0.); tnotch22->RegisterYourself(); } //============================================================= if (Geometry::sGrooves == 0) { if (ipart == (mNPart[disk] - 1)) { - partRohacellini1 = new TGeoSubtraction(partRohacell0, notchRohacell21, nullptr, tnotch21); - auto* rhinit1 = new TGeoCompositeShape(Form("rhinit1%d_D2_H%d", 0, half), partRohacellini1); - partRohacellini2 = new TGeoSubtraction(rhinit1, notchRohacell22, nullptr, tnotch22); - auto* rhinit2 = new TGeoCompositeShape(Form("rhinit2%d_D2_H%d", 0, half), partRohacellini2); - partRohacell = new TGeoVolume(Form("partRohacelli_D2_H%d_%d", half, ipart), rhinit2, mRohacell); + partRohacellini1 = new TGeoSubtraction(partRohacell0, notchRohacell21, + nullptr, tnotch21); + auto* rhinit1 = new TGeoCompositeShape( + Form("rhinit1%d_D2_H%d", 0, half), partRohacellini1); + partRohacellini2 = + new TGeoSubtraction(rhinit1, notchRohacell22, nullptr, tnotch22); + auto* rhinit2 = new TGeoCompositeShape( + Form("rhinit2%d_D2_H%d", 0, half), partRohacellini2); + partRohacell = new TGeoVolume( + Form("partRohacelli_D2_H%d_%d", half, ipart), rhinit2, mRohacell); } if (ipart < (mNPart[disk] - 1)) { - partRohacell = new TGeoVolume(Form("partRohacelli_D2_H%d_%d", half, ipart), partRohacell0, mRohacell); + partRohacell = + new TGeoVolume(Form("partRohacelli_D2_H%d_%d", half, ipart), + partRohacell0, mRohacell); } } if (Geometry::sGrooves == 1) { if (ipart == (mNPart[disk] - 1)) { - partRohacellini1 = new TGeoSubtraction(rohacellGroove[iCount - 1], notchRohacell21, nullptr, tnotch21); - auto* rhinit1 = new TGeoCompositeShape(Form("rhinit1%d_D2_H%d", 0, half), partRohacellini1); - partRohacellini2 = new TGeoSubtraction(rhinit1, notchRohacell22, nullptr, tnotch22); - auto* rhinit2 = new TGeoCompositeShape(Form("rhinit2%d_D2_H%d", 0, half), partRohacellini2); - partRohacell = new TGeoVolume(Form("partRohacelli_D2_H%d_%d", half, ipart), rhinit2, mRohacell); + partRohacellini1 = new TGeoSubtraction( + rohacellGroove[iCount - 1], notchRohacell21, nullptr, tnotch21); + auto* rhinit1 = new TGeoCompositeShape( + Form("rhinit1%d_D2_H%d", 0, half), partRohacellini1); + partRohacellini2 = + new TGeoSubtraction(rhinit1, notchRohacell22, nullptr, tnotch22); + auto* rhinit2 = new TGeoCompositeShape( + Form("rhinit2%d_D2_H%d", 0, half), partRohacellini2); + partRohacell = new TGeoVolume( + Form("partRohacelli_D2_H%d_%d", half, ipart), rhinit2, mRohacell); } if (ipart < (mNPart[disk] - 1)) { - partRohacell = new TGeoVolume(Form("partRohacelli_D2_H%d_%d", half, ipart), rohacellGroove[iCount - 1], mRohacell); + partRohacell = + new TGeoVolume(Form("partRohacelli_D2_H%d_%d", half, ipart), + rohacellGroove[iCount - 1], mRohacell); } } @@ -2604,10 +3847,13 @@ void HeatExchanger::createHalfDisk2(Int_t half) rohacellPlate->AddNode(partRohacell, ipart, t); ty += mSupportYDimensions[disk][ipart] / 2.; - //========== insert to locate the rohacell plate compare to the disk support ============= + //========== insert to locate the rohacell plate compare to the disk support + //============= if (ipart == (mNPart[disk] - 1)) { TGeoTranslation* tinsert2; - TGeoVolume* insert2 = gGeoManager->MakeBox(Form("insert2_H%d_%d", half, ipart), mPeek, 1.0, 0.40 / 2., mRohacellThickness); + TGeoVolume* insert2 = + gGeoManager->MakeBox(Form("insert2_H%d_%d", half, ipart), mPeek, 1.0, + 0.40 / 2., mRohacellThickness); Double_t ylocation = mSupportYDimensions[disk][0] + mHalfDiskGap - 0.80; for (Int_t ip = 1; ip < mNPart[disk]; ip++) { ylocation = ylocation + mSupportYDimensions[disk][ip]; @@ -2653,132 +3899,249 @@ void HeatExchanger::createHalfDisk3(Int_t half) TGeoRotation* rotation = nullptr; TGeoCombiTrans* transformation = nullptr; - // **************************************** Water part **************************************** - // ********************** Four parameters mLwater3, mRadius3, mAngle3, mLpartial3 ************* + // **************************************** Water part + // **************************************** + // ********************** Four parameters mLwater3, mRadius3, mAngle3, + // mLpartial3 ************* Double_t ivolume = 300; // offset chamber 3 Double_t mRadiusCentralTore[4]; Double_t xPos3[4]; Double_t yPos3[4]; for (Int_t itube = 0; itube < 4; itube++) { - TGeoVolume* waterTube1 = gGeoManager->MakeTube(Form("waterTube1%d_D3_H%d", itube, half), mWater, 0., mRWater, mLWater3[itube] / 2.); - translation = new TGeoTranslation(mXPosition3[itube] - mHalfDiskGap, 0., mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube] / 2.); + TGeoVolume* waterTube1 = + gGeoManager->MakeTube(Form("waterTube1%d_D3_H%d", itube, half), mWater, + 0., mRWater, mLWater3[itube] / 2.); + translation = new TGeoTranslation(mXPosition3[itube] - mHalfDiskGap, 0., + mSupportXDimensions[3][0] / 2. + + mMoreLength - mLWater3[itube] / 2.); cooling->AddNode(waterTube1, ivolume++, translation); - TGeoVolume* waterTorus1 = gGeoManager->MakeTorus(Form("waterTorus1%d_D3_H%d", itube, half), mWater, mRadius3[itube], 0., mRWater, 0., mAngle3[itube]); + TGeoVolume* waterTorus1 = gGeoManager->MakeTorus( + Form("waterTorus1%d_D3_H%d", itube, half), mWater, mRadius3[itube], 0., + mRWater, 0., mAngle3[itube]); rotation = new TGeoRotation("rotation", 180., -90., 0.); - transformation = new TGeoCombiTrans(mRadius3[itube] + mXPosition3[itube] - mHalfDiskGap, 0., mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube], rotation); + transformation = new TGeoCombiTrans( + mRadius3[itube] + mXPosition3[itube] - mHalfDiskGap, 0., + mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube], + rotation); cooling->AddNode(waterTorus1, ivolume++, transformation); - TGeoVolume* waterTube2 = gGeoManager->MakeTube(Form("waterTube2%d_D3_H%d", itube, half), mWater, 0., mRWater, mLpartial3[itube] / 2.); + TGeoVolume* waterTube2 = + gGeoManager->MakeTube(Form("waterTube2%d_D3_H%d", itube, half), mWater, + 0., mRWater, mLpartial3[itube] / 2.); rotation = new TGeoRotation("rotation", 90., 180 - mAngle3[itube], 0.); - xPos3[itube] = mLWater3[itube] + mRadius3[itube] * TMath::Sin(mAngle3[itube] * TMath::DegToRad()) + mLpartial3[itube] / 2 * TMath::Cos(mAngle3[itube] * TMath::DegToRad()); - yPos3[itube] = mXPosition3[itube] - mHalfDiskGap + mRadius3[itube] * (1 - TMath::Cos(mAngle3[itube] * TMath::DegToRad())) + mLpartial3[itube] / 2 * TMath::Sin(mAngle3[itube] * TMath::DegToRad()); - transformation = new TGeoCombiTrans(yPos3[itube], 0., mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[itube], rotation); + xPos3[itube] = + mLWater3[itube] + + mRadius3[itube] * TMath::Sin(mAngle3[itube] * TMath::DegToRad()) + + mLpartial3[itube] / 2 * TMath::Cos(mAngle3[itube] * TMath::DegToRad()); + yPos3[itube] = + mXPosition3[itube] - mHalfDiskGap + + mRadius3[itube] * (1 - TMath::Cos(mAngle3[itube] * TMath::DegToRad())) + + mLpartial3[itube] / 2 * TMath::Sin(mAngle3[itube] * TMath::DegToRad()); + transformation = new TGeoCombiTrans( + yPos3[itube], 0., + mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[itube], rotation); cooling->AddNode(waterTube2, ivolume++, transformation); - mRadiusCentralTore[itube] = (mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[itube] - mLpartial3[itube] / 2 * TMath::Cos(mAngle3[itube] * TMath::DegToRad())) / TMath::Sin(mAngle3[itube] * TMath::DegToRad()); - TGeoVolume* waterTorusCentral = gGeoManager->MakeTorus(Form("waterTorusCentral%d_D3_H%d", itube, half), mWater, mRadiusCentralTore[itube], 0., mRWater, - -mAngle3[itube], 2. * mAngle3[itube]); + mRadiusCentralTore[itube] = + (mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[itube] - + mLpartial3[itube] / 2 * + TMath::Cos(mAngle3[itube] * TMath::DegToRad())) / + TMath::Sin(mAngle3[itube] * TMath::DegToRad()); + TGeoVolume* waterTorusCentral = + gGeoManager->MakeTorus(Form("waterTorusCentral%d_D3_H%d", itube, half), + mWater, mRadiusCentralTore[itube], 0., mRWater, + -mAngle3[itube], 2. * mAngle3[itube]); rotation = new TGeoRotation("rotation", 0., 90., 0.); - transformation = new TGeoCombiTrans(yPos3[itube] + mLpartial3[itube] / 2 * TMath::Sin(mAngle3[itube] * TMath::DegToRad()) - mRadiusCentralTore[itube] * TMath::Cos(mAngle3[itube] * TMath::DegToRad()), 0., 0., rotation); + transformation = new TGeoCombiTrans( + yPos3[itube] + + mLpartial3[itube] / 2 * + TMath::Sin(mAngle3[itube] * TMath::DegToRad()) - + mRadiusCentralTore[itube] * + TMath::Cos(mAngle3[itube] * TMath::DegToRad()), + 0., 0., rotation); cooling->AddNode(waterTorusCentral, ivolume++, transformation); - TGeoVolume* waterTube3 = gGeoManager->MakeTube(Form("waterTube3%d_D3_H%d", 2, half), mWater, 0., mRWater, mLpartial3[itube] / 2.); + TGeoVolume* waterTube3 = + gGeoManager->MakeTube(Form("waterTube3%d_D3_H%d", 2, half), mWater, 0., + mRWater, mLpartial3[itube] / 2.); rotation = new TGeoRotation("rotation", -90., 0 - mAngle3[itube], 0.); - transformation = new TGeoCombiTrans(yPos3[itube], 0., -(mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[itube]), rotation); + transformation = new TGeoCombiTrans( + yPos3[itube], 0., + -(mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[itube]), + rotation); cooling->AddNode(waterTube3, ivolume++, transformation); - TGeoVolume* waterTorus2 = gGeoManager->MakeTorus(Form("waterTorus2%d_D3_H%d", itube, half), mWater, mRadius3[itube], 0., mRWater, 0., mAngle3[itube]); + TGeoVolume* waterTorus2 = gGeoManager->MakeTorus( + Form("waterTorus2%d_D3_H%d", itube, half), mWater, mRadius3[itube], 0., + mRWater, 0., mAngle3[itube]); rotation = new TGeoRotation("rotation", 180., 90., 0.); - transformation = new TGeoCombiTrans(mRadius3[itube] + mXPosition3[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube]), rotation); + transformation = new TGeoCombiTrans( + mRadius3[itube] + mXPosition3[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube]), + rotation); cooling->AddNode(waterTorus2, ivolume++, transformation); - TGeoVolume* waterTube4 = gGeoManager->MakeTube(Form("waterTube4%d_D3_H%d", itube, half), mWater, 0., mRWater, mLWater3[itube] / 2.); - translation = new TGeoTranslation(mXPosition3[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube] / 2.)); + TGeoVolume* waterTube4 = + gGeoManager->MakeTube(Form("waterTube4%d_D3_H%d", itube, half), mWater, + 0., mRWater, mLWater3[itube] / 2.); + translation = new TGeoTranslation( + mXPosition3[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube] / 2.)); cooling->AddNode(waterTube4, ivolume++, translation); } - // **************************************************** Tube part ************************************************ - // ****************************** Four parameters mLwater3, mRadius3, mAngle3, mLpartial3 ************************ + // **************************************************** Tube part + // ************************************************ + // ****************************** Four parameters mLwater3, mRadius3, mAngle3, + // mLpartial3 ************************ for (Int_t itube = 0; itube < 4; itube++) { - TGeoVolume* pipeTube1 = gGeoManager->MakeTube(Form("pipeTube1%d_D3_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLWater3[itube] / 2.); - translation = new TGeoTranslation(mXPosition3[itube] - mHalfDiskGap, 0., mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube] / 2.); + TGeoVolume* pipeTube1 = + gGeoManager->MakeTube(Form("pipeTube1%d_D3_H%d", itube, half), mPipe, + mRWater, mRWater + mDRPipe, mLWater3[itube] / 2.); + translation = new TGeoTranslation(mXPosition3[itube] - mHalfDiskGap, 0., + mSupportXDimensions[3][0] / 2. + + mMoreLength - mLWater3[itube] / 2.); cooling->AddNode(pipeTube1, ivolume++, translation); - TGeoVolume* pipeTorus1 = gGeoManager->MakeTorus(Form("pipeTorus1%d_D3_H%d", itube, half), mPipe, mRadius3[itube], mRWater, mRWater + mDRPipe, 0., mAngle3[itube]); + TGeoVolume* pipeTorus1 = gGeoManager->MakeTorus( + Form("pipeTorus1%d_D3_H%d", itube, half), mPipe, mRadius3[itube], + mRWater, mRWater + mDRPipe, 0., mAngle3[itube]); rotation = new TGeoRotation("rotation", 180., -90., 0.); - transformation = new TGeoCombiTrans(mRadius3[itube] + mXPosition3[itube] - mHalfDiskGap, 0., mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube], rotation); + transformation = new TGeoCombiTrans( + mRadius3[itube] + mXPosition3[itube] - mHalfDiskGap, 0., + mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube], + rotation); cooling->AddNode(pipeTorus1, ivolume++, transformation); - TGeoVolume* pipeTube2 = gGeoManager->MakeTube(Form("pipeTube2%d_D3_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLpartial3[itube] / 2.); + TGeoVolume* pipeTube2 = gGeoManager->MakeTube( + Form("pipeTube2%d_D3_H%d", itube, half), mPipe, mRWater, + mRWater + mDRPipe, mLpartial3[itube] / 2.); rotation = new TGeoRotation("rotation", 90., 180 - mAngle3[itube], 0.); - xPos3[itube] = mLWater3[itube] + mRadius3[itube] * TMath::Sin(mAngle3[itube] * TMath::DegToRad()) + mLpartial3[itube] / 2 * TMath::Cos(mAngle3[itube] * TMath::DegToRad()); - yPos3[itube] = mXPosition3[itube] - mHalfDiskGap + mRadius3[itube] * (1 - TMath::Cos(mAngle3[itube] * TMath::DegToRad())) + mLpartial3[itube] / 2 * TMath::Sin(mAngle3[itube] * TMath::DegToRad()); - transformation = new TGeoCombiTrans(yPos3[itube], 0., mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[itube], rotation); + xPos3[itube] = + mLWater3[itube] + + mRadius3[itube] * TMath::Sin(mAngle3[itube] * TMath::DegToRad()) + + mLpartial3[itube] / 2 * TMath::Cos(mAngle3[itube] * TMath::DegToRad()); + yPos3[itube] = + mXPosition3[itube] - mHalfDiskGap + + mRadius3[itube] * (1 - TMath::Cos(mAngle3[itube] * TMath::DegToRad())) + + mLpartial3[itube] / 2 * TMath::Sin(mAngle3[itube] * TMath::DegToRad()); + transformation = new TGeoCombiTrans( + yPos3[itube], 0., + mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[itube], rotation); cooling->AddNode(pipeTube2, ivolume++, transformation); - mRadiusCentralTore[itube] = (mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[itube] - mLpartial3[itube] / 2 * TMath::Cos(mAngle3[itube] * TMath::DegToRad())) / TMath::Sin(mAngle3[itube] * TMath::DegToRad()); - TGeoVolume* pipeTorusCentral = gGeoManager->MakeTorus(Form("pipeTorusCentral%d_D3_H%d", itube, half), mPipe, mRadiusCentralTore[itube], mRWater, mRWater + mDRPipe, - -mAngle3[itube], 2. * mAngle3[itube]); + mRadiusCentralTore[itube] = + (mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[itube] - + mLpartial3[itube] / 2 * + TMath::Cos(mAngle3[itube] * TMath::DegToRad())) / + TMath::Sin(mAngle3[itube] * TMath::DegToRad()); + TGeoVolume* pipeTorusCentral = gGeoManager->MakeTorus( + Form("pipeTorusCentral%d_D3_H%d", itube, half), mPipe, + mRadiusCentralTore[itube], mRWater, mRWater + mDRPipe, -mAngle3[itube], + 2. * mAngle3[itube]); rotation = new TGeoRotation("rotation", 0., 90., 0.); - transformation = new TGeoCombiTrans(yPos3[itube] + mLpartial3[itube] / 2 * TMath::Sin(mAngle3[itube] * TMath::DegToRad()) - mRadiusCentralTore[itube] * TMath::Cos(mAngle3[itube] * TMath::DegToRad()), 0., 0., rotation); + transformation = new TGeoCombiTrans( + yPos3[itube] + + mLpartial3[itube] / 2 * + TMath::Sin(mAngle3[itube] * TMath::DegToRad()) - + mRadiusCentralTore[itube] * + TMath::Cos(mAngle3[itube] * TMath::DegToRad()), + 0., 0., rotation); cooling->AddNode(pipeTorusCentral, ivolume++, transformation); - TGeoVolume* pipeTube3 = gGeoManager->MakeTube(Form("pipeTube3%d_D3_H%d", 2, half), mPipe, mRWater, mRWater + mDRPipe, mLpartial3[itube] / 2.); + TGeoVolume* pipeTube3 = gGeoManager->MakeTube( + Form("pipeTube3%d_D3_H%d", 2, half), mPipe, mRWater, mRWater + mDRPipe, + mLpartial3[itube] / 2.); rotation = new TGeoRotation("rotation", -90., 0 - mAngle3[itube], 0.); - transformation = new TGeoCombiTrans(yPos3[itube], 0., -(mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[itube]), rotation); + transformation = new TGeoCombiTrans( + yPos3[itube], 0., + -(mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[itube]), + rotation); cooling->AddNode(pipeTube3, ivolume++, transformation); - TGeoVolume* pipeTorus2 = gGeoManager->MakeTorus(Form("pipeTorus2%d_D3_H%d", itube, half), mPipe, mRadius3[itube], mRWater, mRWater + mDRPipe, 0., mAngle3[itube]); + TGeoVolume* pipeTorus2 = gGeoManager->MakeTorus( + Form("pipeTorus2%d_D3_H%d", itube, half), mPipe, mRadius3[itube], + mRWater, mRWater + mDRPipe, 0., mAngle3[itube]); rotation = new TGeoRotation("rotation", 180., 90., 0.); - transformation = new TGeoCombiTrans(mRadius3[itube] + mXPosition3[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube]), rotation); + transformation = new TGeoCombiTrans( + mRadius3[itube] + mXPosition3[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube]), + rotation); cooling->AddNode(pipeTorus2, ivolume++, transformation); - TGeoVolume* pipeTube4 = gGeoManager->MakeTube(Form("pipeTube4%d_D3_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLWater3[itube] / 2.); - translation = new TGeoTranslation(mXPosition3[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube] / 2.)); + TGeoVolume* pipeTube4 = + gGeoManager->MakeTube(Form("pipeTube4%d_D3_H%d", itube, half), mPipe, + mRWater, mRWater + mDRPipe, mLWater3[itube] / 2.); + translation = new TGeoTranslation( + mXPosition3[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[itube] / 2.)); cooling->AddNode(pipeTube4, ivolume++, translation); } // *********************************************************************************************** - Double_t deltaz = mHeatExchangerThickness - Geometry::sKaptonOnCarbonThickness * 4 - Geometry::sKaptonGlueThickness * 4 - 2 * mCarbonThickness; + Double_t deltaz = mHeatExchangerThickness - + Geometry::sKaptonOnCarbonThickness * 4 - + Geometry::sKaptonGlueThickness * 4 - 2 * mCarbonThickness; rotation = new TGeoRotation("rotation", -90., 90., 0.); - transformation = - new TGeoCombiTrans(0., 0., mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - 2 * Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - + 2 * Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(cooling, 3, transformation); - transformation = - new TGeoCombiTrans(0., 0., mZPlan[disk] - deltaz / 2. + mCarbonThickness + mRWater + mDRPipe + 2 * Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + mZPlan[disk] - deltaz / 2. + mCarbonThickness + mRWater + mDRPipe + + 2 * Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(cooling, 4, transformation); - // **************************************** Carbon Plates **************************************** + // **************************************** Carbon Plates + // **************************************** auto* carbonPlate = new TGeoVolumeAssembly(Form("carbonPlate_D3_H%d", half)); - auto* carbonBase3 = new TGeoBBox(Form("carbonBase3_D3_H%d", half), (mSupportXDimensions[disk][0]) / 2. + mMoreLength, - (mSupportYDimensions[disk][0]) / 2., mCarbonThickness); - auto* t31 = new TGeoTranslation("t31", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + + auto& mftBaseParam = MFTBaseParam::Instance(); + Double_t mReducedX = 0.; + if (mftBaseParam.buildAlignment) { + mReducedX = 0.6; + } + + auto* carbonBase3 = new TGeoBBox( + Form("carbonBase3_D3_H%d", half), + (mSupportXDimensions[disk][0]) / 2. + mMoreLength - mReducedX, + (mSupportYDimensions[disk][0]) / 2., mCarbonThickness); + auto* t31 = new TGeoTranslation( + "t31", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); t31->RegisterYourself(); auto* holeCarbon3 = - new TGeoTubeSeg(Form("holeCarbon3_D3_H%d", half), 0., mRMin[disk], mCarbonThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holeCarbon3_D3_H%d", half), 0., mRMin[disk], + mCarbonThickness + 0.000001, 0, 180.); auto* t32 = new TGeoTranslation("t32", 0., -mHalfDiskGap, 0.); t32->RegisterYourself(); auto* carbonhole3 = new TGeoSubtraction(carbonBase3, holeCarbon3, t31, t32); auto* cs3 = new TGeoCompositeShape(Form("Carbon3_D3_H%d", half), carbonhole3); - auto* carbonBaseWithHole3 = new TGeoVolume(Form("carbonBaseWithHole_D3_H%d", half), cs3, mCarbon); + auto* carbonBaseWithHole3 = + new TGeoVolume(Form("carbonBaseWithHole_D3_H%d", half), cs3, mCarbon); carbonBaseWithHole3->SetLineColor(kGray + 3); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - carbonPlate->AddNode(carbonBaseWithHole3, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + carbonPlate->AddNode(carbonBaseWithHole3, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t ty = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { ty += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partCarbon = - gGeoManager->MakeBox(Form("partCarbon_D3_H%d_%d", half, ipart), mCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., mCarbonThickness); + TGeoVolume* partCarbon = gGeoManager->MakeBox( + Form("partCarbon_D3_H%d_%d", half, ipart), mCarbon, + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., mCarbonThickness); partCarbon->SetLineColor(kGray + 3); auto* t = new TGeoTranslation("t", 0, ty + mHalfDiskGap, mZPlan[disk]); carbonPlate->AddNode(partCarbon, ipart, t); @@ -2791,36 +4154,53 @@ void HeatExchanger::createHalfDisk3(Int_t half) transformation = new TGeoCombiTrans(0., 0., -deltaz / 2., rotation); mHalfDisk->AddNode(carbonPlate, 4, transformation); - // **************************************** Glue Bwtween Carbon Plate and Rohacell Plate **************************************** + // **************************************** Glue Bwtween Carbon Plate and + // Rohacell Plate **************************************** TGeoMedium* mGlueRohacellCarbon = gGeoManager->GetMedium("MFT_Epoxy$"); - auto* glueRohacellCarbon = new TGeoVolumeAssembly(Form("glueRohacellCarbon_D0_H%d", half)); - auto* glueRohacellCarbonBase0 = new TGeoBBox(Form("glueRohacellCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2., - (mSupportYDimensions[disk][0]) / 2., Geometry::sGlueRohacellCarbonThickness); - - auto* translation_gluRC01 = new TGeoTranslation("translation_gluRC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* glueRohacellCarbon = + new TGeoVolumeAssembly(Form("glueRohacellCarbon_D0_H%d", half)); + auto* glueRohacellCarbonBase0 = + new TGeoBBox(Form("glueRohacellCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. - mReducedX, + (mSupportYDimensions[disk][0]) / 2., + Geometry::sGlueRohacellCarbonThickness); + + auto* translation_gluRC01 = new TGeoTranslation( + "translation_gluRC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_gluRC01->RegisterYourself(); - auto* translation_gluRC02 = new TGeoTranslation("translation_gluRC02", 0., -mHalfDiskGap, 0.); + auto* translation_gluRC02 = + new TGeoTranslation("translation_gluRC02", 0., -mHalfDiskGap, 0.); translation_gluRC02->RegisterYourself(); - auto* holeglueRohacellCarbon0 = - new TGeoTubeSeg(Form("holeglueRohacellCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sGlueRohacellCarbonThickness + 0.000001, 0, 180.); + auto* holeglueRohacellCarbon0 = new TGeoTubeSeg( + Form("holeglueRohacellCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sGlueRohacellCarbonThickness + 0.000001, 0, 180.); - auto* glueRohacellCarbonhole0 = new TGeoSubtraction(glueRohacellCarbonBase0, holeglueRohacellCarbon0, translation_gluRC01, translation_gluRC02); - auto* gRC0 = new TGeoCompositeShape(Form("glueRohacellCarbon0_D0_H%d", half), glueRohacellCarbonhole0); - auto* glueRohacellCarbonBaseWithHole0 = new TGeoVolume(Form("glueRohacellCarbonWithHole_D0_H%d", half), gRC0, mGlueRohacellCarbon); + auto* glueRohacellCarbonhole0 = + new TGeoSubtraction(glueRohacellCarbonBase0, holeglueRohacellCarbon0, + translation_gluRC01, translation_gluRC02); + auto* gRC0 = new TGeoCompositeShape(Form("glueRohacellCarbon0_D0_H%d", half), + glueRohacellCarbonhole0); + auto* glueRohacellCarbonBaseWithHole0 = + new TGeoVolume(Form("glueRohacellCarbonWithHole_D0_H%d", half), gRC0, + mGlueRohacellCarbon); glueRohacellCarbonBaseWithHole0->SetLineColor(kGreen); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - glueRohacellCarbon->AddNode(glueRohacellCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + glueRohacellCarbon->AddNode(glueRohacellCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyGRC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyGRC += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partGlueRohacellCarbon = - gGeoManager->MakeBox(Form("partGlueRohacellCarbon_D0_H%d_%d", half, ipart), mGlueRohacellCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sGlueRohacellCarbonThickness); + TGeoVolume* partGlueRohacellCarbon = gGeoManager->MakeBox( + Form("partGlueRohacellCarbon_D0_H%d_%d", half, ipart), + mGlueRohacellCarbon, mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., + Geometry::sGlueRohacellCarbonThickness); partGlueRohacellCarbon->SetLineColor(kGreen); auto* t = new TGeoTranslation("t", 0, tyGRC + mHalfDiskGap, mZPlan[disk]); glueRohacellCarbon->AddNode(partGlueRohacellCarbon, ipart, t); @@ -2828,41 +4208,62 @@ void HeatExchanger::createHalfDisk3(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(glueRohacellCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness), rotation); + transformation = new TGeoCombiTrans(0., 0., + -(deltaz / 2. - mCarbonThickness - + Geometry::sGlueRohacellCarbonThickness), + rotation); mHalfDisk->AddNode(glueRohacellCarbon, 4, transformation); - // **************************************** Kapton on Carbon Plate **************************************** + // **************************************** Kapton on Carbon Plate + // **************************************** TGeoMedium* mKaptonOnCarbon = gGeoManager->GetMedium("MFT_Kapton$"); - auto* kaptonOnCarbon = new TGeoVolumeAssembly(Form("kaptonOnCarbon_D0_H%d", half)); - auto* kaptonOnCarbonBase0 = new TGeoBBox(Form("kaptonOnCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2. + mMoreLength, - (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonOnCarbonThickness); - - auto* translation_KC01 = new TGeoTranslation("translation_KC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* kaptonOnCarbon = + new TGeoVolumeAssembly(Form("kaptonOnCarbon_D0_H%d", half)); + auto* kaptonOnCarbonBase0 = new TGeoBBox( + Form("kaptonOnCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. + mMoreLength - mReducedX, + (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonOnCarbonThickness); + + auto* translation_KC01 = new TGeoTranslation( + "translation_KC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_KC01->RegisterYourself(); - auto* translation_KC02 = new TGeoTranslation("translation_KC02", 0., -mHalfDiskGap, 0.); + auto* translation_KC02 = + new TGeoTranslation("translation_KC02", 0., -mHalfDiskGap, 0.); translation_KC02->RegisterYourself(); auto* holekaptonOnCarbon0 = - new TGeoTubeSeg(Form("holekaptonOnCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sKaptonOnCarbonThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holekaptonOnCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sKaptonOnCarbonThickness + 0.000001, 0, 180.); - auto* kaptonOnCarbonhole0 = new TGeoSubtraction(kaptonOnCarbonBase0, holekaptonOnCarbon0, translation_KC01, translation_KC02); - auto* KC0 = new TGeoCompositeShape(Form("kaptonOnCarbon_D0_H%d", half), kaptonOnCarbonhole0); - auto* kaptonOnCarbonBaseWithHole0 = new TGeoVolume(Form("kaptonOnCarbonWithHole_D0_H%d", half), KC0, mKaptonOnCarbon); + auto* kaptonOnCarbonhole0 = + new TGeoSubtraction(kaptonOnCarbonBase0, holekaptonOnCarbon0, + translation_KC01, translation_KC02); + auto* KC0 = new TGeoCompositeShape(Form("kaptonOnCarbon_D0_H%d", half), + kaptonOnCarbonhole0); + auto* kaptonOnCarbonBaseWithHole0 = new TGeoVolume( + Form("kaptonOnCarbonWithHole_D0_H%d", half), KC0, mKaptonOnCarbon); kaptonOnCarbonBaseWithHole0->SetLineColor(kMagenta); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - kaptonOnCarbon->AddNode(kaptonOnCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + kaptonOnCarbon->AddNode(kaptonOnCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyKC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyKC += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partkaptonOnCarbonBase = - gGeoManager->MakeBox(Form("partkaptonOnCarbon_D0_H%d_%d", half, ipart), mKaptonOnCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonOnCarbonThickness); + TGeoVolume* partkaptonOnCarbonBase = gGeoManager->MakeBox( + Form("partkaptonOnCarbon_D0_H%d_%d", half, ipart), mKaptonOnCarbon, + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., + Geometry::sKaptonOnCarbonThickness); partkaptonOnCarbonBase->SetLineColor(kMagenta); auto* t = new TGeoTranslation("t", 0, tyKC + mHalfDiskGap, mZPlan[disk]); kaptonOnCarbon->AddNode(partkaptonOnCarbonBase, ipart, t); @@ -2870,41 +4271,63 @@ void HeatExchanger::createHalfDisk3(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + Geometry::sKaptonGlueThickness * 2, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + + Geometry::sKaptonGlueThickness * 2, + rotation); mHalfDisk->AddNode(kaptonOnCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + Geometry::sKaptonGlueThickness * 2), rotation); + transformation = new TGeoCombiTrans( + 0., 0., + -(deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + + Geometry::sKaptonGlueThickness * 2), + rotation); mHalfDisk->AddNode(kaptonOnCarbon, 4, transformation); - // **************************************** Kapton glue on the carbon plate **************************************** + // **************************************** Kapton glue on the carbon plate + // **************************************** TGeoMedium* mGlueKaptonCarbon = gGeoManager->GetMedium("MFT_Epoxy$"); - auto* glueKaptonCarbon = new TGeoVolumeAssembly(Form("glueKaptonCarbon_D0_H%d", half)); - auto* glueKaptonCarbonBase0 = new TGeoBBox(Form("glueKaptonCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2., - (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonGlueThickness); - - auto* translation_gluKC01 = new TGeoTranslation("translation_gluKC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* glueKaptonCarbon = + new TGeoVolumeAssembly(Form("glueKaptonCarbon_D0_H%d", half)); + auto* glueKaptonCarbonBase0 = new TGeoBBox( + Form("glueKaptonCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. - mReducedX, + (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonGlueThickness); + + auto* translation_gluKC01 = new TGeoTranslation( + "translation_gluKC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_gluKC01->RegisterYourself(); - auto* translation_gluKC02 = new TGeoTranslation("translation_gluKC02", 0., -mHalfDiskGap, 0.); + auto* translation_gluKC02 = + new TGeoTranslation("translation_gluKC02", 0., -mHalfDiskGap, 0.); translation_gluKC02->RegisterYourself(); - auto* holeglueKaptonCarbon0 = - new TGeoTubeSeg(Form("holeglueKaptonCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sKaptonGlueThickness + 0.000001, 0, 180.); + auto* holeglueKaptonCarbon0 = new TGeoTubeSeg( + Form("holeglueKaptonCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sKaptonGlueThickness + 0.000001, 0, 180.); - auto* glueKaptonCarbonhole0 = new TGeoSubtraction(glueKaptonCarbonBase0, holeglueKaptonCarbon0, translation_gluKC01, translation_gluKC02); - auto* gKC0 = new TGeoCompositeShape(Form("glueKaptonCarbon0_D0_H%d", half), glueKaptonCarbonhole0); - auto* glueKaptonCarbonBaseWithHole0 = new TGeoVolume(Form("glueKaptonCarbonWithHole_D0_H%d", half), gKC0, mGlueKaptonCarbon); + auto* glueKaptonCarbonhole0 = + new TGeoSubtraction(glueKaptonCarbonBase0, holeglueKaptonCarbon0, + translation_gluKC01, translation_gluKC02); + auto* gKC0 = new TGeoCompositeShape(Form("glueKaptonCarbon0_D0_H%d", half), + glueKaptonCarbonhole0); + auto* glueKaptonCarbonBaseWithHole0 = new TGeoVolume( + Form("glueKaptonCarbonWithHole_D0_H%d", half), gKC0, mGlueKaptonCarbon); glueKaptonCarbonBaseWithHole0->SetLineColor(kGreen); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - glueKaptonCarbon->AddNode(glueKaptonCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + glueKaptonCarbon->AddNode(glueKaptonCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyGKC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyGKC += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partGlueKaptonCarbon = - gGeoManager->MakeBox(Form("partGlueKaptonCarbon_D0_H%d_%d", half, ipart), mGlueKaptonCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonGlueThickness); + TGeoVolume* partGlueKaptonCarbon = gGeoManager->MakeBox( + Form("partGlueKaptonCarbon_D0_H%d_%d", half, ipart), mGlueKaptonCarbon, + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonGlueThickness); partGlueKaptonCarbon->SetLineColor(kGreen); auto* t = new TGeoTranslation("t", 0, tyGKC + mHalfDiskGap, mZPlan[disk]); glueKaptonCarbon->AddNode(partGlueKaptonCarbon, ipart, t); @@ -2912,20 +4335,31 @@ void HeatExchanger::createHalfDisk3(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness, + rotation); mHalfDisk->AddNode(glueKaptonCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness), rotation); + transformation = new TGeoCombiTrans( + 0., 0., + -(deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness), + rotation); mHalfDisk->AddNode(glueKaptonCarbon, 4, transformation); - // **************************************** Rohacell Plate **************************************** - auto* rohacellPlate = new TGeoVolumeAssembly(Form("rohacellPlate_D3_H%d", half)); - auto* rohacellBase3 = new TGeoBBox(Form("rohacellBase3_D3_H%d", half), (mSupportXDimensions[disk][0]) / 2., (mSupportYDimensions[disk][0]) / 2., mRohacellThickness); + // **************************************** Rohacell Plate + // **************************************** + auto* rohacellPlate = + new TGeoVolumeAssembly(Form("rohacellPlate_D3_H%d", half)); + auto* rohacellBase3 = new TGeoBBox( + Form("rohacellBase3_D3_H%d", half), (mSupportXDimensions[disk][0]) / 2., + (mSupportYDimensions[disk][0]) / 2., mRohacellThickness); auto* holeRohacell3 = - new TGeoTubeSeg(Form("holeRohacell3_D3_H%d", half), 0., mRMin[disk], mRohacellThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holeRohacell3_D3_H%d", half), 0., mRMin[disk], + mRohacellThickness + 0.000001, 0, 180.); - // **************************************** GROOVES ************************************************* - // Creating grooves or not according to sGrooves + // **************************************** GROOVES + // ************************************************* Creating grooves or not + // according to sGrooves Double_t diameter = 0.21; // groove diameter Double_t epsilon = 0.06; // outside shift of the goove Int_t iCount = 0; @@ -2937,20 +4371,31 @@ void HeatExchanger::createHalfDisk3(Int_t half) TGeoCompositeShape* rohacellGroove[300]; for (Int_t igroove = 0; igroove < 4; igroove++) { - grooveTube[0][igroove] = new TGeoTube("linear", 0., diameter, mLWater3[igroove] / 2.); - grooveTorus[1][igroove] = new TGeoTorus("SideTorus", mRadius3[igroove], 0., diameter, 0., mAngle3[igroove]); - grooveTube[2][igroove] = new TGeoTube("tiltedLinear", 0., diameter, mLpartial3[igroove] / 2.); - grooveTorus[3][igroove] = new TGeoTorus("centralTorus", mRadiusCentralTore[igroove], 0., diameter, -mAngle3[igroove], 2. * mAngle3[igroove]); - grooveTube[4][igroove] = new TGeoTube("tiltedLinear", 0., diameter, mLpartial3[igroove] / 2.); - grooveTorus[5][igroove] = new TGeoTorus("SideTorus", mRadius3[igroove], 0., diameter, 0., mAngle3[igroove]); - grooveTube[6][igroove] = new TGeoTube("linear", 0., diameter, mLWater3[igroove] / 2.); + grooveTube[0][igroove] = + new TGeoTube("linear", 0., diameter, mLWater3[igroove] / 2.); + grooveTorus[1][igroove] = new TGeoTorus("SideTorus", mRadius3[igroove], 0., + diameter, 0., mAngle3[igroove]); + grooveTube[2][igroove] = + new TGeoTube("tiltedLinear", 0., diameter, mLpartial3[igroove] / 2.); + grooveTorus[3][igroove] = + new TGeoTorus("centralTorus", mRadiusCentralTore[igroove], 0., diameter, + -mAngle3[igroove], 2. * mAngle3[igroove]); + grooveTube[4][igroove] = + new TGeoTube("tiltedLinear", 0., diameter, mLpartial3[igroove] / 2.); + grooveTorus[5][igroove] = new TGeoTorus("SideTorus", mRadius3[igroove], 0., + diameter, 0., mAngle3[igroove]); + grooveTube[6][igroove] = + new TGeoTube("linear", 0., diameter, mLWater3[igroove] / 2.); } // Rotation matrix TGeoRotation* rotationLinear = new TGeoRotation("rotation", -90., 90., 0.); - TGeoRotation* rotationSideTorusL = new TGeoRotation("rotationSideTorusLeft", -90., 0., 0.); - TGeoRotation* rotationSideTorusR = new TGeoRotation("rotationSideTorusRight", 90., 180., 180.); - TGeoRotation* rotationCentralTorus = new TGeoRotation("rotationCentralTorus", 90., 0., 0.); + TGeoRotation* rotationSideTorusL = + new TGeoRotation("rotationSideTorusLeft", -90., 0., 0.); + TGeoRotation* rotationSideTorusR = + new TGeoRotation("rotationSideTorusRight", 90., 180., 180.); + TGeoRotation* rotationCentralTorus = + new TGeoRotation("rotationCentralTorus", 90., 0., 0.); TGeoRotation* rotationTiltedLinearR; TGeoRotation* rotationTiltedLinearL; @@ -2958,51 +4403,95 @@ void HeatExchanger::createHalfDisk3(Int_t half) if (Geometry::sGrooves == 1) { for (Int_t iface = 1; iface > -2; iface -= 2) { // front and rear for (Int_t igroove = 0; igroove < 4; igroove++) { // 4 grooves - mPosition[igroove] = mXPosition3[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap; + mPosition[igroove] = mXPosition3[igroove] - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap; for (Int_t ip = 0; ip < 7; ip++) { // each groove is made of 7 parts switch (ip) { case 0: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[igroove] / 2., mPosition[igroove], iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[3][0] / 2. + mMoreLength - + mLWater3[igroove] / 2., + mPosition[igroove], iface * (mRohacellThickness + epsilon), + rotationLinear); if (igroove == 0 && iface == 1) { - rohacellBaseGroove[0] = new TGeoSubtraction(rohacellBase3, grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); - rohacellGroove[0] = new TGeoCompositeShape(Form("rohacell3Groove%d_G%d_F%d_H%d", ip, igroove, iface, half), rohacellBaseGroove[0]); + rohacellBaseGroove[0] = + new TGeoSubtraction(rohacellBase3, grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); + rohacellGroove[0] = + new TGeoCompositeShape(Form("rohacell3Groove%d_G%d_F%d_H%d", + ip, igroove, iface, half), + rohacellBaseGroove[0]); }; break; case 1: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[igroove], mRadius3[igroove] + mXPosition3[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, iface * (mRohacellThickness + epsilon), rotationSideTorusR); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[3][0] / 2. + mMoreLength - + mLWater3[igroove], + mRadius3[igroove] + mXPosition3[igroove] - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationSideTorusR); break; case 2: // Linear tilted - rotationTiltedLinearR = new TGeoRotation("rotationTiltedLinearRight", 90. - mAngle3[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[igroove], yPos3[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); + rotationTiltedLinearR = new TGeoRotation( + "rotationTiltedLinearRight", 90. - mAngle3[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[igroove], + yPos3[igroove] - mSupportYDimensions[disk][0] / 2. - + mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); break; case 3: // Central Torus - transfo[ip][igroove] = new TGeoCombiTrans(0., yPos3[igroove] + mLpartial3[igroove] / 2 * TMath::Sin(mAngle3[igroove] * TMath::DegToRad()) - mRadiusCentralTore[igroove] * TMath::Cos(mAngle3[igroove] * TMath::DegToRad()) - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationCentralTorus); + transfo[ip][igroove] = new TGeoCombiTrans( + 0., + yPos3[igroove] + + mLpartial3[igroove] / 2 * + TMath::Sin(mAngle3[igroove] * TMath::DegToRad()) - + mRadiusCentralTore[igroove] * + TMath::Cos(mAngle3[igroove] * TMath::DegToRad()) - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationCentralTorus); break; case 4: // Linear tilted - rotationTiltedLinearL = new TGeoRotation("rotationTiltedLinearLeft", 90. + mAngle3[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[igroove]), yPos3[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); + rotationTiltedLinearL = new TGeoRotation( + "rotationTiltedLinearLeft", 90. + mAngle3[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[3][0] / 2. + mMoreLength - + xPos3[igroove]), + yPos3[igroove] - mSupportYDimensions[disk][0] / 2. - + mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); break; case 5: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[igroove]), mRadius3[igroove] + mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationSideTorusL); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[3][0] / 2. + mMoreLength - + mLWater3[igroove]), + mRadius3[igroove] + mPosition[igroove], + iface * (mRohacellThickness + epsilon), rotationSideTorusL); break; case 6: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[igroove] / 2.), mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[3][0] / 2. + mMoreLength - + mLWater3[igroove] / 2.), + mPosition[igroove], iface * (mRohacellThickness + epsilon), + rotationLinear); break; } if (!(ip == 0 && igroove == 0 && iface == 1)) { if (ip & 1) { - rohacellBaseGroove[iCount] = new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, + transfo[ip][igroove]); } else { - rohacellBaseGroove[iCount] = new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, + transfo[ip][igroove]); } - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell3Groove%d_G%d_F%d_H%d", iCount, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell3Groove%d_G%d_F%d_H%d", + iCount, igroove, iface, half), + rohacellBaseGroove[iCount]); } iCount++; } @@ -3016,15 +4505,19 @@ void HeatExchanger::createHalfDisk3(Int_t half) rohacellBase = new TGeoSubtraction(rohacellBase3, holeRohacell3, t31, t32); } if (Geometry::sGrooves == 1) { - rohacellBase = new TGeoSubtraction(rohacellGroove[iCount - 1], holeRohacell3, t31, t32); + rohacellBase = new TGeoSubtraction(rohacellGroove[iCount - 1], + holeRohacell3, t31, t32); } - auto* rh3 = new TGeoCompositeShape(Form("rohacellTore%d_D0_H%d", 0, half), rohacellBase); - auto* rohacellBaseWithHole = new TGeoVolume(Form("rohacellBaseWithHole_D3_H%d", half), rh3, mRohacell); + auto* rh3 = new TGeoCompositeShape(Form("rohacellTore%d_D0_H%d", 0, half), + rohacellBase); + auto* rohacellBaseWithHole = + new TGeoVolume(Form("rohacellBaseWithHole_D3_H%d", half), rh3, mRohacell); rohacellBaseWithHole->SetLineColor(kGray); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - rohacellPlate->AddNode(rohacellBaseWithHole, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + rohacellPlate->AddNode(rohacellBaseWithHole, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); ty = mSupportYDimensions[disk][0]; @@ -3036,74 +4529,128 @@ void HeatExchanger::createHalfDisk3(Int_t half) //=========================================================================================================== //=========================================================================================================== auto* partRohacell0 = - new TGeoBBox(Form("rohacellBase0_D3_H%d_%d", half, ipart), mSupportXDimensions[disk][ipart] / 2., + new TGeoBBox(Form("rohacellBase0_D3_H%d_%d", half, ipart), + mSupportXDimensions[disk][ipart] / 2., mSupportYDimensions[disk][ipart] / 2., mRohacellThickness); Double_t mShift; if (Geometry::sGrooves == 1) { - // **************** Creating grooves for the other parts of the rohacell plate ********************** + // **************** Creating grooves for the other parts of the rohacell + // plate ********************** for (Int_t iface = 1; iface > -2; iface -= 2) { // front and rear for (Int_t igroove = 0; igroove < 4; igroove++) { // 4 grooves if (ipart == 1) { - mPosition[ipart] = mXPosition3[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1]; + mPosition[ipart] = + mXPosition3[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1]; mShift = -mSupportYDimensions[disk][ipart - 1]; }; if (ipart == 2) { - mPosition[ipart] = mXPosition3[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2]; - mShift = -mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2]; + mPosition[ipart] = + mXPosition3[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2]; + mShift = -mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2]; }; if (ipart == 3) { - mPosition[ipart] = mXPosition3[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2] - mSupportYDimensions[disk][ipart - 3]; - mShift = -mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2] - mSupportYDimensions[disk][ipart - 3]; + mPosition[ipart] = + mXPosition3[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2] - + mSupportYDimensions[disk][ipart - 3]; + mShift = -mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2] - + mSupportYDimensions[disk][ipart - 3]; }; for (Int_t ip = 0; ip < 7; ip++) { // each groove is made of 7 parts switch (ip) { case 0: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[igroove] / 2., mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[3][0] / 2. + mMoreLength - + mLWater3[igroove] / 2., + mPosition[ipart], iface * (mRohacellThickness + epsilon), + rotationLinear); if (igroove == 0 && iface == 1) { - rohacellBaseGroove[iCount] = new TGeoSubtraction(partRohacell0, grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell3Groove%d_G%d_F%d_H%d", ip, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellBaseGroove[iCount] = + new TGeoSubtraction(partRohacell0, grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell3Groove%d_G%d_F%d_H%d", + ip, igroove, iface, half), + rohacellBaseGroove[iCount]); }; break; case 1: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[igroove], mPosition[ipart] + mRadius3[igroove], - iface * (mRohacellThickness + epsilon), rotationSideTorusR); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[3][0] / 2. + mMoreLength - + mLWater3[igroove], + mPosition[ipart] + mRadius3[igroove], + iface * (mRohacellThickness + epsilon), rotationSideTorusR); break; case 2: // Linear tilted - rotationTiltedLinearR = new TGeoRotation("rotationTiltedLinearRight", 90. - mAngle3[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[igroove], yPos3[igroove] + mShift - mHalfDiskGap - mSupportYDimensions[disk][ipart] / 2., iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); + rotationTiltedLinearR = new TGeoRotation( + "rotationTiltedLinearRight", 90. - mAngle3[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[igroove], + yPos3[igroove] + mShift - mHalfDiskGap - + mSupportYDimensions[disk][ipart] / 2., + iface * (mRohacellThickness + epsilon), + rotationTiltedLinearR); break; case 3: // Central Torus - transfo[ip][igroove] = new TGeoCombiTrans(0., mPosition[ipart] + yPos3[igroove] + mLpartial3[igroove] / 2 * TMath::Sin(mAngle3[igroove] * TMath::DegToRad()) - mRadiusCentralTore[igroove] * TMath::Cos(mAngle3[igroove] * TMath::DegToRad()) - mXPosition3[igroove], - iface * (mRohacellThickness + epsilon), rotationCentralTorus); + transfo[ip][igroove] = new TGeoCombiTrans( + 0., + mPosition[ipart] + yPos3[igroove] + + mLpartial3[igroove] / 2 * + TMath::Sin(mAngle3[igroove] * TMath::DegToRad()) - + mRadiusCentralTore[igroove] * + TMath::Cos(mAngle3[igroove] * TMath::DegToRad()) - + mXPosition3[igroove], + iface * (mRohacellThickness + epsilon), rotationCentralTorus); break; case 4: // Linear tilted - rotationTiltedLinearL = new TGeoRotation("rotationTiltedLinearLeft", 90. + mAngle3[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[3][0] / 2. + mMoreLength - xPos3[igroove]), yPos3[igroove] + mPosition[ipart] - mXPosition3[igroove], - iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); + rotationTiltedLinearL = new TGeoRotation( + "rotationTiltedLinearLeft", 90. + mAngle3[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[3][0] / 2. + mMoreLength - + xPos3[igroove]), + yPos3[igroove] + mPosition[ipart] - mXPosition3[igroove], + iface * (mRohacellThickness + epsilon), + rotationTiltedLinearL); break; case 5: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[igroove]), mRadius3[igroove] + mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationSideTorusL); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[3][0] / 2. + mMoreLength - + mLWater3[igroove]), + mRadius3[igroove] + mPosition[ipart], + iface * (mRohacellThickness + epsilon), rotationSideTorusL); break; case 6: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[3][0] / 2. + mMoreLength - mLWater3[igroove] / 2.), mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[3][0] / 2. + mMoreLength - + mLWater3[igroove] / 2.), + mPosition[ipart], iface * (mRohacellThickness + epsilon), + rotationLinear); break; } if (!(ip == 0 && igroove == 0 && iface == 1)) { if (ip & 1) { - rohacellBaseGroove[iCount] = - new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTorus[ip][igroove], + nullptr, transfo[ip][igroove]); } else { - rohacellBaseGroove[iCount] = - new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); } - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell3Groove%d_G%d_F%d_H%d", iCount, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell3Groove%d_G%d_F%d_H%d", + iCount, igroove, iface, half), + rohacellBaseGroove[iCount]); } iCount++; } @@ -3120,30 +4667,42 @@ void HeatExchanger::createHalfDisk3(Int_t half) xnotch = 2.05; // half width ynotch = 0.4; // full height if (ipart == (mNPart[disk] - 1)) { - notchRohacell0 = new TGeoBBox(Form("notchRohacell0_D3_H%d", half), xnotch, ynotch, mRohacellThickness + 0.000001); - tnotch0 = new TGeoTranslation("tnotch0", 0., mSupportYDimensions[disk][ipart] / 2., 0.); + notchRohacell0 = new TGeoBBox(Form("notchRohacell0_D3_H%d", half), xnotch, + ynotch, mRohacellThickness + 0.000001); + tnotch0 = new TGeoTranslation("tnotch0", 0., + mSupportYDimensions[disk][ipart] / 2., 0.); tnotch0->RegisterYourself(); } //============================================================= if (Geometry::sGrooves == 0) { if (ipart == (mNPart[disk] - 1)) { - partRohacellini = new TGeoSubtraction(partRohacell0, notchRohacell0, nullptr, tnotch0); - auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D3_H%d", 0, half), partRohacellini); - partRohacell = new TGeoVolume(Form("partRohacelli_D3_H%d_%d", half, ipart), rhinit, mRohacell); + partRohacellini = new TGeoSubtraction(partRohacell0, notchRohacell0, + nullptr, tnotch0); + auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D3_H%d", 0, half), + partRohacellini); + partRohacell = new TGeoVolume( + Form("partRohacelli_D3_H%d_%d", half, ipart), rhinit, mRohacell); } if (ipart < (mNPart[disk] - 1)) { - partRohacell = new TGeoVolume(Form("partRohacelli_D3_H%d_%d", half, ipart), partRohacell0, mRohacell); + partRohacell = + new TGeoVolume(Form("partRohacelli_D3_H%d_%d", half, ipart), + partRohacell0, mRohacell); } } if (Geometry::sGrooves == 1) { if (ipart == (mNPart[disk] - 1)) { - partRohacellini = new TGeoSubtraction(rohacellGroove[iCount - 1], notchRohacell0, nullptr, tnotch0); - auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D3_H%d", 0, half), partRohacellini); - partRohacell = new TGeoVolume(Form("partRohacelli_D3_H%d_%d", half, ipart), rhinit, mRohacell); + partRohacellini = new TGeoSubtraction(rohacellGroove[iCount - 1], + notchRohacell0, nullptr, tnotch0); + auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D3_H%d", 0, half), + partRohacellini); + partRohacell = new TGeoVolume( + Form("partRohacelli_D3_H%d_%d", half, ipart), rhinit, mRohacell); } if (ipart < (mNPart[disk] - 1)) { - partRohacell = new TGeoVolume(Form("partRohacelli_D3_H%d_%d", half, ipart), rohacellGroove[iCount - 1], mRohacell); + partRohacell = + new TGeoVolume(Form("partRohacelli_D3_H%d_%d", half, ipart), + rohacellGroove[iCount - 1], mRohacell); } } @@ -3152,11 +4711,15 @@ void HeatExchanger::createHalfDisk3(Int_t half) partRohacell->SetLineColor(kGray); rohacellPlate->AddNode(partRohacell, ipart, t); - //========== insert to locate the rohacell plate compare to the disk support ============= + //========== insert to locate the rohacell plate compare to the disk support + //============= if (ipart == (mNPart[disk] - 1)) { TGeoTranslation* tinsert3; - TGeoVolume* insert3 = gGeoManager->MakeBox(Form("insert3_H%d_%d", half, ipart), mPeek, 4.0 / 2., 0.44 / 2., mRohacellThickness); - Double_t ylocation = mSupportYDimensions[disk][0] + mHalfDiskGap + 0.44 / 2. - ynotch; + TGeoVolume* insert3 = + gGeoManager->MakeBox(Form("insert3_H%d_%d", half, ipart), mPeek, + 4.0 / 2., 0.44 / 2., mRohacellThickness); + Double_t ylocation = + mSupportYDimensions[disk][0] + mHalfDiskGap + 0.44 / 2. - ynotch; for (Int_t ip = 1; ip < mNPart[disk]; ip++) { ylocation = ylocation + mSupportYDimensions[disk][ip]; } @@ -3202,134 +4765,249 @@ void HeatExchanger::createHalfDisk4(Int_t half) TGeoRotation* rotation = nullptr; TGeoCombiTrans* transformation = nullptr; - // **************************************** Water part ****************************************** - // ********************* Four parameters mLwater4, mRadius4, mAngle4, mLpartial4 **************** + // **************************************** Water part + // ****************************************** + // ********************* Four parameters mLwater4, mRadius4, mAngle4, + // mLpartial4 **************** Double_t ivolume = 400; // offset chamber 4 Double_t mRadiusCentralTore[4]; Double_t xPos4[4]; Double_t yPos4[4]; for (Int_t itube = 0; itube < 4; itube++) { - TGeoVolume* waterTube1 = gGeoManager->MakeTube(Form("waterTube1%d_D4_H%d", itube, half), mWater, 0., mRWater, mLWater4[itube] / 2.); - translation = new TGeoTranslation(mXPosition4[itube] - mHalfDiskGap, 0., mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube] / 2.); + TGeoVolume* waterTube1 = + gGeoManager->MakeTube(Form("waterTube1%d_D4_H%d", itube, half), mWater, + 0., mRWater, mLWater4[itube] / 2.); + translation = new TGeoTranslation(mXPosition4[itube] - mHalfDiskGap, 0., + mSupportXDimensions[4][0] / 2. + + mMoreLength - mLWater4[itube] / 2.); cooling->AddNode(waterTube1, ivolume++, translation); - TGeoVolume* waterTorus1 = gGeoManager->MakeTorus(Form("waterTorus1%d_D4_H%d", itube, half), mWater, mRadius4[itube], 0., mRWater, 0., mAngle4[itube]); + TGeoVolume* waterTorus1 = gGeoManager->MakeTorus( + Form("waterTorus1%d_D4_H%d", itube, half), mWater, mRadius4[itube], 0., + mRWater, 0., mAngle4[itube]); rotation = new TGeoRotation("rotation", 180., -90., 0.); - transformation = new TGeoCombiTrans(mRadius4[itube] + mXPosition4[itube] - mHalfDiskGap, 0., mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube], rotation); + transformation = new TGeoCombiTrans( + mRadius4[itube] + mXPosition4[itube] - mHalfDiskGap, 0., + mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube], + rotation); // cooling->AddNode(waterTorus1, ivolume++, transformation); - TGeoVolume* waterTube2 = gGeoManager->MakeTube(Form("waterTube2%d_D4_H%d", itube, half), mWater, 0., mRWater, mLpartial4[itube] / 2.); + TGeoVolume* waterTube2 = + gGeoManager->MakeTube(Form("waterTube2%d_D4_H%d", itube, half), mWater, + 0., mRWater, mLpartial4[itube] / 2.); rotation = new TGeoRotation("rotation", 90., 180 - mAngle4[itube], 0.); - xPos4[itube] = mLWater4[itube] + mRadius4[itube] * TMath::Sin(mAngle4[itube] * TMath::DegToRad()) + mLpartial4[itube] / 2 * TMath::Cos(mAngle4[itube] * TMath::DegToRad()); - yPos4[itube] = mXPosition4[itube] - mHalfDiskGap + mRadius4[itube] * (1 - TMath::Cos(mAngle4[itube] * TMath::DegToRad())) + mLpartial4[itube] / 2 * TMath::Sin(mAngle4[itube] * TMath::DegToRad()); - transformation = new TGeoCombiTrans(yPos4[itube], 0., mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[itube], rotation); + xPos4[itube] = + mLWater4[itube] + + mRadius4[itube] * TMath::Sin(mAngle4[itube] * TMath::DegToRad()) + + mLpartial4[itube] / 2 * TMath::Cos(mAngle4[itube] * TMath::DegToRad()); + yPos4[itube] = + mXPosition4[itube] - mHalfDiskGap + + mRadius4[itube] * (1 - TMath::Cos(mAngle4[itube] * TMath::DegToRad())) + + mLpartial4[itube] / 2 * TMath::Sin(mAngle4[itube] * TMath::DegToRad()); + transformation = new TGeoCombiTrans( + yPos4[itube], 0., + mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[itube], rotation); cooling->AddNode(waterTube2, ivolume++, transformation); - mRadiusCentralTore[itube] = (mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[itube] - mLpartial4[itube] / 2 * TMath::Cos(mAngle4[itube] * TMath::DegToRad())) / TMath::Sin(mAngle4[itube] * TMath::DegToRad()); - TGeoVolume* waterTorusCentral = gGeoManager->MakeTorus(Form("waterTorusCentral%d_D4_H%d", itube, half), mWater, mRadiusCentralTore[itube], 0., - mRWater, -mAngle4[itube], 2. * mAngle4[itube]); + mRadiusCentralTore[itube] = + (mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[itube] - + mLpartial4[itube] / 2 * + TMath::Cos(mAngle4[itube] * TMath::DegToRad())) / + TMath::Sin(mAngle4[itube] * TMath::DegToRad()); + TGeoVolume* waterTorusCentral = + gGeoManager->MakeTorus(Form("waterTorusCentral%d_D4_H%d", itube, half), + mWater, mRadiusCentralTore[itube], 0., mRWater, + -mAngle4[itube], 2. * mAngle4[itube]); rotation = new TGeoRotation("rotation", 0., 90., 0.); - transformation = new TGeoCombiTrans(yPos4[itube] + mLpartial4[itube] / 2 * TMath::Sin(mAngle4[itube] * TMath::DegToRad()) - - mRadiusCentralTore[itube] * TMath::Cos(mAngle4[itube] * TMath::DegToRad()), - 0., 0., rotation); + transformation = new TGeoCombiTrans( + yPos4[itube] + + mLpartial4[itube] / 2 * + TMath::Sin(mAngle4[itube] * TMath::DegToRad()) - + mRadiusCentralTore[itube] * + TMath::Cos(mAngle4[itube] * TMath::DegToRad()), + 0., 0., rotation); cooling->AddNode(waterTorusCentral, ivolume++, transformation); - TGeoVolume* waterTube3 = gGeoManager->MakeTube(Form("waterTube3%d_D4_H%d", 2, half), mWater, 0., mRWater, mLpartial4[itube] / 2.); + TGeoVolume* waterTube3 = + gGeoManager->MakeTube(Form("waterTube3%d_D4_H%d", 2, half), mWater, 0., + mRWater, mLpartial4[itube] / 2.); rotation = new TGeoRotation("rotation", -90., 0 - mAngle4[itube], 0.); - transformation = new TGeoCombiTrans(yPos4[itube], 0., -(mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[itube]), rotation); + transformation = new TGeoCombiTrans( + yPos4[itube], 0., + -(mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[itube]), + rotation); cooling->AddNode(waterTube3, ivolume++, transformation); - TGeoVolume* waterTorus2 = gGeoManager->MakeTorus(Form("waterTorus2%d_D4_H%d", itube, half), mWater, mRadius4[itube], 0., mRWater, 0., mAngle4[itube]); + TGeoVolume* waterTorus2 = gGeoManager->MakeTorus( + Form("waterTorus2%d_D4_H%d", itube, half), mWater, mRadius4[itube], 0., + mRWater, 0., mAngle4[itube]); rotation = new TGeoRotation("rotation", 180., 90., 0.); - transformation = new TGeoCombiTrans(mRadius4[itube] + mXPosition4[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube]), rotation); + transformation = new TGeoCombiTrans( + mRadius4[itube] + mXPosition4[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube]), + rotation); cooling->AddNode(waterTorus2, ivolume++, transformation); - TGeoVolume* waterTube4 = gGeoManager->MakeTube(Form("waterTube4%d_D4_H%d", itube, half), mWater, 0., mRWater, mLWater4[itube] / 2.); - translation = new TGeoTranslation(mXPosition4[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube] / 2.)); + TGeoVolume* waterTube4 = + gGeoManager->MakeTube(Form("waterTube4%d_D4_H%d", itube, half), mWater, + 0., mRWater, mLWater4[itube] / 2.); + translation = new TGeoTranslation( + mXPosition4[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube] / 2.)); cooling->AddNode(waterTube4, ivolume++, translation); } - // **************************************** Tube part ******************************************* - // ********************* Four parameters mLwater4, mRadius4, mAngle4, mLpartial4 **************** + // **************************************** Tube part + // ******************************************* + // ********************* Four parameters mLwater4, mRadius4, mAngle4, + // mLpartial4 **************** for (Int_t itube = 0; itube < 4; itube++) { - TGeoVolume* pipeTube1 = gGeoManager->MakeTube(Form("pipeTube1%d_D4_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLWater4[itube] / 2.); - translation = new TGeoTranslation(mXPosition4[itube] - mHalfDiskGap, 0., mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube] / 2.); + TGeoVolume* pipeTube1 = + gGeoManager->MakeTube(Form("pipeTube1%d_D4_H%d", itube, half), mPipe, + mRWater, mRWater + mDRPipe, mLWater4[itube] / 2.); + translation = new TGeoTranslation(mXPosition4[itube] - mHalfDiskGap, 0., + mSupportXDimensions[4][0] / 2. + + mMoreLength - mLWater4[itube] / 2.); cooling->AddNode(pipeTube1, ivolume++, translation); - TGeoVolume* pipeTorus1 = gGeoManager->MakeTorus(Form("pipeTorus1%d_D4_H%d", itube, half), mPipe, mRadius4[itube], mRWater, mRWater + mDRPipe, 0., mAngle4[itube]); + TGeoVolume* pipeTorus1 = gGeoManager->MakeTorus( + Form("pipeTorus1%d_D4_H%d", itube, half), mPipe, mRadius4[itube], + mRWater, mRWater + mDRPipe, 0., mAngle4[itube]); rotation = new TGeoRotation("rotation", 180., -90., 0.); - transformation = new TGeoCombiTrans(mRadius4[itube] + mXPosition4[itube] - mHalfDiskGap, 0., mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube], rotation); + transformation = new TGeoCombiTrans( + mRadius4[itube] + mXPosition4[itube] - mHalfDiskGap, 0., + mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube], + rotation); cooling->AddNode(pipeTorus1, ivolume++, transformation); - TGeoVolume* pipeTube2 = gGeoManager->MakeTube(Form("pipeTube2%d_D4_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLpartial4[itube] / 2.); + TGeoVolume* pipeTube2 = gGeoManager->MakeTube( + Form("pipeTube2%d_D4_H%d", itube, half), mPipe, mRWater, + mRWater + mDRPipe, mLpartial4[itube] / 2.); rotation = new TGeoRotation("rotation", 90., 180 - mAngle4[itube], 0.); - xPos4[itube] = mLWater4[itube] + mRadius4[itube] * TMath::Sin(mAngle4[itube] * TMath::DegToRad()) + mLpartial4[itube] / 2 * TMath::Cos(mAngle4[itube] * TMath::DegToRad()); - yPos4[itube] = mXPosition4[itube] - mHalfDiskGap + mRadius4[itube] * (1 - TMath::Cos(mAngle4[itube] * TMath::DegToRad())) + mLpartial4[itube] / 2 * TMath::Sin(mAngle4[itube] * TMath::DegToRad()); - transformation = new TGeoCombiTrans(yPos4[itube], 0., mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[itube], rotation); + xPos4[itube] = + mLWater4[itube] + + mRadius4[itube] * TMath::Sin(mAngle4[itube] * TMath::DegToRad()) + + mLpartial4[itube] / 2 * TMath::Cos(mAngle4[itube] * TMath::DegToRad()); + yPos4[itube] = + mXPosition4[itube] - mHalfDiskGap + + mRadius4[itube] * (1 - TMath::Cos(mAngle4[itube] * TMath::DegToRad())) + + mLpartial4[itube] / 2 * TMath::Sin(mAngle4[itube] * TMath::DegToRad()); + transformation = new TGeoCombiTrans( + yPos4[itube], 0., + mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[itube], rotation); cooling->AddNode(pipeTube2, ivolume++, transformation); - mRadiusCentralTore[itube] = (mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[itube] - mLpartial4[itube] / 2 * TMath::Cos(mAngle4[itube] * TMath::DegToRad())) / TMath::Sin(mAngle4[itube] * TMath::DegToRad()); - TGeoVolume* pipeTorusCentral = gGeoManager->MakeTorus(Form("pipeTorusCentral%d_D4_H%d", itube, half), mPipe, mRadiusCentralTore[itube], mRWater, mRWater + mDRPipe, - -mAngle4[itube], 2. * mAngle4[itube]); + mRadiusCentralTore[itube] = + (mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[itube] - + mLpartial4[itube] / 2 * + TMath::Cos(mAngle4[itube] * TMath::DegToRad())) / + TMath::Sin(mAngle4[itube] * TMath::DegToRad()); + TGeoVolume* pipeTorusCentral = gGeoManager->MakeTorus( + Form("pipeTorusCentral%d_D4_H%d", itube, half), mPipe, + mRadiusCentralTore[itube], mRWater, mRWater + mDRPipe, -mAngle4[itube], + 2. * mAngle4[itube]); rotation = new TGeoRotation("rotation", 0., 90., 0.); - transformation = new TGeoCombiTrans(yPos4[itube] + mLpartial4[itube] / 2 * TMath::Sin(mAngle4[itube] * TMath::DegToRad()) - mRadiusCentralTore[itube] * TMath::Cos(mAngle4[itube] * TMath::DegToRad()), 0., 0., rotation); + transformation = new TGeoCombiTrans( + yPos4[itube] + + mLpartial4[itube] / 2 * + TMath::Sin(mAngle4[itube] * TMath::DegToRad()) - + mRadiusCentralTore[itube] * + TMath::Cos(mAngle4[itube] * TMath::DegToRad()), + 0., 0., rotation); cooling->AddNode(pipeTorusCentral, ivolume++, transformation); - TGeoVolume* pipeTube3 = gGeoManager->MakeTube(Form("pipeTube3%d_D4_H%d", 2, half), mPipe, mRWater, mRWater + mDRPipe, mLpartial4[itube] / 2.); + TGeoVolume* pipeTube3 = gGeoManager->MakeTube( + Form("pipeTube3%d_D4_H%d", 2, half), mPipe, mRWater, mRWater + mDRPipe, + mLpartial4[itube] / 2.); rotation = new TGeoRotation("rotation", -90., 0 - mAngle4[itube], 0.); - transformation = new TGeoCombiTrans(yPos4[itube], 0., -(mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[itube]), rotation); + transformation = new TGeoCombiTrans( + yPos4[itube], 0., + -(mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[itube]), + rotation); cooling->AddNode(pipeTube3, ivolume++, transformation); - TGeoVolume* pipeTorus2 = gGeoManager->MakeTorus(Form("pipeTorus2%d_D4_H%d", itube, half), mPipe, mRadius4[itube], mRWater, mRWater + mDRPipe, 0., mAngle4[itube]); + TGeoVolume* pipeTorus2 = gGeoManager->MakeTorus( + Form("pipeTorus2%d_D4_H%d", itube, half), mPipe, mRadius4[itube], + mRWater, mRWater + mDRPipe, 0., mAngle4[itube]); rotation = new TGeoRotation("rotation", 180., 90., 0.); - transformation = new TGeoCombiTrans(mRadius4[itube] + mXPosition4[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube]), rotation); + transformation = new TGeoCombiTrans( + mRadius4[itube] + mXPosition4[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube]), + rotation); cooling->AddNode(pipeTorus2, ivolume++, transformation); - TGeoVolume* pipeTube4 = gGeoManager->MakeTube(Form("pipeTube4%d_D4_H%d", itube, half), mPipe, mRWater, mRWater + mDRPipe, mLWater4[itube] / 2.); - translation = new TGeoTranslation(mXPosition4[itube] - mHalfDiskGap, 0., -(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube] / 2.)); + TGeoVolume* pipeTube4 = + gGeoManager->MakeTube(Form("pipeTube4%d_D4_H%d", itube, half), mPipe, + mRWater, mRWater + mDRPipe, mLWater4[itube] / 2.); + translation = new TGeoTranslation( + mXPosition4[itube] - mHalfDiskGap, 0., + -(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[itube] / 2.)); cooling->AddNode(pipeTube4, ivolume++, translation); } // *********************************************************************************************** - Double_t deltaz = mHeatExchangerThickness - Geometry::sKaptonOnCarbonThickness * 4 - Geometry::sKaptonGlueThickness * 4 - 2 * mCarbonThickness; + Double_t deltaz = mHeatExchangerThickness - + Geometry::sKaptonOnCarbonThickness * 4 - + Geometry::sKaptonGlueThickness * 4 - 2 * mCarbonThickness; rotation = new TGeoRotation("rotation", -90., 90., 0.); - transformation = - new TGeoCombiTrans(0., 0., mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - 2 * Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + mZPlan[disk] + deltaz / 2. - mCarbonThickness - mRWater - mDRPipe - + 2 * Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(cooling, 3, transformation); - transformation = - new TGeoCombiTrans(0., 0., mZPlan[disk] - deltaz / 2. + mCarbonThickness + mRWater + mDRPipe + 2 * Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + mZPlan[disk] - deltaz / 2. + mCarbonThickness + mRWater + mDRPipe + + 2 * Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(cooling, 4, transformation); - // **************************************** Carbon Plates **************************************** + // **************************************** Carbon Plates + // **************************************** auto* carbonPlate = new TGeoVolumeAssembly(Form("carbonPlate_D4_H%d", half)); - auto* carbonBase4 = new TGeoBBox(Form("carbonBase4_D4_H%d", half), (mSupportXDimensions[disk][0]) / 2. + mMoreLength, - (mSupportYDimensions[disk][0]) / 2., mCarbonThickness); - auto* t41 = new TGeoTranslation("t41", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + + auto& mftBaseParam = MFTBaseParam::Instance(); + Double_t mReducedX = 0.; + if (mftBaseParam.buildAlignment) { + mReducedX = 0.6; + } + + auto* carbonBase4 = new TGeoBBox( + Form("carbonBase4_D4_H%d", half), + (mSupportXDimensions[disk][0]) / 2. + mMoreLength - mReducedX, + (mSupportYDimensions[disk][0]) / 2., mCarbonThickness); + auto* t41 = new TGeoTranslation( + "t41", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); t41->RegisterYourself(); auto* holeCarbon4 = - new TGeoTubeSeg(Form("holeCarbon4_D4_H%d", half), 0., mRMin[disk], mCarbonThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holeCarbon4_D4_H%d", half), 0., mRMin[disk], + mCarbonThickness + 0.000001, 0, 180.); auto* t42 = new TGeoTranslation("t42", 0., -mHalfDiskGap, 0.); t42->RegisterYourself(); auto* carbonhole4 = new TGeoSubtraction(carbonBase4, holeCarbon4, t41, t42); auto* cs4 = new TGeoCompositeShape(Form("Carbon4_D4_H%d", half), carbonhole4); - auto* carbonBaseWithHole4 = new TGeoVolume(Form("carbonBaseWithHole_D4_H%d", half), cs4, mCarbon); + auto* carbonBaseWithHole4 = + new TGeoVolume(Form("carbonBaseWithHole_D4_H%d", half), cs4, mCarbon); carbonBaseWithHole4->SetLineColor(kGray + 3); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - carbonPlate->AddNode(carbonBaseWithHole4, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + carbonPlate->AddNode(carbonBaseWithHole4, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t ty = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { ty += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partCarbon = - gGeoManager->MakeBox(Form("partCarbon_D4_H%d_%d", half, ipart), mCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., mCarbonThickness); + TGeoVolume* partCarbon = gGeoManager->MakeBox( + Form("partCarbon_D4_H%d_%d", half, ipart), mCarbon, + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., mCarbonThickness); partCarbon->SetLineColor(kGray + 3); auto* t = new TGeoTranslation("t", 0, ty + mHalfDiskGap, mZPlan[disk]); carbonPlate->AddNode(partCarbon, ipart, t); @@ -3342,36 +5020,53 @@ void HeatExchanger::createHalfDisk4(Int_t half) transformation = new TGeoCombiTrans(0., 0., -deltaz / 2., rotation); mHalfDisk->AddNode(carbonPlate, 4, transformation); - // **************************************** Glue Bwtween Carbon Plate and Rohacell Plate **************************************** + // **************************************** Glue Bwtween Carbon Plate and + // Rohacell Plate **************************************** TGeoMedium* mGlueRohacellCarbon = gGeoManager->GetMedium("MFT_Epoxy$"); - auto* glueRohacellCarbon = new TGeoVolumeAssembly(Form("glueRohacellCarbon_D0_H%d", half)); - auto* glueRohacellCarbonBase0 = new TGeoBBox(Form("glueRohacellCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2., - (mSupportYDimensions[disk][0]) / 2., Geometry::sGlueRohacellCarbonThickness); - - auto* translation_gluRC01 = new TGeoTranslation("translation_gluRC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* glueRohacellCarbon = + new TGeoVolumeAssembly(Form("glueRohacellCarbon_D0_H%d", half)); + auto* glueRohacellCarbonBase0 = + new TGeoBBox(Form("glueRohacellCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. - mReducedX, + (mSupportYDimensions[disk][0]) / 2., + Geometry::sGlueRohacellCarbonThickness); + + auto* translation_gluRC01 = new TGeoTranslation( + "translation_gluRC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_gluRC01->RegisterYourself(); - auto* translation_gluRC02 = new TGeoTranslation("translation_gluRC02", 0., -mHalfDiskGap, 0.); + auto* translation_gluRC02 = + new TGeoTranslation("translation_gluRC02", 0., -mHalfDiskGap, 0.); translation_gluRC02->RegisterYourself(); - auto* holeglueRohacellCarbon0 = - new TGeoTubeSeg(Form("holeglueRohacellCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sGlueRohacellCarbonThickness + 0.000001, 0, 180.); + auto* holeglueRohacellCarbon0 = new TGeoTubeSeg( + Form("holeglueRohacellCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sGlueRohacellCarbonThickness + 0.000001, 0, 180.); - auto* glueRohacellCarbonhole0 = new TGeoSubtraction(glueRohacellCarbonBase0, holeglueRohacellCarbon0, translation_gluRC01, translation_gluRC02); - auto* gRC0 = new TGeoCompositeShape(Form("glueRohacellCarbon0_D0_H%d", half), glueRohacellCarbonhole0); - auto* glueRohacellCarbonBaseWithHole0 = new TGeoVolume(Form("glueRohacellCarbonWithHole_D0_H%d", half), gRC0, mGlueRohacellCarbon); + auto* glueRohacellCarbonhole0 = + new TGeoSubtraction(glueRohacellCarbonBase0, holeglueRohacellCarbon0, + translation_gluRC01, translation_gluRC02); + auto* gRC0 = new TGeoCompositeShape(Form("glueRohacellCarbon0_D0_H%d", half), + glueRohacellCarbonhole0); + auto* glueRohacellCarbonBaseWithHole0 = + new TGeoVolume(Form("glueRohacellCarbonWithHole_D0_H%d", half), gRC0, + mGlueRohacellCarbon); glueRohacellCarbonBaseWithHole0->SetLineColor(kGreen); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - glueRohacellCarbon->AddNode(glueRohacellCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + glueRohacellCarbon->AddNode(glueRohacellCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyGRC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyGRC += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partGlueRohacellCarbon = - gGeoManager->MakeBox(Form("partGlueRohacellCarbon_D0_H%d_%d", half, ipart), mGlueRohacellCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sGlueRohacellCarbonThickness); + TGeoVolume* partGlueRohacellCarbon = gGeoManager->MakeBox( + Form("partGlueRohacellCarbon_D0_H%d_%d", half, ipart), + mGlueRohacellCarbon, mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., + Geometry::sGlueRohacellCarbonThickness); partGlueRohacellCarbon->SetLineColor(kGreen); auto* t = new TGeoTranslation("t", 0, tyGRC + mHalfDiskGap, mZPlan[disk]); glueRohacellCarbon->AddNode(partGlueRohacellCarbon, ipart, t); @@ -3379,41 +5074,62 @@ void HeatExchanger::createHalfDisk4(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness, + rotation); mHalfDisk->AddNode(glueRohacellCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2. - mCarbonThickness - Geometry::sGlueRohacellCarbonThickness), rotation); + transformation = new TGeoCombiTrans(0., 0., + -(deltaz / 2. - mCarbonThickness - + Geometry::sGlueRohacellCarbonThickness), + rotation); mHalfDisk->AddNode(glueRohacellCarbon, 4, transformation); - // **************************************** Kapton on Carbon Plate **************************************** + // **************************************** Kapton on Carbon Plate + // **************************************** TGeoMedium* mKaptonOnCarbon = gGeoManager->GetMedium("MFT_Kapton$"); - auto* kaptonOnCarbon = new TGeoVolumeAssembly(Form("kaptonOnCarbon_D0_H%d", half)); - auto* kaptonOnCarbonBase0 = new TGeoBBox(Form("kaptonOnCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2. + mMoreLength, - (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonOnCarbonThickness); - - auto* translation_KC01 = new TGeoTranslation("translation_KC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* kaptonOnCarbon = + new TGeoVolumeAssembly(Form("kaptonOnCarbon_D0_H%d", half)); + auto* kaptonOnCarbonBase0 = new TGeoBBox( + Form("kaptonOnCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. + mMoreLength - mReducedX, + (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonOnCarbonThickness); + + auto* translation_KC01 = new TGeoTranslation( + "translation_KC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_KC01->RegisterYourself(); - auto* translation_KC02 = new TGeoTranslation("translation_KC02", 0., -mHalfDiskGap, 0.); + auto* translation_KC02 = + new TGeoTranslation("translation_KC02", 0., -mHalfDiskGap, 0.); translation_KC02->RegisterYourself(); auto* holekaptonOnCarbon0 = - new TGeoTubeSeg(Form("holekaptonOnCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sKaptonOnCarbonThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holekaptonOnCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sKaptonOnCarbonThickness + 0.000001, 0, 180.); - auto* kaptonOnCarbonhole0 = new TGeoSubtraction(kaptonOnCarbonBase0, holekaptonOnCarbon0, translation_KC01, translation_KC02); - auto* KC0 = new TGeoCompositeShape(Form("kaptonOnCarbon_D0_H%d", half), kaptonOnCarbonhole0); - auto* kaptonOnCarbonBaseWithHole0 = new TGeoVolume(Form("kaptonOnCarbonWithHole_D0_H%d", half), KC0, mKaptonOnCarbon); + auto* kaptonOnCarbonhole0 = + new TGeoSubtraction(kaptonOnCarbonBase0, holekaptonOnCarbon0, + translation_KC01, translation_KC02); + auto* KC0 = new TGeoCompositeShape(Form("kaptonOnCarbon_D0_H%d", half), + kaptonOnCarbonhole0); + auto* kaptonOnCarbonBaseWithHole0 = new TGeoVolume( + Form("kaptonOnCarbonWithHole_D0_H%d", half), KC0, mKaptonOnCarbon); kaptonOnCarbonBaseWithHole0->SetLineColor(kMagenta); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - kaptonOnCarbon->AddNode(kaptonOnCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + kaptonOnCarbon->AddNode(kaptonOnCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyKC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyKC += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partkaptonOnCarbonBase = - gGeoManager->MakeBox(Form("partkaptonOnCarbon_D0_H%d_%d", half, ipart), mKaptonOnCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonOnCarbonThickness); + TGeoVolume* partkaptonOnCarbonBase = gGeoManager->MakeBox( + Form("partkaptonOnCarbon_D0_H%d_%d", half, ipart), mKaptonOnCarbon, + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., + Geometry::sKaptonOnCarbonThickness); partkaptonOnCarbonBase->SetLineColor(kMagenta); auto* t = new TGeoTranslation("t", 0, tyKC + mHalfDiskGap, mZPlan[disk]); kaptonOnCarbon->AddNode(partkaptonOnCarbonBase, ipart, t); @@ -3421,40 +5137,63 @@ void HeatExchanger::createHalfDisk4(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + Geometry::sKaptonGlueThickness * 2, rotation); + transformation = new TGeoCombiTrans( + 0., 0., + deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + + Geometry::sKaptonGlueThickness * 2, + rotation); mHalfDisk->AddNode(kaptonOnCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + Geometry::sKaptonGlueThickness * 2), rotation); + transformation = new TGeoCombiTrans( + 0., 0., + -(deltaz / 2 + Geometry::sKaptonOnCarbonThickness + mCarbonThickness + + Geometry::sKaptonGlueThickness * 2), + rotation); mHalfDisk->AddNode(kaptonOnCarbon, 4, transformation); - // **************************************** Kapton glue on the carbon plate **************************************** + // **************************************** Kapton glue on the carbon plate + // **************************************** TGeoMedium* mGlueKaptonCarbon = gGeoManager->GetMedium("MFT_Epoxy$"); - auto* glueKaptonCarbon = new TGeoVolumeAssembly(Form("glueKaptonCarbon_D0_H%d", half)); - auto* glueKaptonCarbonBase0 = new TGeoBBox(Form("glueKaptonCarbonBase0_D0_H%d", half), (mSupportXDimensions[disk][0]) / 2., (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonGlueThickness); - - auto* translation_gluKC01 = new TGeoTranslation("translation_gluKC01", 0., (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); + auto* glueKaptonCarbon = + new TGeoVolumeAssembly(Form("glueKaptonCarbon_D0_H%d", half)); + auto* glueKaptonCarbonBase0 = new TGeoBBox( + Form("glueKaptonCarbonBase0_D0_H%d", half), + (mSupportXDimensions[disk][0]) / 2. - mReducedX, + (mSupportYDimensions[disk][0]) / 2., Geometry::sKaptonGlueThickness); + + auto* translation_gluKC01 = new TGeoTranslation( + "translation_gluKC01", 0., + (mSupportYDimensions[disk][0]) / 2. + mHalfDiskGap, 0.); translation_gluKC01->RegisterYourself(); - auto* translation_gluKC02 = new TGeoTranslation("translation_gluKC02", 0., -mHalfDiskGap, 0.); + auto* translation_gluKC02 = + new TGeoTranslation("translation_gluKC02", 0., -mHalfDiskGap, 0.); translation_gluKC02->RegisterYourself(); - auto* holeglueKaptonCarbon0 = - new TGeoTubeSeg(Form("holeglueKaptonCarbon0_D0_H%d", half), 0., mRMin[disk], Geometry::sKaptonGlueThickness + 0.000001, 0, 180.); + auto* holeglueKaptonCarbon0 = new TGeoTubeSeg( + Form("holeglueKaptonCarbon0_D0_H%d", half), 0., mRMin[disk], + Geometry::sKaptonGlueThickness + 0.000001, 0, 180.); - auto* glueKaptonCarbonhole0 = new TGeoSubtraction(glueKaptonCarbonBase0, holeglueKaptonCarbon0, translation_gluKC01, translation_gluKC02); - auto* gKC0 = new TGeoCompositeShape(Form("glueKaptonCarbon0_D0_H%d", half), glueKaptonCarbonhole0); - auto* glueKaptonCarbonBaseWithHole0 = new TGeoVolume(Form("glueKaptonCarbonWithHole_D0_H%d", half), gKC0, mGlueKaptonCarbon); + auto* glueKaptonCarbonhole0 = + new TGeoSubtraction(glueKaptonCarbonBase0, holeglueKaptonCarbon0, + translation_gluKC01, translation_gluKC02); + auto* gKC0 = new TGeoCompositeShape(Form("glueKaptonCarbon0_D0_H%d", half), + glueKaptonCarbonhole0); + auto* glueKaptonCarbonBaseWithHole0 = new TGeoVolume( + Form("glueKaptonCarbonWithHole_D0_H%d", half), gKC0, mGlueKaptonCarbon); glueKaptonCarbonBaseWithHole0->SetLineColor(kGreen); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - glueKaptonCarbon->AddNode(glueKaptonCarbonBaseWithHole0, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + glueKaptonCarbon->AddNode(glueKaptonCarbonBaseWithHole0, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); Double_t tyGKC = mSupportYDimensions[disk][0]; for (Int_t ipart = 1; ipart < mNPart[disk]; ipart++) { tyGKC += mSupportYDimensions[disk][ipart] / 2.; - TGeoVolume* partGlueKaptonCarbon = - gGeoManager->MakeBox(Form("partGlueKaptonCarbon_D0_H%d_%d", half, ipart), mGlueKaptonCarbon, mSupportXDimensions[disk][ipart] / 2., - mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonGlueThickness); + TGeoVolume* partGlueKaptonCarbon = gGeoManager->MakeBox( + Form("partGlueKaptonCarbon_D0_H%d_%d", half, ipart), mGlueKaptonCarbon, + mSupportXDimensions[disk][ipart] / 2., + mSupportYDimensions[disk][ipart] / 2., Geometry::sKaptonGlueThickness); partGlueKaptonCarbon->SetLineColor(kGreen); auto* t = new TGeoTranslation("t", 0, tyGKC + mHalfDiskGap, mZPlan[disk]); glueKaptonCarbon->AddNode(partGlueKaptonCarbon, ipart, t); @@ -3462,19 +5201,29 @@ void HeatExchanger::createHalfDisk4(Int_t half) } rotation = new TGeoRotation("rotation", 180., 0., 0.); - transformation = new TGeoCombiTrans(0., 0., deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness, rotation); + transformation = new TGeoCombiTrans( + 0., 0., deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness, + rotation); mHalfDisk->AddNode(glueKaptonCarbon, 3, transformation); - transformation = new TGeoCombiTrans(0., 0., -(deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness), rotation); + transformation = new TGeoCombiTrans( + 0., 0., + -(deltaz / 2. + mCarbonThickness + Geometry::sKaptonGlueThickness), + rotation); mHalfDisk->AddNode(glueKaptonCarbon, 4, transformation); - // **************************************** Rohacell Plate **************************************** - auto* rohacellPlate = new TGeoVolumeAssembly(Form("rohacellPlate_D4_H%d", half)); - auto* rohacellBase4 = new TGeoBBox(Form("rohacellBase4_D4_H%d", half), (mSupportXDimensions[disk][0]) / 2., - (mSupportYDimensions[disk][0]) / 2., mRohacellThickness); + // **************************************** Rohacell Plate + // **************************************** + auto* rohacellPlate = + new TGeoVolumeAssembly(Form("rohacellPlate_D4_H%d", half)); + auto* rohacellBase4 = new TGeoBBox( + Form("rohacellBase4_D4_H%d", half), (mSupportXDimensions[disk][0]) / 2., + (mSupportYDimensions[disk][0]) / 2., mRohacellThickness); auto* holeRohacell4 = - new TGeoTubeSeg(Form("holeRohacell4_D4_H%d", half), 0., mRMin[disk], mRohacellThickness + 0.000001, 0, 180.); + new TGeoTubeSeg(Form("holeRohacell4_D4_H%d", half), 0., mRMin[disk], + mRohacellThickness + 0.000001, 0, 180.); - // *************************************** Grooves ************************************************* + // *************************************** Grooves + // ************************************************* Double_t diameter = 0.21; // groove diameter Double_t epsilon = 0.06; // outside shift of the goove Int_t iCount = 0; @@ -3487,20 +5236,31 @@ void HeatExchanger::createHalfDisk4(Int_t half) TGeoRotation* rotationTorus5[8]; for (Int_t igroove = 0; igroove < 4; igroove++) { - grooveTube[0][igroove] = new TGeoTube("linear", 0., diameter, mLWater4[igroove] / 2.); - grooveTorus[1][igroove] = new TGeoTorus("SideTorus", mRadius4[igroove], 0., diameter, 0., mAngle4[igroove]); - grooveTube[2][igroove] = new TGeoTube("tiltedLinear", 0., diameter, mLpartial4[igroove] / 2.); - grooveTorus[3][igroove] = new TGeoTorus("centralTorus", mRadiusCentralTore[igroove], 0., diameter, -mAngle4[igroove], 2. * mAngle4[igroove]); - grooveTube[4][igroove] = new TGeoTube("tiltedLinear", 0., diameter, mLpartial4[igroove] / 2.); - grooveTorus[5][igroove] = new TGeoTorus("SideTorus", mRadius4[igroove], 0., diameter, 0., mAngle4[igroove]); - grooveTube[6][igroove] = new TGeoTube("linear", 0., diameter, mLWater4[igroove] / 2.); + grooveTube[0][igroove] = + new TGeoTube("linear", 0., diameter, mLWater4[igroove] / 2.); + grooveTorus[1][igroove] = new TGeoTorus("SideTorus", mRadius4[igroove], 0., + diameter, 0., mAngle4[igroove]); + grooveTube[2][igroove] = + new TGeoTube("tiltedLinear", 0., diameter, mLpartial4[igroove] / 2.); + grooveTorus[3][igroove] = + new TGeoTorus("centralTorus", mRadiusCentralTore[igroove], 0., diameter, + -mAngle4[igroove], 2. * mAngle4[igroove]); + grooveTube[4][igroove] = + new TGeoTube("tiltedLinear", 0., diameter, mLpartial4[igroove] / 2.); + grooveTorus[5][igroove] = new TGeoTorus("SideTorus", mRadius4[igroove], 0., + diameter, 0., mAngle4[igroove]); + grooveTube[6][igroove] = + new TGeoTube("linear", 0., diameter, mLWater4[igroove] / 2.); } // Rotation matrix TGeoRotation* rotationLinear = new TGeoRotation("rotation", 90., 90., 0.); - TGeoRotation* rotationSideTorusL = new TGeoRotation("rotationSideTorusLeft", -90., 0., 0.); - TGeoRotation* rotationSideTorusR = new TGeoRotation("rotationSideTorusRight", 90., 180., 180.); - TGeoRotation* rotationCentralTorus = new TGeoRotation("rotationCentralTorus", 90., 0., 0.); + TGeoRotation* rotationSideTorusL = + new TGeoRotation("rotationSideTorusLeft", -90., 0., 0.); + TGeoRotation* rotationSideTorusR = + new TGeoRotation("rotationSideTorusRight", 90., 180., 180.); + TGeoRotation* rotationCentralTorus = + new TGeoRotation("rotationCentralTorus", 90., 0., 0.); TGeoRotation* rotationTiltedLinearR; TGeoRotation* rotationTiltedLinearL; @@ -3508,54 +5268,95 @@ void HeatExchanger::createHalfDisk4(Int_t half) if (Geometry::sGrooves == 1) { for (Int_t iface = 1; iface > -2; iface -= 2) { // front and rear for (Int_t igroove = 0; igroove < 4; igroove++) { // 4 grooves - mPosition[igroove] = mXPosition4[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap; + mPosition[igroove] = mXPosition4[igroove] - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap; for (Int_t ip = 0; ip < 7; ip++) { // each groove is made of 7 parts switch (ip) { case 0: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[igroove] / 2., mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[4][0] / 2. + mMoreLength - + mLWater4[igroove] / 2., + mPosition[igroove], iface * (mRohacellThickness + epsilon), + rotationLinear); if (igroove == 0 && iface == 1) { - rohacellBaseGroove[0] = new TGeoSubtraction(rohacellBase4, grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); - rohacellGroove[0] = new TGeoCompositeShape(Form("rohacell4Groove%d_G%d_F%d_H%d", ip, igroove, iface, half), rohacellBaseGroove[0]); + rohacellBaseGroove[0] = + new TGeoSubtraction(rohacellBase4, grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); + rohacellGroove[0] = + new TGeoCompositeShape(Form("rohacell4Groove%d_G%d_F%d_H%d", + ip, igroove, iface, half), + rohacellBaseGroove[0]); }; break; case 1: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[igroove], mRadius4[igroove] + mXPosition4[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, iface * (mRohacellThickness + epsilon), rotationSideTorusR); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[4][0] / 2. + mMoreLength - + mLWater4[igroove], + mRadius4[igroove] + mXPosition4[igroove] - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationSideTorusR); break; case 2: // Linear tilted - rotationTiltedLinearR = new TGeoRotation("rotationTiltedLinearRight", 90. - mAngle4[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[igroove], yPos4[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); + rotationTiltedLinearR = new TGeoRotation( + "rotationTiltedLinearRight", 90. - mAngle4[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[igroove], + yPos4[igroove] - mSupportYDimensions[disk][0] / 2. - + mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); break; case 3: // Central Torus - transfo[ip][igroove] = new TGeoCombiTrans(0., yPos4[igroove] + mLpartial4[igroove] / 2 * TMath::Sin(mAngle4[igroove] * TMath::DegToRad()) - mRadiusCentralTore[igroove] * TMath::Cos(mAngle4[igroove] * TMath::DegToRad()) - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationCentralTorus); + transfo[ip][igroove] = new TGeoCombiTrans( + 0., + yPos4[igroove] + + mLpartial4[igroove] / 2 * + TMath::Sin(mAngle4[igroove] * TMath::DegToRad()) - + mRadiusCentralTore[igroove] * + TMath::Cos(mAngle4[igroove] * TMath::DegToRad()) - + mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationCentralTorus); break; case 4: // Linear tilted - rotationTiltedLinearL = new TGeoRotation("rotationTiltedLinearLeft", 90. + mAngle4[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[igroove]), yPos4[igroove] - mSupportYDimensions[disk][0] / 2. - mHalfDiskGap, - iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); + rotationTiltedLinearL = new TGeoRotation( + "rotationTiltedLinearLeft", 90. + mAngle4[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[4][0] / 2. + mMoreLength - + xPos4[igroove]), + yPos4[igroove] - mSupportYDimensions[disk][0] / 2. - + mHalfDiskGap, + iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); break; case 5: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[igroove]), mRadius4[igroove] + mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationSideTorusL); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[4][0] / 2. + mMoreLength - + mLWater4[igroove]), + mRadius4[igroove] + mPosition[igroove], + iface * (mRohacellThickness + epsilon), rotationSideTorusL); break; case 6: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[igroove] / 2.), mPosition[igroove], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[4][0] / 2. + mMoreLength - + mLWater4[igroove] / 2.), + mPosition[igroove], iface * (mRohacellThickness + epsilon), + rotationLinear); break; } if (!(ip == 0 && igroove == 0 && iface == 1)) { if (ip & 1) { - rohacellBaseGroove[iCount] = - new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, + transfo[ip][igroove]); } else { - rohacellBaseGroove[iCount] = - new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, + transfo[ip][igroove]); } - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell4Groove%d_G%d_F%d_H%d", iCount, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell4Groove%d_G%d_F%d_H%d", + iCount, igroove, iface, half), + rohacellBaseGroove[iCount]); } iCount++; } @@ -3570,16 +5371,20 @@ void HeatExchanger::createHalfDisk4(Int_t half) rohacellBase = new TGeoSubtraction(rohacellBase4, holeRohacell4, t41, t42); } if (Geometry::sGrooves == 1) { - rohacellBase = new TGeoSubtraction(rohacellGroove[iCount - 1], holeRohacell4, t41, t42); + rohacellBase = new TGeoSubtraction(rohacellGroove[iCount - 1], + holeRohacell4, t41, t42); } - auto* rh4 = new TGeoCompositeShape(Form("rohacellTore%d_D4_H%d", 0, half), rohacellBase); - auto* rohacellBaseWithHole = new TGeoVolume(Form("rohacellBaseWithHole_D4_H%d", half), rh4, mRohacell); + auto* rh4 = new TGeoCompositeShape(Form("rohacellTore%d_D4_H%d", 0, half), + rohacellBase); + auto* rohacellBaseWithHole = + new TGeoVolume(Form("rohacellBaseWithHole_D4_H%d", half), rh4, mRohacell); TGeoVolume* partRohacell; rohacellBaseWithHole->SetLineColor(kGray); rotation = new TGeoRotation("rotation", 0., 0., 0.); transformation = new TGeoCombiTrans(0., 0., 0., rotation); - rohacellPlate->AddNode(rohacellBaseWithHole, 0, new TGeoTranslation(0., 0., mZPlan[disk])); + rohacellPlate->AddNode(rohacellBaseWithHole, 0, + new TGeoTranslation(0., 0., mZPlan[disk])); ty = mSupportYDimensions[disk][0]; @@ -3590,74 +5395,128 @@ void HeatExchanger::createHalfDisk4(Int_t half) //=========================================================================================================== //=========================================================================================================== auto* partRohacell0 = - new TGeoBBox(Form("rohacellBase0_D4_H%d_%d", half, ipart), mSupportXDimensions[disk][ipart] / 2., + new TGeoBBox(Form("rohacellBase0_D4_H%d_%d", half, ipart), + mSupportXDimensions[disk][ipart] / 2., mSupportYDimensions[disk][ipart] / 2., mRohacellThickness); Double_t mShift; if (Geometry::sGrooves == 1) { - // **************** Creating grooves for the other parts of the rohacell plate ********************** + // **************** Creating grooves for the other parts of the rohacell + // plate ********************** for (Int_t iface = 1; iface > -2; iface -= 2) { // front and rear for (Int_t igroove = 0; igroove < 4; igroove++) { // 4 grooves if (ipart == 1) { - mPosition[ipart] = mXPosition4[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1]; + mPosition[ipart] = + mXPosition4[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1]; mShift = -mSupportYDimensions[disk][ipart - 1]; }; if (ipart == 2) { - mPosition[ipart] = mXPosition4[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2]; - mShift = -mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2]; + mPosition[ipart] = + mXPosition4[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2]; + mShift = -mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2]; }; if (ipart == 3) { - mPosition[ipart] = mXPosition4[igroove] - mSupportYDimensions[disk][ipart] / 2. - mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2] - mSupportYDimensions[disk][ipart - 3]; - mShift = -mSupportYDimensions[disk][ipart - 1] - mSupportYDimensions[disk][ipart - 2] - mSupportYDimensions[disk][ipart - 3]; + mPosition[ipart] = + mXPosition4[igroove] - mSupportYDimensions[disk][ipart] / 2. - + mHalfDiskGap - mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2] - + mSupportYDimensions[disk][ipart - 3]; + mShift = -mSupportYDimensions[disk][ipart - 1] - + mSupportYDimensions[disk][ipart - 2] - + mSupportYDimensions[disk][ipart - 3]; }; for (Int_t ip = 0; ip < 7; ip++) { // each groove is made of 7 parts switch (ip) { case 0: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[igroove] / 2., mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[4][0] / 2. + mMoreLength - + mLWater4[igroove] / 2., + mPosition[ipart], iface * (mRohacellThickness + epsilon), + rotationLinear); if (igroove == 0 && iface == 1) { - rohacellBaseGroove[iCount] = new TGeoSubtraction(partRohacell0, grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell4Groove%d_G%d_F%d_H%d", ip, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellBaseGroove[iCount] = + new TGeoSubtraction(partRohacell0, grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell4Groove%d_G%d_F%d_H%d", + ip, igroove, iface, half), + rohacellBaseGroove[iCount]); }; break; case 1: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[igroove], mPosition[ipart] + mRadius4[igroove], - iface * (mRohacellThickness + epsilon), rotationSideTorusR); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[4][0] / 2. + mMoreLength - + mLWater4[igroove], + mPosition[ipart] + mRadius4[igroove], + iface * (mRohacellThickness + epsilon), rotationSideTorusR); break; case 2: // Linear tilted - rotationTiltedLinearR = new TGeoRotation("rotationTiltedLinearRight", 90. - mAngle4[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[igroove], yPos4[igroove] + mShift - mHalfDiskGap - mSupportYDimensions[disk][ipart] / 2., iface * (mRohacellThickness + epsilon), rotationTiltedLinearR); + rotationTiltedLinearR = new TGeoRotation( + "rotationTiltedLinearRight", 90. - mAngle4[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[igroove], + yPos4[igroove] + mShift - mHalfDiskGap - + mSupportYDimensions[disk][ipart] / 2., + iface * (mRohacellThickness + epsilon), + rotationTiltedLinearR); break; case 3: // Central Torus - transfo[ip][igroove] = new TGeoCombiTrans(0., mPosition[ipart] + yPos4[igroove] + mLpartial4[igroove] / 2 * TMath::Sin(mAngle4[igroove] * TMath::DegToRad()) - mRadiusCentralTore[igroove] * TMath::Cos(mAngle4[igroove] * TMath::DegToRad()) - mXPosition4[igroove], - iface * (mRohacellThickness + epsilon), rotationCentralTorus); + transfo[ip][igroove] = new TGeoCombiTrans( + 0., + mPosition[ipart] + yPos4[igroove] + + mLpartial4[igroove] / 2 * + TMath::Sin(mAngle4[igroove] * TMath::DegToRad()) - + mRadiusCentralTore[igroove] * + TMath::Cos(mAngle4[igroove] * TMath::DegToRad()) - + mXPosition4[igroove], + iface * (mRohacellThickness + epsilon), rotationCentralTorus); break; case 4: // Linear tilted - rotationTiltedLinearL = new TGeoRotation("rotationTiltedLinearLeft", 90. + mAngle4[igroove], 90., 0.); - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[4][0] / 2. + mMoreLength - xPos4[igroove]), yPos4[igroove] + mPosition[ipart] - mXPosition4[igroove], - iface * (mRohacellThickness + epsilon), rotationTiltedLinearL); + rotationTiltedLinearL = new TGeoRotation( + "rotationTiltedLinearLeft", 90. + mAngle4[igroove], 90., 0.); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[4][0] / 2. + mMoreLength - + xPos4[igroove]), + yPos4[igroove] + mPosition[ipart] - mXPosition4[igroove], + iface * (mRohacellThickness + epsilon), + rotationTiltedLinearL); break; case 5: // side torus - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[igroove]), mRadius4[igroove] + mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationSideTorusL); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[4][0] / 2. + mMoreLength - + mLWater4[igroove]), + mRadius4[igroove] + mPosition[ipart], + iface * (mRohacellThickness + epsilon), rotationSideTorusL); break; case 6: // Linear - transfo[ip][igroove] = new TGeoCombiTrans(-(mSupportXDimensions[4][0] / 2. + mMoreLength - mLWater4[igroove] / 2.), mPosition[ipart], - iface * (mRohacellThickness + epsilon), rotationLinear); + transfo[ip][igroove] = new TGeoCombiTrans( + -(mSupportXDimensions[4][0] / 2. + mMoreLength - + mLWater4[igroove] / 2.), + mPosition[ipart], iface * (mRohacellThickness + epsilon), + rotationLinear); break; } if (!(ip == 0 && igroove == 0 && iface == 1)) { if (ip & 1) { - rohacellBaseGroove[iCount] = - new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTorus[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTorus[ip][igroove], + nullptr, transfo[ip][igroove]); } else { - rohacellBaseGroove[iCount] = - new TGeoSubtraction(rohacellGroove[iCount - 1], grooveTube[ip][igroove], nullptr, transfo[ip][igroove]); + rohacellBaseGroove[iCount] = new TGeoSubtraction( + rohacellGroove[iCount - 1], grooveTube[ip][igroove], + nullptr, transfo[ip][igroove]); } - rohacellGroove[iCount] = new TGeoCompositeShape(Form("rohacell4Groove%d_G%d_F%d_H%d", iCount, igroove, iface, half), rohacellBaseGroove[iCount]); + rohacellGroove[iCount] = + new TGeoCompositeShape(Form("rohacell4Groove%d_G%d_F%d_H%d", + iCount, igroove, iface, half), + rohacellBaseGroove[iCount]); } iCount++; } @@ -3674,30 +5533,42 @@ void HeatExchanger::createHalfDisk4(Int_t half) xnotch = 2.1; // half width ynotch = 0.4; // full height if (ipart == (mNPart[disk] - 1)) { - notchRohacell0 = new TGeoBBox(Form("notchRohacell0_D4_H%d", half), xnotch, ynotch, mRohacellThickness + 0.000001); - tnotch0 = new TGeoTranslation("tnotch0", 0., mSupportYDimensions[disk][ipart] / 2., 0.); + notchRohacell0 = new TGeoBBox(Form("notchRohacell0_D4_H%d", half), xnotch, + ynotch, mRohacellThickness + 0.000001); + tnotch0 = new TGeoTranslation("tnotch0", 0., + mSupportYDimensions[disk][ipart] / 2., 0.); tnotch0->RegisterYourself(); } //============================================================= if (Geometry::sGrooves == 0) { if (ipart == (mNPart[disk] - 1)) { - partRohacellini = new TGeoSubtraction(partRohacell0, notchRohacell0, nullptr, tnotch0); - auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D4_H%d", 0, half), partRohacellini); - partRohacell = new TGeoVolume(Form("partRohacelli_D4_H%d_%d", half, ipart), rhinit, mRohacell); + partRohacellini = new TGeoSubtraction(partRohacell0, notchRohacell0, + nullptr, tnotch0); + auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D4_H%d", 0, half), + partRohacellini); + partRohacell = new TGeoVolume( + Form("partRohacelli_D4_H%d_%d", half, ipart), rhinit, mRohacell); } if (ipart < (mNPart[disk] - 1)) { - partRohacell = new TGeoVolume(Form("partRohacelli_D4_H%d_%d", half, ipart), partRohacell0, mRohacell); + partRohacell = + new TGeoVolume(Form("partRohacelli_D4_H%d_%d", half, ipart), + partRohacell0, mRohacell); } } if (Geometry::sGrooves == 1) { if (ipart == (mNPart[disk] - 1)) { - partRohacellini = new TGeoSubtraction(rohacellGroove[iCount - 1], notchRohacell0, nullptr, tnotch0); - auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D4_H%d", 0, half), partRohacellini); - partRohacell = new TGeoVolume(Form("partRohacelli_D4_H%d_%d", half, ipart), rhinit, mRohacell); + partRohacellini = new TGeoSubtraction(rohacellGroove[iCount - 1], + notchRohacell0, nullptr, tnotch0); + auto* rhinit = new TGeoCompositeShape(Form("rhinit%d_D4_H%d", 0, half), + partRohacellini); + partRohacell = new TGeoVolume( + Form("partRohacelli_D4_H%d_%d", half, ipart), rhinit, mRohacell); } if (ipart < (mNPart[disk] - 1)) { - partRohacell = new TGeoVolume(Form("partRohacelli_D4_H%d_%d", half, ipart), rohacellGroove[iCount - 1], mRohacell); + partRohacell = + new TGeoVolume(Form("partRohacelli_D4_H%d_%d", half, ipart), + rohacellGroove[iCount - 1], mRohacell); } } //=========================================================================================================== @@ -3705,11 +5576,15 @@ void HeatExchanger::createHalfDisk4(Int_t half) partRohacell->SetLineColor(kGray); rohacellPlate->AddNode(partRohacell, ipart, t); - //========== insert to locate the rohacell plate compare to the disk support ============= + //========== insert to locate the rohacell plate compare to the disk support + //============= if (ipart == (mNPart[disk] - 1)) { TGeoTranslation* tinsert4; - TGeoVolume* insert4 = gGeoManager->MakeBox(Form("insert4_H%d_%d", half, ipart), mPeek, 4.0 / 2., 0.44 / 2., mRohacellThickness); - Double_t ylocation = mSupportYDimensions[disk][0] + mHalfDiskGap + 0.44 / 2. - ynotch; + TGeoVolume* insert4 = + gGeoManager->MakeBox(Form("insert4_H%d_%d", half, ipart), mPeek, + 4.0 / 2., 0.44 / 2., mRohacellThickness); + Double_t ylocation = + mSupportYDimensions[disk][0] + mHalfDiskGap + 0.44 / 2. - ynotch; for (Int_t ip = 1; ip < mNPart[disk]; ip++) { ylocation = ylocation + mSupportYDimensions[disk][ip]; } @@ -3747,9 +5622,12 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) Float_t radius1; //----------------------------------------------------------------- if (disk == 0 || disk == 1 || disk == 2) { - auto* mCoolingPipe1 = new TGeoVolumeAssembly(Form("cooling_pipe1_H%d", half)); - auto* mCoolingPipeRear1 = new TGeoVolumeAssembly(Form("cooling_pipeRear1_H%d", half)); - auto* mCoolingPipeRear2 = new TGeoVolumeAssembly(Form("cooling_pipeRear2_H%d", half)); + auto* mCoolingPipe1 = + new TGeoVolumeAssembly(Form("cooling_pipe1_H%d", half)); + auto* mCoolingPipeRear1 = + new TGeoVolumeAssembly(Form("cooling_pipeRear1_H%d", half)); + auto* mCoolingPipeRear2 = + new TGeoVolumeAssembly(Form("cooling_pipeRear2_H%d", half)); if (disk == 0) { length1 = 1.5; } @@ -3759,14 +5637,18 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) if (disk == 2) { length1 = 0.5; } - Tube1 = gGeoManager->MakeTube(Form("Tube1_H%d_D%d", half, disk), mPipe, rin, rout, length1 / 2); - TubeW1 = gGeoManager->MakeTube(Form("TubeW1_H%d_D%d", half, disk), mWater, 0., rin, length1 / 2); + Tube1 = gGeoManager->MakeTube(Form("Tube1_H%d_D%d", half, disk), mPipe, rin, + rout, length1 / 2); + TubeW1 = gGeoManager->MakeTube(Form("TubeW1_H%d_D%d", half, disk), mWater, + 0., rin, length1 / 2); TGeoTranslation* tTube1 = new TGeoTranslation(0.0, 0.0, 0.0); tTube1->RegisterYourself(); radius1 = 0.4; - Torus1 = gGeoManager->MakeTorus(Form("Torus1_H%d_D%d", half, disk), mPipe, radius1, rin, rout, 0., 90.); - TorusW1 = gGeoManager->MakeTorus(Form("TorusW1_H%d_D%d", half, disk), mWater, radius1, 0., rin, 0., 90.); + Torus1 = gGeoManager->MakeTorus(Form("Torus1_H%d_D%d", half, disk), mPipe, + radius1, rin, rout, 0., 90.); + TorusW1 = gGeoManager->MakeTorus(Form("TorusW1_H%d_D%d", half, disk), + mWater, radius1, 0., rin, 0., 90.); rTorus1 = new TGeoRotation("rotationTorus1", 0.0, 90.0, 0.0); rTorus1->RegisterYourself(); transfoTorus1 = new TGeoCombiTrans(-radius1, 0., length1 / 2, rTorus1); @@ -3781,22 +5663,30 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) if (disk == 2) { length2 = 0.55; } - TGeoVolume* Tube2 = gGeoManager->MakeTube(Form("Tube2_H%d_D%d", half, disk), mPipe, rin, rout, length2 / 2); - TGeoVolume* TubeW2 = gGeoManager->MakeTube(Form("TubeW2_H%d_D%d", half, disk), mWater, 0., rin, length2 / 2); + TGeoVolume* Tube2 = gGeoManager->MakeTube(Form("Tube2_H%d_D%d", half, disk), + mPipe, rin, rout, length2 / 2); + TGeoVolume* TubeW2 = gGeoManager->MakeTube( + Form("TubeW2_H%d_D%d", half, disk), mWater, 0., rin, length2 / 2); TGeoRotation* rTube2 = new TGeoRotation("rotationTube2", 90.0, 90.0, 0.0); rTube2->RegisterYourself(); - TGeoCombiTrans* transfoTube2 = new TGeoCombiTrans(-length2 / 2 - radius1, 0., length1 / 2 + radius1, rTube2); + TGeoCombiTrans* transfoTube2 = new TGeoCombiTrans( + -length2 / 2 - radius1, 0., length1 / 2 + radius1, rTube2); transfoTube2->RegisterYourself(); Float_t radius2 = 4.; if (disk == 2) { radius2 = 3.5; } - TGeoVolume* Torus2 = gGeoManager->MakeTorus(Form("Torus2_H%d_D%d", half, disk), mPipe, radius2, rin, rout, 0., -90.); - TGeoVolume* TorusW2 = gGeoManager->MakeTorus(Form("TorusW2_H%d_D%d", half, disk), mWater, radius2, 0., rin, 0., -90.); + TGeoVolume* Torus2 = + gGeoManager->MakeTorus(Form("Torus2_H%d_D%d", half, disk), mPipe, + radius2, rin, rout, 0., -90.); + TGeoVolume* TorusW2 = + gGeoManager->MakeTorus(Form("TorusW2_H%d_D%d", half, disk), mWater, + radius2, 0., rin, 0., -90.); TGeoRotation* rTorus2 = new TGeoRotation("rotationTorus2", 180.0, 0.0, 0.0); rTorus2->RegisterYourself(); - TGeoCombiTrans* transfoTorus2 = new TGeoCombiTrans(-length2 - radius1, -radius2, length1 / 2 + radius1, rTorus2); + TGeoCombiTrans* transfoTorus2 = new TGeoCombiTrans( + -length2 - radius1, -radius2, length1 / 2 + radius1, rTorus2); transfoTorus2->RegisterYourself(); Float_t length3; @@ -3809,28 +5699,45 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) if (disk == 2) { length3 = 4.2; } - TGeoVolume* Tube3 = gGeoManager->MakeTube(Form("Tube3_H%d_D%d", half, disk), mPipe, rin, rout, length3 / 2); - TGeoVolume* TubeW3 = gGeoManager->MakeTube(Form("TubeW3_H%d_D%d", half, disk), mWater, 0., rin, length3 / 2); + TGeoVolume* Tube3 = gGeoManager->MakeTube(Form("Tube3_H%d_D%d", half, disk), + mPipe, rin, rout, length3 / 2); + TGeoVolume* TubeW3 = gGeoManager->MakeTube( + Form("TubeW3_H%d_D%d", half, disk), mWater, 0., rin, length3 / 2); TGeoRotation* rTube3 = new TGeoRotation("rotationTube3", 0.0, -90.0, 0.0); rTube3->RegisterYourself(); - TGeoCombiTrans* transfoTube3 = new TGeoCombiTrans(-length2 - radius2 - radius1, -radius2 - length3 / 2, length1 / 2 + radius1, rTube3); + TGeoCombiTrans* transfoTube3 = + new TGeoCombiTrans(-length2 - radius2 - radius1, -radius2 - length3 / 2, + length1 / 2 + radius1, rTube3); transfoTube3->RegisterYourself(); - Float_t length4 = 16.0; // one single pipe instead of 3 pipes coming from the 3 first disks + Float_t length4 = 16.0; // one single pipe instead of 3 pipes coming from + // the 3 first disks Float_t rin4 = 0.216; Float_t rout4 = 0.346; - TGeoVolume* Tube4 = gGeoManager->MakeTube(Form("Tube4_H%d_D%d", half, disk), mPipe, rin4, rout4, length4 / 2); - TGeoVolume* TubeW4 = gGeoManager->MakeTube(Form("TubeW4_H%d_D%d", half, disk), mWater, 0., rin4, length4 / 2); + TGeoVolume* Tube4 = gGeoManager->MakeTube(Form("Tube4_H%d_D%d", half, disk), + mPipe, rin4, rout4, length4 / 2); + TGeoVolume* TubeW4 = gGeoManager->MakeTube( + Form("TubeW4_H%d_D%d", half, disk), mWater, 0., rin4, length4 / 2); Float_t theta4 = 10.5; // horizontal plane angle Float_t phi4 = 35; // vertical plane angle - TGeoRotation* rTube4 = new TGeoRotation("rotationTube4", 90.0 + theta4, 90.0 + phi4, 0.0); + TGeoRotation* rTube4 = + new TGeoRotation("rotationTube4", 90.0 + theta4, 90.0 + phi4, 0.0); rTube4->RegisterYourself(); // next line, the x and z axis are reversed in the location... Float_t dx = 2.0; - Float_t xTube4 = length1 / 2. + radius1 + TMath::Cos(theta4 * TMath::DegToRad()) * TMath::Sin(phi4 * TMath::DegToRad()) * length4 / 2 * 0.8; - Float_t yTube4 = -radius2 - length3 - TMath::Sin(theta4 * TMath::DegToRad()) * length4 / 2 * 0.8; - Float_t zTube4 = -radius1 - length2 - radius2 - TMath::Cos(theta4 * TMath::DegToRad()) * TMath::Cos(phi4 * TMath::DegToRad()) * length4 / 2 * 0.8 - 0.2; - TGeoCombiTrans* transfoTube4 = new TGeoCombiTrans(zTube4, yTube4 - 0.2, xTube4 - 0.1, rTube4); + Float_t xTube4 = length1 / 2. + radius1 + + TMath::Cos(theta4 * TMath::DegToRad()) * + TMath::Sin(phi4 * TMath::DegToRad()) * length4 / 2 * + 0.8; + Float_t yTube4 = -radius2 - length3 - + TMath::Sin(theta4 * TMath::DegToRad()) * length4 / 2 * 0.8; + Float_t zTube4 = -radius1 - length2 - radius2 - + TMath::Cos(theta4 * TMath::DegToRad()) * + TMath::Cos(phi4 * TMath::DegToRad()) * length4 / 2 * + 0.8 - + 0.2; + TGeoCombiTrans* transfoTube4 = + new TGeoCombiTrans(zTube4, yTube4 - 0.2, xTube4 - 0.1, rTube4); transfoTube4->RegisterYourself(); Float_t length5 = 13.0; // one single pipe instead of 5 pipes @@ -3848,16 +5755,34 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) nhi[2] = TMath::Cos(theta); Float_t rin5 = 0.278; Float_t rout5 = 0.447; - TGeoVolume* Tube5 = gGeoManager->MakeCtub(Form("Tube5_H%d_D%d", half, disk), mPipe, rin5, rout5, length5 / 2, 0., 360., nlow[0], nlow[1], nlow[2], nhi[0], nhi[1], nhi[2]); - TGeoVolume* TubeW5 = gGeoManager->MakeCtub(Form("TubeW5_H%d_D%d", half, disk), mWater, 0., rin5, length5 / 2, 0., 360., nlow[0], nlow[1], nlow[2], nhi[0], nhi[1], nhi[2]); + TGeoVolume* Tube5 = gGeoManager->MakeCtub( + Form("Tube5_H%d_D%d", half, disk), mPipe, rin5, rout5, length5 / 2, 0., + 360., nlow[0], nlow[1], nlow[2], nhi[0], nhi[1], nhi[2]); + TGeoVolume* TubeW5 = gGeoManager->MakeCtub( + Form("TubeW5_H%d_D%d", half, disk), mWater, 0., rin5, length5 / 2, 0., + 360., nlow[0], nlow[1], nlow[2], nhi[0], nhi[1], nhi[2]); Float_t theta5 = 11.5; // angle from the "horizontal" plane x,z Float_t phi5 = 16.7; // "azimutal" angle - TGeoRotation* rTube5 = new TGeoRotation("rotationTube5", 90.0 + theta5, 90.0 + phi5, 0.0); + TGeoRotation* rTube5 = + new TGeoRotation("rotationTube5", 90.0 + theta5, 90.0 + phi5, 0.0); rTube5->RegisterYourself(); - Float_t xTube5 = xTube4 + TMath::Cos(theta4 * TMath::DegToRad()) * TMath::Sin(phi4 * TMath::DegToRad()) * length4 / 2 + TMath::Cos(theta5 * TMath::DegToRad()) * TMath::Sin(phi5 * TMath::DegToRad()) * length5 / 2 * 1.03; - Float_t yTube5 = yTube4 - TMath::Sin(theta4 * TMath::DegToRad()) * length4 / 2 - TMath::Sin(theta5 * TMath::DegToRad()) * length5 / 2 * 1.03 + 0.2; - Float_t zTube5 = zTube4 - TMath::Cos(theta4 * TMath::DegToRad()) * TMath::Cos(phi4 * TMath::DegToRad()) * length4 / 2 - TMath::Cos(theta5 * TMath::DegToRad()) * TMath::Cos(phi5 * TMath::DegToRad()) * length5 / 2 * 1.03; - TGeoCombiTrans* transfoTube5 = new TGeoCombiTrans(zTube5, yTube5, xTube5, rTube5); + Float_t xTube5 = xTube4 + + TMath::Cos(theta4 * TMath::DegToRad()) * + TMath::Sin(phi4 * TMath::DegToRad()) * length4 / 2 + + TMath::Cos(theta5 * TMath::DegToRad()) * + TMath::Sin(phi5 * TMath::DegToRad()) * length5 / 2 * + 1.03; + Float_t yTube5 = + yTube4 - TMath::Sin(theta4 * TMath::DegToRad()) * length4 / 2 - + TMath::Sin(theta5 * TMath::DegToRad()) * length5 / 2 * 1.03 + 0.2; + Float_t zTube5 = zTube4 - + TMath::Cos(theta4 * TMath::DegToRad()) * + TMath::Cos(phi4 * TMath::DegToRad()) * length4 / 2 - + TMath::Cos(theta5 * TMath::DegToRad()) * + TMath::Cos(phi5 * TMath::DegToRad()) * length5 / 2 * + 1.03; + TGeoCombiTrans* transfoTube5 = + new TGeoCombiTrans(zTube5, yTube5, xTube5, rTube5); transfoTube5->RegisterYourself(); Tube1->SetLineColor(kGray); @@ -3890,32 +5815,54 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) } //----------------------------------------------------------------- - auto* mCoolingPipe2 = new TGeoVolumeAssembly(Form("cooling_pipe2_H%d_D%d", half, disk)); - TGeoVolume* Tube1p = gGeoManager->MakeTube(Form("Tube1p_H%d_D%d", half, disk), mPipe, rin, rout, length1 / 2); - TGeoVolume* TubeW1p = gGeoManager->MakeTube(Form("TubeW1p_H%d_D%d", half, disk), mWater, 0., rin, length1 / 2); - - TGeoVolume* Torus1p = gGeoManager->MakeTorus(Form("Torus1p_H%d_D%d", half, disk), mPipe, radius1, rin, rout, 0., 90.); - TGeoVolume* TorusW1p = gGeoManager->MakeTorus(Form("TorusW1p_H%d_D%d", half, disk), mWater, radius1, 0., rin, 0., 90.); - - TGeoVolume* Tube2p = gGeoManager->MakeTube(Form("Tube2p_H%d_D%d", half, disk), mPipe, rin, rout, length2 / 2); - TGeoVolume* TubeW2p = gGeoManager->MakeTube(Form("TubeW2p_H%d_D%d", half, disk), mWater, 0., rin, length2 / 2); - - TGeoVolume* Torus2p = gGeoManager->MakeTorus(Form("Torus2p_H%d_D%d", half, disk), mPipe, radius2, rin, rout, 0., 90.); - TGeoVolume* TorusW2p = gGeoManager->MakeTorus(Form("TorusW2p_H%d_D%d", half, disk), mWater, radius2, 0., rin, 0., 90.); - - TGeoVolume* Tube3p = gGeoManager->MakeTube(Form("Tube3p_H%d_D%d", half, disk), mPipe, rin, rout, length3 / 2); - TGeoVolume* TubeW3p = gGeoManager->MakeTube(Form("TubeW3p_H%d_D%d", half, disk), mWater, 0., rin, length3 / 2); - - TGeoRotation* rTorus2p = new TGeoRotation("rotationTorus2p", 180.0, 0.0, 0.0); + auto* mCoolingPipe2 = + new TGeoVolumeAssembly(Form("cooling_pipe2_H%d_D%d", half, disk)); + TGeoVolume* Tube1p = gGeoManager->MakeTube( + Form("Tube1p_H%d_D%d", half, disk), mPipe, rin, rout, length1 / 2); + TGeoVolume* TubeW1p = gGeoManager->MakeTube( + Form("TubeW1p_H%d_D%d", half, disk), mWater, 0., rin, length1 / 2); + + TGeoVolume* Torus1p = + gGeoManager->MakeTorus(Form("Torus1p_H%d_D%d", half, disk), mPipe, + radius1, rin, rout, 0., 90.); + TGeoVolume* TorusW1p = + gGeoManager->MakeTorus(Form("TorusW1p_H%d_D%d", half, disk), mWater, + radius1, 0., rin, 0., 90.); + + TGeoVolume* Tube2p = gGeoManager->MakeTube( + Form("Tube2p_H%d_D%d", half, disk), mPipe, rin, rout, length2 / 2); + TGeoVolume* TubeW2p = gGeoManager->MakeTube( + Form("TubeW2p_H%d_D%d", half, disk), mWater, 0., rin, length2 / 2); + + TGeoVolume* Torus2p = + gGeoManager->MakeTorus(Form("Torus2p_H%d_D%d", half, disk), mPipe, + radius2, rin, rout, 0., 90.); + TGeoVolume* TorusW2p = + gGeoManager->MakeTorus(Form("TorusW2p_H%d_D%d", half, disk), mWater, + radius2, 0., rin, 0., 90.); + + TGeoVolume* Tube3p = gGeoManager->MakeTube( + Form("Tube3p_H%d_D%d", half, disk), mPipe, rin, rout, length3 / 2); + TGeoVolume* TubeW3p = gGeoManager->MakeTube( + Form("TubeW3p_H%d_D%d", half, disk), mWater, 0., rin, length3 / 2); + + TGeoRotation* rTorus2p = + new TGeoRotation("rotationTorus2p", 180.0, 0.0, 0.0); rTorus2p->RegisterYourself(); - TGeoCombiTrans* transfoTorus2p = new TGeoCombiTrans(-length2 - radius1, radius2, length1 / 2 + radius1, rTorus2p); + TGeoCombiTrans* transfoTorus2p = new TGeoCombiTrans( + -length2 - radius1, radius2, length1 / 2 + radius1, rTorus2p); transfoTorus2p->RegisterYourself(); - TGeoCombiTrans* transfoTube3p = new TGeoCombiTrans(-length2 - radius2 - radius1, radius2 + length3 / 2, length1 / 2 + radius1, rTube3); + TGeoCombiTrans* transfoTube3p = + new TGeoCombiTrans(-length2 - radius2 - radius1, radius2 + length3 / 2, + length1 / 2 + radius1, rTube3); transfoTube3p->RegisterYourself(); - TGeoRotation* rTube4p = new TGeoRotation(Form("rotationTube4p_H%d_D%d", half, disk), 90.0 - theta4, phi4 - 90.0, 0.0); + TGeoRotation* rTube4p = + new TGeoRotation(Form("rotationTube4p_H%d_D%d", half, disk), + 90.0 - theta4, phi4 - 90.0, 0.0); rTube4p->RegisterYourself(); - TGeoCombiTrans* transfoTube4p = new TGeoCombiTrans(zTube4, -yTube4 + 0.2, xTube4 - 0.1, rTube4p); + TGeoCombiTrans* transfoTube4p = + new TGeoCombiTrans(zTube4, -yTube4 + 0.2, xTube4 - 0.1, rTube4p); transfoTube4p->RegisterYourself(); Tube1p->SetLineColor(kGray); @@ -3938,8 +5885,10 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) if (disk == 0) { - TGeoVolume* Tube4p = gGeoManager->MakeTube(Form("Tube4p_H%d_D%d", half, disk), mPipe, rin4, rout4, length4 / 2); - TGeoVolume* TubeW4p = gGeoManager->MakeTube(Form("TubeW4p_H%d_D%d", half, disk), mWater, 0., rin4, length4 / 2); + TGeoVolume* Tube4p = gGeoManager->MakeTube( + Form("Tube4p_H%d_D%d", half, disk), mPipe, rin4, rout4, length4 / 2); + TGeoVolume* TubeW4p = gGeoManager->MakeTube( + Form("TubeW4p_H%d_D%d", half, disk), mWater, 0., rin4, length4 / 2); Tube4p->SetLineColor(kGray); TubeW4p->SetLineColor(kBlue); @@ -3955,9 +5904,14 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) nhi[0] = TMath::Sin(theta) * TMath::Cos(phi); nhi[1] = TMath::Sin(theta) * TMath::Sin(phi); nhi[2] = TMath::Cos(theta); - TGeoVolume* Tube5p = gGeoManager->MakeCtub(Form("Tube5p_H%d_D%d", half, disk), mPipe, rin5, rout5, length5 / 2, 0., 360., nlow[0], nlow[1], nlow[2], nhi[0], nhi[1], nhi[2]); - TGeoVolume* TubeW5p = gGeoManager->MakeCtub(Form("TubeW5p_H%d_D%d", half, disk), mWater, 0., rin5, length5 / 2, 0., 360., nlow[0], nlow[1], nlow[2], nhi[0], nhi[1], nhi[2]); - TGeoRotation* rTube5p = new TGeoRotation("rotationTube5p", -90.0 - theta5, -(90.0 + phi5), 0.0); + TGeoVolume* Tube5p = gGeoManager->MakeCtub( + Form("Tube5p_H%d_D%d", half, disk), mPipe, rin5, rout5, length5 / 2, + 0., 360., nlow[0], nlow[1], nlow[2], nhi[0], nhi[1], nhi[2]); + TGeoVolume* TubeW5p = gGeoManager->MakeCtub( + Form("TubeW5p_H%d_D%d", half, disk), mWater, 0., rin5, length5 / 2, + 0., 360., nlow[0], nlow[1], nlow[2], nhi[0], nhi[1], nhi[2]); + TGeoRotation* rTube5p = new TGeoRotation("rotationTube5p", -90.0 - theta5, + -(90.0 + phi5), 0.0); rTube5p->RegisterYourself(); TGeoCombiTrans* transfoTube5p; transfoTube5p = new TGeoCombiTrans(zTube5, -yTube5, xTube5, rTube5p); @@ -3975,15 +5929,19 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) TGeoRotation* rotation1 = new TGeoRotation("rotation1", 90., 90., 90.); rotation1->RegisterYourself(); // 0.75 = Y location from manifold line 836 - transfoCoolingPipe1 = new TGeoCombiTrans(13.8 + length1 / 2, 0.75, 0.0, rotation1); + transfoCoolingPipe1 = + new TGeoCombiTrans(13.8 + length1 / 2, 0.75, 0.0, rotation1); transfoCoolingPipe1->RegisterYourself(); - transfoCoolingPipeRear1 = new TGeoCombiTrans(13.8 + length1 / 2, 0.75, 0.0, rotation1); + transfoCoolingPipeRear1 = + new TGeoCombiTrans(13.8 + length1 / 2, 0.75, 0.0, rotation1); transfoCoolingPipeRear1->RegisterYourself(); TGeoRotation* rotation2 = new TGeoRotation("rotation2", 90., 90., 90.); rotation2->RegisterYourself(); - transfoCoolingPipe2 = new TGeoCombiTrans(13.8 + length1 / 2, -0.75, 0.0, rotation2); + transfoCoolingPipe2 = + new TGeoCombiTrans(13.8 + length1 / 2, -0.75, 0.0, rotation2); transfoCoolingPipe2->RegisterYourself(); - transfoCoolingPipeRear2 = new TGeoCombiTrans(13.8 + length1 / 2, -0.75, 0.0, rotation2); + transfoCoolingPipeRear2 = + new TGeoCombiTrans(13.8 + length1 / 2, -0.75, 0.0, rotation2); transfoCoolingPipeRear2->RegisterYourself(); mHalfDisk->AddNode(mCoolingPipe1, 1, transfoCoolingPipe1); mHalfDisk->AddNode(mCoolingPipeRear1, 1, transfoCoolingPipeRear1); @@ -3995,46 +5953,70 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) //================================================================= if (disk == 3) { // One diagonal side - auto* mCoolingPipe3 = new TGeoVolumeAssembly(Form("cooling_pipe3_H%d_D%d", half, disk)); + auto* mCoolingPipe3 = + new TGeoVolumeAssembly(Form("cooling_pipe3_H%d_D%d", half, disk)); Float_t length1_3 = 4.0; - TGeoVolume* Tube1_3 = gGeoManager->MakeTube(Form("Tube1_3_H%d_D%d", half, disk), mPipe, rin, rout, length1_3 / 2); - TGeoVolume* TubeW1_3 = gGeoManager->MakeTube(Form("TubeW1_3_H%d_D%d", half, disk), mWater, 0., rin, length1_3 / 2); + TGeoVolume* Tube1_3 = gGeoManager->MakeTube( + Form("Tube1_3_H%d_D%d", half, disk), mPipe, rin, rout, length1_3 / 2); + TGeoVolume* TubeW1_3 = gGeoManager->MakeTube( + Form("TubeW1_3_H%d_D%d", half, disk), mWater, 0., rin, length1_3 / 2); TGeoTranslation* tTube1_3 = new TGeoTranslation(0.0, 0.0, 0.0); tTube1_3->RegisterYourself(); Float_t radius1_3 = 0.4; - TGeoVolume* Torus1_3 = gGeoManager->MakeTorus(Form("Torus1_3_H%d_D%d", half, disk), mPipe, radius1_3, rin, rout, 0., 90.); - TGeoVolume* TorusW1_3 = gGeoManager->MakeTorus(Form("TorusW1_3_H%d_D%d", half, disk), mWater, radius1_3, 0., rin, 0., 90.); - TGeoRotation* rTorus1_3 = new TGeoRotation("rotationTorus1_3", 90.0, 90.0, 0.0); + TGeoVolume* Torus1_3 = + gGeoManager->MakeTorus(Form("Torus1_3_H%d_D%d", half, disk), mPipe, + radius1_3, rin, rout, 0., 90.); + TGeoVolume* TorusW1_3 = + gGeoManager->MakeTorus(Form("TorusW1_3_H%d_D%d", half, disk), mWater, + radius1_3, 0., rin, 0., 90.); + TGeoRotation* rTorus1_3 = + new TGeoRotation("rotationTorus1_3", 90.0, 90.0, 0.0); rTorus1_3->RegisterYourself(); - TGeoCombiTrans* transfoTorus1_3 = new TGeoCombiTrans(0.0, -radius1_3, length1_3 / 2, rTorus1_3); + TGeoCombiTrans* transfoTorus1_3 = + new TGeoCombiTrans(0.0, -radius1_3, length1_3 / 2, rTorus1_3); transfoTorus1_3->RegisterYourself(); Float_t length2_3; if (disk == 3) { length2_3 = 10.4; } - TGeoVolume* Tube2_3 = gGeoManager->MakeTube(Form("Tube2_3_H%d_D%d", half, disk), mPipe, rin, rout, length2_3 / 2); - TGeoVolume* TubeW2_3 = gGeoManager->MakeTube(Form("TubeW2_3_H%d_D%d", half, disk), mWater, 0., rin, length2_3 / 2); - TGeoRotation* rTube2_3 = new TGeoRotation("rotationTube2_3", 180.0, 90.0, 90.0); + TGeoVolume* Tube2_3 = gGeoManager->MakeTube( + Form("Tube2_3_H%d_D%d", half, disk), mPipe, rin, rout, length2_3 / 2); + TGeoVolume* TubeW2_3 = gGeoManager->MakeTube( + Form("TubeW2_3_H%d_D%d", half, disk), mWater, 0., rin, length2_3 / 2); + TGeoRotation* rTube2_3 = + new TGeoRotation("rotationTube2_3", 180.0, 90.0, 90.0); rTube2_3->RegisterYourself(); - TGeoCombiTrans* transfoTube2_3 = new TGeoCombiTrans(0., -length2_3 / 2 - radius1_3, length1_3 / 2 + radius1_3, rTube2_3); + TGeoCombiTrans* transfoTube2_3 = new TGeoCombiTrans( + 0., -length2_3 / 2 - radius1_3, length1_3 / 2 + radius1_3, rTube2_3); transfoTube2_3->RegisterYourself(); - TGeoVolume* Torus2_3 = gGeoManager->MakeTorus(Form("Torus2_3_H%d_D%d", half, disk), mPipe, radius1_3, rin, rout, 0., 90.); - TGeoVolume* TorusW2_3 = gGeoManager->MakeTorus(Form("TorusW2_3_H%d_D%d", half, disk), mWater, radius1_3, 0., rin, 0., 90.); - TGeoRotation* rTorus2_3 = new TGeoRotation("rotationTorus2_3", 90.0, 90.0, 180.0); + TGeoVolume* Torus2_3 = + gGeoManager->MakeTorus(Form("Torus2_3_H%d_D%d", half, disk), mPipe, + radius1_3, rin, rout, 0., 90.); + TGeoVolume* TorusW2_3 = + gGeoManager->MakeTorus(Form("TorusW2_3_H%d_D%d", half, disk), mWater, + radius1_3, 0., rin, 0., 90.); + TGeoRotation* rTorus2_3 = + new TGeoRotation("rotationTorus2_3", 90.0, 90.0, 180.0); rTorus2_3->RegisterYourself(); - TGeoCombiTrans* transfoTorus2_3 = new TGeoCombiTrans(0.0, -length2_3 - radius1_3, length1_3 / 2 + radius1_3 + radius1_3, rTorus2_3); + TGeoCombiTrans* transfoTorus2_3 = + new TGeoCombiTrans(0.0, -length2_3 - radius1_3, + length1_3 / 2 + radius1_3 + radius1_3, rTorus2_3); transfoTorus2_3->RegisterYourself(); Float_t length3_3; if (disk == 3) { length3_3 = 1.5; } - TGeoVolume* Tube3_3 = gGeoManager->MakeTube(Form("Tube3_3_H%d_D%d", half, disk), mPipe, rin, rout, length3_3 / 2); - TGeoVolume* TubeW3_3 = gGeoManager->MakeTube(Form("TubeW3_3_H%d_D%d", half, disk), mWater, 0., rin, length3_3 / 2); + TGeoVolume* Tube3_3 = gGeoManager->MakeTube( + Form("Tube3_3_H%d_D%d", half, disk), mPipe, rin, rout, length3_3 / 2); + TGeoVolume* TubeW3_3 = gGeoManager->MakeTube( + Form("TubeW3_3_H%d_D%d", half, disk), mWater, 0., rin, length3_3 / 2); TGeoRotation* rTube3_3 = new TGeoRotation("rotationTube3_3", 0.0, 0.0, 0.0); rTube3_3->RegisterYourself(); - TGeoCombiTrans* transfoTube3_3 = new TGeoCombiTrans(0., -length2_3 - radius1_3 - radius1_3, length1_3 / 2 + radius1_3 + radius1_3 + length3_3 / 2, rTube3_3); + TGeoCombiTrans* transfoTube3_3 = new TGeoCombiTrans( + 0., -length2_3 - radius1_3 - radius1_3, + length1_3 / 2 + radius1_3 + radius1_3 + length3_3 / 2, rTube3_3); transfoTube3_3->RegisterYourself(); Tube1_3->SetLineColor(kGray); @@ -4058,21 +6040,37 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) TGeoCombiTrans* transfoCoolingPipe3_3 = nullptr; TGeoRotation* rotation3_3 = new TGeoRotation("rotation3_3", 90., 90., 76.); rotation3_3->RegisterYourself(); - transfoCoolingPipe3_3 = new TGeoCombiTrans(17. + length1_3 / 2, 0.75, 0.0, rotation3_3); + transfoCoolingPipe3_3 = + new TGeoCombiTrans(17. + length1_3 / 2, 0.75, 0.0, rotation3_3); // ------------------Other diagonal side - auto* mCoolingPipe4 = new TGeoVolumeAssembly(Form("cooling_pipe4_H%d_D%d", half, disk)); - - TGeoVolume* Tube1p_3 = gGeoManager->MakeTube(Form("Tube1p_3_H%d_D%d", half, disk), mPipe, rin, rout, length1_3 / 2); - TGeoVolume* Torus1p_3 = gGeoManager->MakeTorus(Form("Torus1p_3_H%d_D%d", half, disk), mPipe, radius1_3, rin, rout, 0., 90.); - TGeoVolume* Tube2p_3 = gGeoManager->MakeTube(Form("Tube2p_3_H%d_D%d", half, disk), mPipe, rin, rout, length2_3 / 2); - TGeoVolume* Torus2p_3 = gGeoManager->MakeTorus(Form("Torus2p_3_H%d_D%d", half, disk), mPipe, radius1_3, rin, rout, 0., 90.); - TGeoVolume* Tube3p_3 = gGeoManager->MakeTube(Form("Tube3p_3_H%d_D%d", half, disk), mPipe, rin, rout, length3_3 / 2); - TGeoVolume* TubeW1p_3 = gGeoManager->MakeTube(Form("TubeW1p_3_H%d_D%d", half, disk), mWater, 0, rin, length1_3 / 2); - TGeoVolume* TorusW1p_3 = gGeoManager->MakeTorus(Form("TorusW1p_3_H%d_D%d", half, disk), mWater, radius1_3, 0., rin, 0., 90.); - TGeoVolume* TubeW2p_3 = gGeoManager->MakeTube(Form("TubeW2p_3_H%d_D%d", half, disk), mWater, 0., rin, length2_3 / 2); - TGeoVolume* TorusW2p_3 = gGeoManager->MakeTorus(Form("TorusW2p_3_H%d_D%d", half, disk), mWater, radius1_3, 0., rin, 0., 90.); - TGeoVolume* TubeW3p_3 = gGeoManager->MakeTube(Form("TubeW3p_3_H%d_D%d", half, disk), mWater, 0., rin, length3_3 / 2); + auto* mCoolingPipe4 = + new TGeoVolumeAssembly(Form("cooling_pipe4_H%d_D%d", half, disk)); + + TGeoVolume* Tube1p_3 = gGeoManager->MakeTube( + Form("Tube1p_3_H%d_D%d", half, disk), mPipe, rin, rout, length1_3 / 2); + TGeoVolume* Torus1p_3 = + gGeoManager->MakeTorus(Form("Torus1p_3_H%d_D%d", half, disk), mPipe, + radius1_3, rin, rout, 0., 90.); + TGeoVolume* Tube2p_3 = gGeoManager->MakeTube( + Form("Tube2p_3_H%d_D%d", half, disk), mPipe, rin, rout, length2_3 / 2); + TGeoVolume* Torus2p_3 = + gGeoManager->MakeTorus(Form("Torus2p_3_H%d_D%d", half, disk), mPipe, + radius1_3, rin, rout, 0., 90.); + TGeoVolume* Tube3p_3 = gGeoManager->MakeTube( + Form("Tube3p_3_H%d_D%d", half, disk), mPipe, rin, rout, length3_3 / 2); + TGeoVolume* TubeW1p_3 = gGeoManager->MakeTube( + Form("TubeW1p_3_H%d_D%d", half, disk), mWater, 0, rin, length1_3 / 2); + TGeoVolume* TorusW1p_3 = + gGeoManager->MakeTorus(Form("TorusW1p_3_H%d_D%d", half, disk), mWater, + radius1_3, 0., rin, 0., 90.); + TGeoVolume* TubeW2p_3 = gGeoManager->MakeTube( + Form("TubeW2p_3_H%d_D%d", half, disk), mWater, 0., rin, length2_3 / 2); + TGeoVolume* TorusW2p_3 = + gGeoManager->MakeTorus(Form("TorusW2p_3_H%d_D%d", half, disk), mWater, + radius1_3, 0., rin, 0., 90.); + TGeoVolume* TubeW3p_3 = gGeoManager->MakeTube( + Form("TubeW3p_3_H%d_D%d", half, disk), mWater, 0., rin, length3_3 / 2); Tube1p_3->SetLineColor(kGray); Torus1p_3->SetLineColor(kGray); @@ -4095,7 +6093,8 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) TGeoCombiTrans* transfoCoolingPipe4_3 = nullptr; TGeoRotation* rotation4_3 = new TGeoRotation("rotation4_3", 90., 90., -76.); rotation4_3->RegisterYourself(); - transfoCoolingPipe4_3 = new TGeoCombiTrans(17. + length1_3 / 2, -0.75, 0.0, rotation4_3); + transfoCoolingPipe4_3 = + new TGeoCombiTrans(17. + length1_3 / 2, -0.75, 0.0, rotation4_3); transfoCoolingPipe4_3->RegisterYourself(); mHalfDisk->AddNode(mCoolingPipe3, 1, transfoCoolingPipe3_3); @@ -4105,48 +6104,72 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) //================================================================= if (disk == 4) { // One diagonal side - auto* mCoolingPipe3 = new TGeoVolumeAssembly(Form("cooling_pipe3_H%d_D%d", half, disk)); + auto* mCoolingPipe3 = + new TGeoVolumeAssembly(Form("cooling_pipe3_H%d_D%d", half, disk)); Float_t length1_4 = 3.0; - TGeoVolume* Tube1_4 = gGeoManager->MakeTube(Form("Tube1_4_H%d_D%d", half, disk), mPipe, rin, rout, length1_4 / 2); - TGeoVolume* TubeW1_4 = gGeoManager->MakeTube(Form("TubeW1_4_H%d_D%d", half, disk), mWater, 0., rin, length1_4 / 2); + TGeoVolume* Tube1_4 = gGeoManager->MakeTube( + Form("Tube1_4_H%d_D%d", half, disk), mPipe, rin, rout, length1_4 / 2); + TGeoVolume* TubeW1_4 = gGeoManager->MakeTube( + Form("TubeW1_4_H%d_D%d", half, disk), mWater, 0., rin, length1_4 / 2); TGeoTranslation* tTube1_4 = new TGeoTranslation(0.0, 0.0, 0.0); tTube1_4->RegisterYourself(); Float_t radius1_4 = 0.4; - TGeoVolume* Torus1_4 = gGeoManager->MakeTorus(Form("Torus1_4_H%d_D%d", half, disk), mPipe, radius1_4, rin, rout, 0., 90.); - TGeoVolume* TorusW1_4 = gGeoManager->MakeTorus(Form("TorusW1_4_H%d_D%d", half, disk), mWater, radius1_4, 0., rin, 0., 90.); - TGeoRotation* rTorus1_4 = new TGeoRotation("rotationTorus1_4", 90.0, 90.0, 0.0); + TGeoVolume* Torus1_4 = + gGeoManager->MakeTorus(Form("Torus1_4_H%d_D%d", half, disk), mPipe, + radius1_4, rin, rout, 0., 90.); + TGeoVolume* TorusW1_4 = + gGeoManager->MakeTorus(Form("TorusW1_4_H%d_D%d", half, disk), mWater, + radius1_4, 0., rin, 0., 90.); + TGeoRotation* rTorus1_4 = + new TGeoRotation("rotationTorus1_4", 90.0, 90.0, 0.0); rTorus1_4->RegisterYourself(); - TGeoCombiTrans* transfoTorus1_4 = new TGeoCombiTrans(0.0, -radius1_4, length1_4 / 2, rTorus1_4); + TGeoCombiTrans* transfoTorus1_4 = + new TGeoCombiTrans(0.0, -radius1_4, length1_4 / 2, rTorus1_4); transfoTorus1_4->RegisterYourself(); Float_t length2_4; if (disk == 4) { length2_4 = 10.8; } - TGeoVolume* Tube2_4 = gGeoManager->MakeTube("Tube2_4", mPipe, rin, rout, length2_4 / 2); - TGeoVolume* TubeW2_4 = gGeoManager->MakeTube("TubeW2_4", mWater, 0., rin, length2_4 / 2); - TGeoRotation* rTube2_4 = new TGeoRotation("rotationTube2_4", 180.0, 90.0, 90.0); + TGeoVolume* Tube2_4 = + gGeoManager->MakeTube("Tube2_4", mPipe, rin, rout, length2_4 / 2); + TGeoVolume* TubeW2_4 = + gGeoManager->MakeTube("TubeW2_4", mWater, 0., rin, length2_4 / 2); + TGeoRotation* rTube2_4 = + new TGeoRotation("rotationTube2_4", 180.0, 90.0, 90.0); rTube2_4->RegisterYourself(); - TGeoCombiTrans* transfoTube2_4 = new TGeoCombiTrans(0., -length2_4 / 2 - radius1_4, length1_4 / 2 + radius1_4, rTube2_4); + TGeoCombiTrans* transfoTube2_4 = new TGeoCombiTrans( + 0., -length2_4 / 2 - radius1_4, length1_4 / 2 + radius1_4, rTube2_4); transfoTube2_4->RegisterYourself(); - TGeoVolume* Torus2_4 = gGeoManager->MakeTorus(Form("Torus2_4_H%d_D%d", half, disk), mPipe, radius1_4, rin, rout, 0., 90.); - TGeoVolume* TorusW2_4 = gGeoManager->MakeTorus(Form("TorusW2_4_H%d_D%d", half, disk), mWater, radius1_4, 0., rin, 0., 90.); - TGeoRotation* rTorus2_4 = new TGeoRotation("rotationTorus2_4", 90.0, 90.0, 180.0); + TGeoVolume* Torus2_4 = + gGeoManager->MakeTorus(Form("Torus2_4_H%d_D%d", half, disk), mPipe, + radius1_4, rin, rout, 0., 90.); + TGeoVolume* TorusW2_4 = + gGeoManager->MakeTorus(Form("TorusW2_4_H%d_D%d", half, disk), mWater, + radius1_4, 0., rin, 0., 90.); + TGeoRotation* rTorus2_4 = + new TGeoRotation("rotationTorus2_4", 90.0, 90.0, 180.0); rTorus2_4->RegisterYourself(); - TGeoCombiTrans* transfoTorus2_4 = new TGeoCombiTrans(0.0, -length2_4 - radius1_4, length1_4 / 2 + radius1_4 + radius1_4, rTorus2_4); + TGeoCombiTrans* transfoTorus2_4 = + new TGeoCombiTrans(0.0, -length2_4 - radius1_4, + length1_4 / 2 + radius1_4 + radius1_4, rTorus2_4); transfoTorus2_4->RegisterYourself(); Float_t length3_4; if (disk == 4) { length3_4 = 3.8; } - TGeoVolume* Tube3_4 = gGeoManager->MakeTube(Form("Tube3_4_H%d_D%d", half, disk), mPipe, rin, rout, length3_4 / 2); - TGeoVolume* TubeW3_4 = gGeoManager->MakeTube(Form("TubeW3_4_H%d_D%d", half, disk), mWater, 0., rin, length3_4 / 2); + TGeoVolume* Tube3_4 = gGeoManager->MakeTube( + Form("Tube3_4_H%d_D%d", half, disk), mPipe, rin, rout, length3_4 / 2); + TGeoVolume* TubeW3_4 = gGeoManager->MakeTube( + Form("TubeW3_4_H%d_D%d", half, disk), mWater, 0., rin, length3_4 / 2); TGeoRotation* rTube3_4 = new TGeoRotation("rotationTube3_4", 0.0, 0.0, 0.0); rTube3_4->RegisterYourself(); - TGeoCombiTrans* transfoTube3_4 = new TGeoCombiTrans(0., -length2_4 - radius1_4 - radius1_4, length1_4 / 2 + radius1_4 + radius1_4 + length3_4 / 2, rTube3_4); + TGeoCombiTrans* transfoTube3_4 = new TGeoCombiTrans( + 0., -length2_4 - radius1_4 - radius1_4, + length1_4 / 2 + radius1_4 + radius1_4 + length3_4 / 2, rTube3_4); transfoTube3_4->RegisterYourself(); Tube1_4->SetLineColor(kGray); @@ -4170,20 +6193,36 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) TGeoCombiTrans* transfoCoolingPipe3_4 = nullptr; TGeoRotation* rotation3_4 = new TGeoRotation("rotation3_4", 90., 90., 100.); rotation3_4->RegisterYourself(); - transfoCoolingPipe3_4 = new TGeoCombiTrans(17. + length1_4 / 2, 0.75, 0.0, rotation3_4); + transfoCoolingPipe3_4 = + new TGeoCombiTrans(17. + length1_4 / 2, 0.75, 0.0, rotation3_4); transfoCoolingPipe3_4->RegisterYourself(); // ------------------Other diagonal side - auto* mCoolingPipe4 = new TGeoVolumeAssembly(Form("cooling_pipe4_H%d_D%d", half, disk)); - TGeoVolume* Tube1p_4 = gGeoManager->MakeTube(Form("Tube1p_4_H%d_D%d", half, disk), mPipe, rin, rout, length1_4 / 2); - TGeoVolume* Torus1p_4 = gGeoManager->MakeTorus(Form("Torus1p_4_H%d_D%d", half, disk), mPipe, radius1_4, rin, rout, 0., 90.); - TGeoVolume* Tube2p_4 = gGeoManager->MakeTube(Form("Tube2p_4_H%d_D%d", half, disk), mPipe, rin, rout, length2_4 / 2); - TGeoVolume* Torus2p_4 = gGeoManager->MakeTorus(Form("Torus2p_4_H%d_D%d", half, disk), mPipe, radius1_4, rin, rout, 0., 90.); - TGeoVolume* Tube3p_4 = gGeoManager->MakeTube(Form("Tube3p_4_H%d_D%d", half, disk), mPipe, rin, rout, length3_4 / 2); - TGeoVolume* TubeW1p_4 = gGeoManager->MakeTube(Form("TubeW1p_4_H%d_D%d", half, disk), mWater, 0., rin, length1_4 / 2); - TGeoVolume* TorusW1p_4 = gGeoManager->MakeTorus(Form("TorusW1p_4_H%d_D%d", half, disk), mWater, radius1_4, 0., rin, 0., 90.); - TGeoVolume* TubeW2p_4 = gGeoManager->MakeTube(Form("TubeW2p_4_H%d_D%d", half, disk), mWater, 0., rin, length2_4 / 2); - TGeoVolume* TorusW2p_4 = gGeoManager->MakeTorus(Form("TorusW2p_4_H%d_D%d", half, disk), mWater, radius1_4, 0., rin, 0., 90.); - TGeoVolume* TubeW3p_4 = gGeoManager->MakeTube(Form("TubeW3p_4_H%d_D%d", half, disk), mWater, 0., rin, length3_4 / 2); + auto* mCoolingPipe4 = + new TGeoVolumeAssembly(Form("cooling_pipe4_H%d_D%d", half, disk)); + TGeoVolume* Tube1p_4 = gGeoManager->MakeTube( + Form("Tube1p_4_H%d_D%d", half, disk), mPipe, rin, rout, length1_4 / 2); + TGeoVolume* Torus1p_4 = + gGeoManager->MakeTorus(Form("Torus1p_4_H%d_D%d", half, disk), mPipe, + radius1_4, rin, rout, 0., 90.); + TGeoVolume* Tube2p_4 = gGeoManager->MakeTube( + Form("Tube2p_4_H%d_D%d", half, disk), mPipe, rin, rout, length2_4 / 2); + TGeoVolume* Torus2p_4 = + gGeoManager->MakeTorus(Form("Torus2p_4_H%d_D%d", half, disk), mPipe, + radius1_4, rin, rout, 0., 90.); + TGeoVolume* Tube3p_4 = gGeoManager->MakeTube( + Form("Tube3p_4_H%d_D%d", half, disk), mPipe, rin, rout, length3_4 / 2); + TGeoVolume* TubeW1p_4 = gGeoManager->MakeTube( + Form("TubeW1p_4_H%d_D%d", half, disk), mWater, 0., rin, length1_4 / 2); + TGeoVolume* TorusW1p_4 = + gGeoManager->MakeTorus(Form("TorusW1p_4_H%d_D%d", half, disk), mWater, + radius1_4, 0., rin, 0., 90.); + TGeoVolume* TubeW2p_4 = gGeoManager->MakeTube( + Form("TubeW2p_4_H%d_D%d", half, disk), mWater, 0., rin, length2_4 / 2); + TGeoVolume* TorusW2p_4 = + gGeoManager->MakeTorus(Form("TorusW2p_4_H%d_D%d", half, disk), mWater, + radius1_4, 0., rin, 0., 90.); + TGeoVolume* TubeW3p_4 = gGeoManager->MakeTube( + Form("TubeW3p_4_H%d_D%d", half, disk), mWater, 0., rin, length3_4 / 2); Tube1p_4->SetLineColor(kGray); Torus1p_4->SetLineColor(kGray); @@ -4204,9 +6243,11 @@ void HeatExchanger::createCoolingPipes(Int_t half, Int_t disk) mCoolingPipe4->AddNode(TubeW3p_4, 1, transfoTube3_4); TGeoCombiTrans* transfoCoolingPipe4_4 = nullptr; - TGeoRotation* rotation4_4 = new TGeoRotation("rotation4_4", 90., 90., -100.); + TGeoRotation* rotation4_4 = + new TGeoRotation("rotation4_4", 90., 90., -100.); rotation4_4->RegisterYourself(); - transfoCoolingPipe4_4 = new TGeoCombiTrans(17. + length1_4 / 2, -0.75, 0.0, rotation4_4); + transfoCoolingPipe4_4 = + new TGeoCombiTrans(17. + length1_4 / 2, -0.75, 0.0, rotation4_4); transfoCoolingPipe4_4->RegisterYourself(); mHalfDisk->AddNode(mCoolingPipe3, 1, transfoCoolingPipe3_4); @@ -4223,19 +6264,30 @@ void HeatExchanger::initParameters() mHalfDiskTransformation = new TGeoCombiTrans**[constants::DisksNumber]; for (Int_t idisk = 0; idisk < constants::DisksNumber; idisk++) { mHalfDiskRotation[idisk] = new TGeoRotation*[constants::HalvesNumber]; - mHalfDiskTransformation[idisk] = new TGeoCombiTrans*[constants::HalvesNumber]; + mHalfDiskTransformation[idisk] = + new TGeoCombiTrans*[constants::HalvesNumber]; for (Int_t ihalf = 0; ihalf < constants::HalvesNumber; ihalf++) { - mHalfDiskRotation[idisk][ihalf] = new TGeoRotation(Form("rotation%d%d", idisk, ihalf), 0., 0., 0.); + mHalfDiskRotation[idisk][ihalf] = + new TGeoRotation(Form("rotation%d%d", idisk, ihalf), 0., 0., 0.); mHalfDiskTransformation[idisk][ihalf] = - new TGeoCombiTrans(Form("transformation%d%d", idisk, ihalf), 0., 0., 0., mHalfDiskRotation[idisk][ihalf]); + new TGeoCombiTrans(Form("transformation%d%d", idisk, ihalf), 0., 0., + 0., mHalfDiskRotation[idisk][ihalf]); } } if (Geometry::sGrooves == 0) { - mRohacellThickness = mHeatExchangerThickness / 2. - 2. * mCarbonThickness - 2 * Geometry::sGlueRohacellCarbonThickness - 2 * Geometry::sKaptonOnCarbonThickness - 2 * Geometry::sKaptonGlueThickness - 2 * (mRWater + mDRPipe); // smaller rohacell thickness, no grooves + mRohacellThickness = + mHeatExchangerThickness / 2. - 2. * mCarbonThickness - + 2 * Geometry::sGlueRohacellCarbonThickness - + 2 * Geometry::sKaptonOnCarbonThickness - + 2 * Geometry::sKaptonGlueThickness - + 2 * (mRWater + mDRPipe); // smaller rohacell thickness, no grooves } if (Geometry::sGrooves == 1) { - mRohacellThickness = mHeatExchangerThickness / 2. - 2. * mCarbonThickness - 2 * Geometry::sGlueRohacellCarbonThickness - 2 * Geometry::sKaptonOnCarbonThickness - 2 * Geometry::sKaptonGlueThickness; // with grooves + mRohacellThickness = mHeatExchangerThickness / 2. - 2. * mCarbonThickness - + 2 * Geometry::sGlueRohacellCarbonThickness - + 2 * Geometry::sKaptonOnCarbonThickness - + 2 * Geometry::sKaptonGlueThickness; // with grooves } mHalfDiskGap = 0.1; @@ -4266,8 +6318,10 @@ void HeatExchanger::initParameters() mSupportYDimensions[i] = new double[mNPart[i]]; } - mMoreLength01 = 0.6; // additional length of carbon plates compare to the rohacell plate, disk 0 and 1 - mMoreLength = 0.6; // additional length of carbon plates compare to the rohacell plate + mMoreLength01 = 0.6; // additional length of carbon plates compare to the + // rohacell plate, disk 0 and 1 + mMoreLength = + 0.6; // additional length of carbon plates compare to the rohacell plate // disk width // disks 0, 1 From c72c4ef6a2a23fa899121c7d82dbadb5d5d30133 Mon Sep 17 00:00:00 2001 From: frmanso Date: Thu, 21 Sep 2023 10:32:17 +0200 Subject: [PATCH 146/324] Update HeatExchanger.cxx Modified headers --- Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx b/Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx index 99b42f6102ae9..08cb444c983b6 100644 --- a/Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx +++ b/Detectors/ITSMFT/MFT/base/src/HeatExchanger.cxx @@ -1,6 +1,6 @@ // Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright -// holders. All rights not expressly granted are reserved. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. // // This software is distributed under the terms of the GNU General Public // License v3 (GPL Version 3), copied verbatim in the file "COPYING". @@ -9,9 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file HeatExchanger.cxx -/// \brief Class building the MFT heat exchanger -/// \author P. Demongodin, and Raphael Tieulent +/// \author P. Demongodin, Raphael Tieulent, Franck Manso #include "MFTBase/HeatExchanger.h" #include "MFTBase/Constants.h" From e314a90c5f0558e61f7a0bee0b0699f571721262 Mon Sep 17 00:00:00 2001 From: noferini Date: Wed, 13 Sep 2023 09:07:37 +0200 Subject: [PATCH 147/324] adjusting TOF calib info alignment to BC --- .../include/GlobalTracking/MatchTOF.h | 10 +++-- Detectors/GlobalTracking/src/MatchTOF.cxx | 39 ++++++++++++------- .../src/TOFMatcherSpec.cxx | 4 +- .../tofworkflow/src/tof-calibinfo-reader.cxx | 4 +- Detectors/TOF/base/src/Utils.cxx | 22 +++++++++-- 5 files changed, 54 insertions(+), 25 deletions(-) diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h index db0abf1233e00..fbaef9a8a0c1f 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h @@ -90,7 +90,7 @@ class MatchTOF public: ///< perform matching for provided input - void run(const o2::globaltracking::RecoContainer& inp); + void run(const o2::globaltracking::RecoContainer& inp, unsigned long firstTForbit = 0); void setCosmics() { @@ -173,7 +173,7 @@ class MatchTOF } void setFIT(bool value = true) { mIsFIT = value; } - static int findFITIndex(int bc, const gsl::span& FITRecPoints); + static int findFITIndex(int bc, const gsl::span& FITRecPoints, unsigned long firstOrbit); void checkRefitter(); bool makeConstrainedTPCTrack(int matchedID, o2::dataformats::TrackTPCTOF& trConstr); @@ -216,8 +216,8 @@ class MatchTOF void doMatching(int sec); void doMatchingForTPC(int sec); void selectBestMatches(); - static void BestMatches(std::vector& matchedTracksPairs, std::vector* matchedTracks, std::vector* matchedTracksIndex, int* matchedClustersIndex, const gsl::span& FITRecPoints, const std::vector& TOFClusWork, const std::vector* TracksWork, std::vector& CalibInfoTOF, unsigned long Timestamp, bool MCTruthON, const o2::dataformats::MCTruthContainer* TOFClusLabels, const std::vector* TracksLblWork, std::vector* OutTOFLabels, float calibMaxChi2); - static void BestMatchesHP(std::vector& matchedTracksPairs, std::vector* matchedTracks, std::vector* matchedTracksIndex, int* matchedClustersIndex, const gsl::span& FITRecPoints, const std::vector& TOFClusWork, std::vector& CalibInfoTOF, unsigned long Timestamp, bool MCTruthON, const o2::dataformats::MCTruthContainer* TOFClusLabels, const std::vector* TracksLblWork, std::vector* OutTOFLabels); + void BestMatches(std::vector& matchedTracksPairs, std::vector* matchedTracks, std::vector* matchedTracksIndex, int* matchedClustersIndex, const gsl::span& FITRecPoints, const std::vector& TOFClusWork, const std::vector* TracksWork, std::vector& CalibInfoTOF, unsigned long Timestamp, bool MCTruthON, const o2::dataformats::MCTruthContainer* TOFClusLabels, const std::vector* TracksLblWork, std::vector* OutTOFLabels, float calibMaxChi2); + void BestMatchesHP(std::vector& matchedTracksPairs, std::vector* matchedTracks, std::vector* matchedTracksIndex, int* matchedClustersIndex, const gsl::span& FITRecPoints, const std::vector& TOFClusWork, std::vector& CalibInfoTOF, unsigned long Timestamp, bool MCTruthON, const o2::dataformats::MCTruthContainer* TOFClusLabels, const std::vector* TracksLblWork, std::vector* OutTOFLabels); bool propagateToRefX(o2::track::TrackParCov& trc, float xRef /*in cm*/, float stepInCm /*in cm*/, o2::track::TrackLTIntegral& intLT); bool propagateToRefXWithoutCov(o2::track::TrackParCov& trc, float xRef /*in cm*/, float stepInCm /*in cm*/, float bz); @@ -269,6 +269,8 @@ class MatchTOF unsigned long mTimestamp = 0; ///< in ms + unsigned long mFirstTForbit = 0; ///< First orbit in TF (needed to align FT0 recpoints) + // from ruben gsl::span mTPCTracksArray; ///< input TPC tracks span diff --git a/Detectors/GlobalTracking/src/MatchTOF.cxx b/Detectors/GlobalTracking/src/MatchTOF.cxx index 9cebaa73e24df..5d09e96951ff2 100644 --- a/Detectors/GlobalTracking/src/MatchTOF.cxx +++ b/Detectors/GlobalTracking/src/MatchTOF.cxx @@ -56,8 +56,10 @@ using timeEst = o2::dataformats::TimeStampWithError; ClassImp(MatchTOF); //______________________________________________ -void MatchTOF::run(const o2::globaltracking::RecoContainer& inp) +void MatchTOF::run(const o2::globaltracking::RecoContainer& inp, unsigned long firstTForbit) { + mFirstTForbit = firstTForbit; + if (!mMatchParams) { mMatchParams = &o2::globaltracking::MatchTOFParams::Instance(); mSigmaTimeCut = mMatchParams->nsigmaTimeCut; @@ -1183,18 +1185,20 @@ void MatchTOF::doMatchingForTPC(int sec) return; } //______________________________________________ -int MatchTOF::findFITIndex(int bc, const gsl::span& FITRecPoints) +int MatchTOF::findFITIndex(int bc, const gsl::span& FITRecPoints, unsigned long firstOrbit) { + bc -= o2::tof::Geo::LATENCYWINDOW_IN_BC; + if (FITRecPoints.size() == 0) { return -1; } int index = -1; - int distMax = 5; // require bc distance below 5 + int distMax = 7; // require bc distance below 5 for (unsigned int i = 0; i < FITRecPoints.size(); i++) { const o2::InteractionRecord ir = FITRecPoints[i].getInteractionRecord(); - int bct0 = ir.orbit * o2::constants::lhc::LHCMaxBunches + ir.bc; + int bct0 = (ir.orbit - firstOrbit) * o2::constants::lhc::LHCMaxBunches + ir.bc; int dist = bc - bct0; if (dist < 0 || dist > distMax) { @@ -1254,14 +1258,15 @@ void MatchTOF::BestMatches(std::vector& match const o2::track::TrackLTIntegral& intLT = matchingPair.getLTIntegralOut(); - if (FITRecPoints.size() > 0) { - int index = findFITIndex(TOFClusWork[matchingPair.getTOFClIndex()].getBC(), FITRecPoints); + if (FITRecPoints.size() > 0 && mIsFIT) { + int index = findFITIndex(TOFClusWork[matchingPair.getTOFClIndex()].getBC() - o2::tof::Geo::LATENCYWINDOW_IN_BC, FITRecPoints, mFirstTForbit); if (index > -1) { o2::InteractionRecord ir = FITRecPoints[index].getInteractionRecord(); - t0info = ir.bc2ns() * 1E3; + int bct0 = (ir.orbit - mFirstTForbit) * o2::constants::lhc::LHCMaxBunches + ir.bc; + t0info = bct0 * o2::tof::Geo::BC_TIME_INPS; } - } else { // move time to time in orbit to avoid loss of precision when truncating from double to float + } else if (!mIsFIT) { // move time to time in orbit to avoid loss of precision when truncating from double to float int bcStarOrbit = int((TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - intLT.getTOF(o2::track::PID::Pion)) * o2::tof::Geo::BC_TIME_INPS_INV); bcStarOrbit = (bcStarOrbit / o2::constants::lhc::LHCMaxBunches) * o2::constants::lhc::LHCMaxBunches; // truncation t0info = bcStarOrbit * o2::tof::Geo::BC_TIME_INPS; @@ -1280,7 +1285,14 @@ void MatchTOF::BestMatches(std::vector& match } int mask = 0; - float deltat = o2::tof::Utils::subtractInteractionBC(TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - t0info - intLT.getTOF(o2::track::PID::Pion), mask, true); + float deltat; + + if (t0info > 0 && mIsFIT) { // FT0 BC found + deltat = TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - t0info - intLT.getTOF(o2::track::PID::Pion) - o2::tof::Geo::LATENCYWINDOW_IN_BC * o2::tof::Geo::BC_TIME_INPS; // latency subtracted + mask = 1 << 8; // only FT0 BC allowed (-> BC=0 since t0info already subtracted and assumed to be aligned to the true IntBC) + } else if (!mIsFIT) { + deltat = o2::tof::Utils::subtractInteractionBC(TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - t0info - intLT.getTOF(o2::track::PID::Pion), mask, true); + } const o2::track::TrackParCov& trc = TracksWork[trkType][itrk].first; float pt = trc.getPt(); // from outer parameters! @@ -1301,7 +1313,7 @@ void MatchTOF::BestMatches(std::vector& match flags = flags | o2::dataformats::CalibInfoTOF::kMultiHit; } - if (matchingPair.getChi2() < calibMaxChi2) { // extra cut in ChiSquare for storing calib info + if (matchingPair.getChi2() < calibMaxChi2 && t0info > 0) { // extra cut in ChiSquare for storing calib info CalibInfoTOF.emplace_back(TOFClusWork[matchingPair.getTOFClIndex()].getMainContributingChannel(), Timestamp / 1000 + int(TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() * 1E-12), // add time stamp deltat, @@ -1394,12 +1406,13 @@ void MatchTOF::BestMatchesHP(std::vector& mat // get fit info double t0info = 0; - if (FITRecPoints.size() > 0) { - int index = findFITIndex(TOFClusWork[matchingPair.getTOFClIndex()].getBC(), FITRecPoints); + if (FITRecPoints.size() > 0 && mIsFIT) { + int index = findFITIndex(TOFClusWork[matchingPair.getTOFClIndex()].getBC() - o2::tof::Geo::LATENCYWINDOW_IN_BC, FITRecPoints, mFirstTForbit); if (index > -1) { o2::InteractionRecord ir = FITRecPoints[index].getInteractionRecord(); - t0info = ir.bc2ns() * 1E3; + int bct0 = (ir.orbit - mFirstTForbit) * o2::constants::lhc::LHCMaxBunches + ir.bc; + t0info = bct0 * o2::tof::Geo::BC_TIME_INPS; } } else { // move time to time in orbit to avoid loss of precision when truncating from double to float int bcStarOrbit = int((TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - intLT.getTOF(o2::track::PID::Pion)) * o2::tof::Geo::BC_TIME_INPS_INV); diff --git a/Detectors/GlobalTrackingWorkflow/src/TOFMatcherSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/TOFMatcherSpec.cxx index 5b81466363710..a235242750ba3 100644 --- a/Detectors/GlobalTrackingWorkflow/src/TOFMatcherSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/TOFMatcherSpec.cxx @@ -165,7 +165,7 @@ void TOFMatcherSpec::run(ProcessingContext& pc) mMatcher.setTS(creationTime); - mMatcher.run(recoData); + mMatcher.run(recoData, pc.services().get().firstTForbit); if (isTPCused) { pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MTC_TPC", ss, Lifetime::Timeframe}, mMatcher.getMatchedTrackVector(o2::dataformats::MatchInfoTOFReco::TrackType::TPC)); @@ -248,7 +248,7 @@ DataProcessorSpec getTOFMatcherSpec(GID::mask_t src, bool useMC, bool useFIT, bo dataRequest->requestTracks(src, useMC); dataRequest->requestClusters(GID::getSourceMask(GID::TOF), useMC); if (useFIT) { - dataRequest->requestClusters(GID::getSourceMask(GID::FT0), false); + dataRequest->requestFT0RecPoints(false); } auto ggRequest = std::make_shared(false, // orbitResetTime diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-calibinfo-reader.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-calibinfo-reader.cxx index e9e7db4e6f339..27a48d93dac8b 100644 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-calibinfo-reader.cxx +++ b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/tof-calibinfo-reader.cxx @@ -74,8 +74,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) auto listname = cfgc.options().get("collection-infile"); auto toftpc = cfgc.options().get("tpc-matches"); - char* stringTBP = new char[listname.size()]; - snprintf(stringTBP, listname.size(), "%s", listname.c_str()); + char* stringTBP = new char[listname.size() + 1]; + snprintf(stringTBP, listname.size() + 1, "%s", listname.c_str()); // the lane configuration defines the subspecification ids to be distributed among the lanes. // auto tofSectors = o2::RangeTokenizer::tokenize(cfgc.options().get("tof-sectors")); diff --git a/Detectors/TOF/base/src/Utils.cxx b/Detectors/TOF/base/src/Utils.cxx index 02d0621c09752..265cb0247b544 100644 --- a/Detectors/TOF/base/src/Utils.cxx +++ b/Detectors/TOF/base/src/Utils.cxx @@ -272,14 +272,28 @@ int Utils::addMaskBC(int mask, int channel) int mask2 = (mask >> 16); int cmask = 1; int used = 0; + int weight = 1; + int candidates = 0; + for (int ibit = 0; ibit < 16; ibit++) { // counts candidates + if (mask & cmask) { + candidates++; + } + cmask *= 2; + } + + if (candidates) { + weight = 16 / candidates; + } + + cmask = 1; for (int ibit = 0; ibit < 16; ibit++) { if (mask & cmask) { - mMaskBCchan[channel][ibit]++; - mMaskBC[ibit]++; + mMaskBCchan[channel][ibit] += weight; + mMaskBC[ibit] += weight; } if (mask2 & cmask) { - mMaskBCchanUsed[channel][ibit]++; - mMaskBCUsed[ibit]++; + mMaskBCchanUsed[channel][ibit] += weight; + mMaskBCUsed[ibit] += weight; used = ibit - 8; } cmask *= 2; From 0b24762cc9142714a78bf9aa611f1a1b97f13c48 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Tue, 26 Sep 2023 09:09:38 +0200 Subject: [PATCH 148/324] dpl-workflow: With NUMAGPUIDS, we expect 5 region callbacks not 4 --- prodtests/full-system-test/dpl-workflow.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 5d2e55d2335cf..07ef905a339b8 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -195,7 +195,13 @@ has_detector_flp_processing CPV && CPV_INPUT=digits if [[ $EPNSYNCMODE == 1 ]]; then EVE_CONFIG+=" --eve-dds-collection-index 0" MIDDEC_CONFIG+=" --feeId-config-file \"$MID_FEEID_MAP\"" - if [[ $EXTINPUT == 1 ]] && [[ $GPUTYPE != "CPU" ]] && [[ -z "$GPU_NUM_MEM_REG_CALLBACKS" ]]; then GPU_NUM_MEM_REG_CALLBACKS=4; fi + if [[ $EXTINPUT == 1 ]] && [[ $GPUTYPE != "CPU" ]] && [[ -z "$GPU_NUM_MEM_REG_CALLBACKS" ]]; then + if [[ $NUMAGPUIDS == 1 ]]; then + GPU_NUM_MEM_REG_CALLBACKS=5 + else + GPU_NUM_MEM_REG_CALLBACKS=4 + fi + fi fi if [[ $SYNCRAWMODE == 1 ]]; then GPU_CONFIG_KEY+="GPU_proc.tpcIncreasedMinClustersPerRow=500000;GPU_proc.ignoreNonFatalGPUErrors=1;GPU_proc.throttleAlarms=1;GPU_proc.conservativeMemoryEstimate=1;" From aa60d4978c0c9c99f5189e8a4008bb694198df0a Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 26 Sep 2023 17:33:36 +0200 Subject: [PATCH 149/324] DPL: fix race condition with the delivery of region events (#11961) * DPL: fix race condition with the delivery of region events * Update Framework/Core/src/DataProcessingDevice.cxx --- Framework/Core/src/DataProcessingDevice.cxx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index cf664a5e9fdeb..e3c29035e9d21 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -957,9 +957,12 @@ void DataProcessingDevice::InitTask() LOG(detail) << "ptr: " << info.ptr; LOG(detail) << "size: " << info.size; LOG(detail) << "flags: " << info.flags; - context.expectedRegionCallbacks -= 1; + // Now we check for pending events with the mutex, + // so the lines below are atomic. pendingRegionInfos.push_back(info); - // We always want to handle these on the main loop + context.expectedRegionCallbacks -= 1; + // We always want to handle these on the main loop, + // so we awake it. ServiceRegistryRef ref{registry}; uv_async_send(ref.get().awakeMainThread); }); @@ -991,11 +994,17 @@ void DataProcessingDevice::InitTask() // We will get there. this->fillContext(mServiceRegistry.get(ServiceRegistry::globalDeviceSalt()), deviceContext); + auto hasPendingEvents = [&mutex = mRegionInfoMutex, &pendingRegionInfos = mPendingRegionInfos](DeviceContext& deviceContext) { + std::lock_guard lock(mutex); + return (pendingRegionInfos.empty() == false) || deviceContext.expectedRegionCallbacks > 0; + }; /// We now run an event loop also in InitTask. This is needed to: /// * Make sure region registration callbacks are invoked /// on the main thread. /// * Wait for enough callbacks to be delivered before moving to START - while (deviceContext.expectedRegionCallbacks > 0 && uv_run(state.loop, UV_RUN_ONCE)) { + while (hasPendingEvents(deviceContext)) { + // Wait for the callback to signal its done, so that we do not busy wait. + uv_run(state.loop, UV_RUN_ONCE); // Handle callbacks if any { std::lock_guard lock(mRegionInfoMutex); From 99aaf3a5ad15520dc493bbcfe849f6781247d776 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Tue, 26 Sep 2023 17:37:35 +0200 Subject: [PATCH 150/324] DPL: Do not inject at EndOfStream --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 4118e1ce0d0e2..bd9767fe0661e 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -244,6 +244,7 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve bool allFound = true; DataProcessingHeader const* dph = nullptr; DataHeader const* firstDH = nullptr; + bool hassih = false; // Do not check anything which has DISTSUBTIMEFRAME in it. for (size_t pi = 0; pi < present.size(); ++pi) { @@ -258,6 +259,7 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve const auto dh = o2::header::get(parts.At(msgidx)->GetData()); auto const sih = o2::header::get(parts.At(msgidx)->GetData()); if (sih != nullptr) { + hassih = true; continue; } if (parts.At(msgidx).get() == nullptr) { @@ -304,6 +306,13 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve } if (unmatchedDescriptions.size() > 0) { + if (hassih) { + if (firstDH) { + LOG(error) << "Received an EndOfStream message together with data. This should not happen."; + } + LOG(detail) << "This is an End Of Stream message. Not injecting anything."; + return; + } if (firstDH == nullptr) { LOG(error) << "Input proxy received incomplete data without any data header. This should not happen! Cannot inject missing data as requsted."; return; From a29f636384d66a579ff963e1fa6f380715827753 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Tue, 26 Sep 2023 10:55:17 +0200 Subject: [PATCH 151/324] GPU SA MultiThreading: Run async receiveThread only once DPL invoked run() the first time to make sure everything is initialized --- GPU/Workflow/src/GPUWorkflowInternal.h | 10 +++++----- GPU/Workflow/src/GPUWorkflowPipeline.cxx | 22 ++++++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/GPU/Workflow/src/GPUWorkflowInternal.h b/GPU/Workflow/src/GPUWorkflowInternal.h index 9e805b3448bfc..3a8aa0da54694 100644 --- a/GPU/Workflow/src/GPUWorkflowInternal.h +++ b/GPU/Workflow/src/GPUWorkflowInternal.h @@ -63,13 +63,13 @@ struct GPURecoWorkflowSpec_PipelineInternals { fair::mq::Device* fmqDevice = nullptr; fair::mq::State fmqState = fair::mq::State::Undefined; - bool endOfStreamReceived = false; - std::mutex fmqStateMutex; - std::condition_variable fmqStateCheckNotify; + volatile bool endOfStreamReceived = false; + volatile bool runStarted = false; + volatile bool shouldTerminate = false; + std::mutex stateMutex; + std::condition_variable stateNotify; std::thread receiveThread; - std::mutex threadMutex; - volatile bool shouldTerminate = false; struct pipelineWorkerStruct { std::thread thread; diff --git a/GPU/Workflow/src/GPUWorkflowPipeline.cxx b/GPU/Workflow/src/GPUWorkflowPipeline.cxx index f564f1e5e6837..83c96582fca36 100644 --- a/GPU/Workflow/src/GPUWorkflowPipeline.cxx +++ b/GPU/Workflow/src/GPUWorkflowPipeline.cxx @@ -156,6 +156,9 @@ void GPURecoWorkflowSpec::finalizeInputPipelinedJob(GPUTrackingInOutPointers* pt int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutPointers& ptrs, GPURecoWorkflowSpec_TPCZSBuffers& tpcZSmeta, o2::gpu::GPUTrackingInOutZS& tpcZS, std::unique_ptr& context) { + mPipeline->runStarted = true; + mPipeline->stateNotify.notify_all(); + auto* device = pc.services().get().device(); const auto& tinfo = pc.services().get(); if (mSpecConfig.enableDoublePipeline == 1) { @@ -239,11 +242,8 @@ int GPURecoWorkflowSpec::handlePipeline(ProcessingContext& pc, GPUTrackingInOutP void GPURecoWorkflowSpec::handlePipelineEndOfStream(EndOfStreamContext& ec) { if (mSpecConfig.enableDoublePipeline == 1) { - { - std::lock_guard lk(mPipeline->fmqStateMutex); - mPipeline->endOfStreamReceived = true; - } - mPipeline->fmqStateCheckNotify.notify_all(); + mPipeline->endOfStreamReceived = true; + mPipeline->stateNotify.notify_all(); } if (mSpecConfig.enableDoublePipeline == 2) { auto* device = ec.services().get().device(); @@ -260,7 +260,7 @@ void GPURecoWorkflowSpec::handlePipelineEndOfStream(EndOfStreamContext& ec) void GPURecoWorkflowSpec::receiveFMQStateCallback(fair::mq::State newState) { { - std::lock_guard lk(mPipeline->fmqStateMutex); + std::lock_guard lk(mPipeline->stateMutex); if (mPipeline->fmqState != fair::mq::State::Running && newState == fair::mq::State::Running) { mPipeline->endOfStreamReceived = false; } @@ -269,7 +269,7 @@ void GPURecoWorkflowSpec::receiveFMQStateCallback(fair::mq::State newState) mPipeline->fmqDevice->UnsubscribeFromStateChange(GPURecoWorkflowSpec_FMQCallbackKey); } } - mPipeline->fmqStateCheckNotify.notify_all(); + mPipeline->stateNotify.notify_all(); } void GPURecoWorkflowSpec::RunReceiveThread() @@ -282,8 +282,8 @@ void GPURecoWorkflowSpec::RunReceiveThread() LOG(debug) << "Waiting for out of band message"; do { { - std::unique_lock lk(mPipeline->fmqStateMutex); - mPipeline->fmqStateCheckNotify.wait(lk, [this]() { return (mPipeline->fmqState == fair::mq::State::Running && !mPipeline->endOfStreamReceived) || mPipeline->shouldTerminate; }); // Do not check mPipeline->fmqDevice->NewStatePending() since we wait for EndOfStream! + std::unique_lock lk(mPipeline->stateMutex); + mPipeline->stateNotify.wait(lk, [this]() { return (mPipeline->runStarted && mPipeline->fmqState == fair::mq::State::Running && !mPipeline->endOfStreamReceived) || mPipeline->shouldTerminate; }); // Do not check mPipeline->fmqDevice->NewStatePending() since we wait for EndOfStream! } if (mPipeline->shouldTerminate) { break; @@ -309,8 +309,10 @@ void GPURecoWorkflowSpec::RunReceiveThread() } if (m->flagEndOfStream) { LOG(info) << "Received end-of-stream from out-of-band channel"; + std::lock_guard lk(mPipeline->stateMutex); mPipeline->endOfStreamReceived = true; mPipeline->mNTFReceived = 0; + mPipeline->runStarted = false; continue; } @@ -379,7 +381,7 @@ void GPURecoWorkflowSpec::ExitPipeline() if (mSpecConfig.enableDoublePipeline == 1 && mPipeline->fmqDevice) { mPipeline->fmqDevice = nullptr; mPipeline->shouldTerminate = true; - mPipeline->fmqStateCheckNotify.notify_all(); + mPipeline->stateNotify.notify_all(); for (unsigned int i = 0; i < mPipeline->workers.size(); i++) { mPipeline->workers[i].inputQueueNotify.notify_one(); } From 78e0835ce19b87603b7259917a23780f4a7d87d1 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 27 Sep 2023 01:00:24 +0200 Subject: [PATCH 152/324] GPU: Bugfix for GPU QA in double-pipeline mode --- GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx b/GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx index 9aa3a50cdee55..37d6bc35a0810 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx @@ -251,7 +251,7 @@ int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) } else if (GetProcessingSettings().keepDisplayMemory || GetProcessingSettings().createO2Output <= 1 || mFractionalQAEnabled) { if (!(GetProcessingSettings().keepDisplayMemory || GetProcessingSettings().createO2Output <= 1)) { size_t size = mRec->Res(Merger.MemoryResOutput()).Size() + GPUCA_MEMALIGN; - void* buffer = mQA->AllocateScratchBuffer(size); + void* buffer = GetQA()->AllocateScratchBuffer(size); void* bufferEnd = Merger.SetPointersOutput(buffer); if ((size_t)((char*)bufferEnd - (char*)buffer) > size) { throw std::runtime_error("QA Scratch buffer exceeded"); From 68e16f233affc641df8776bc971e8ecd9e264d03 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Wed, 27 Sep 2023 10:15:54 +0200 Subject: [PATCH 153/324] DPL Analysis: unified getter for a group of simple-typed columns (#11906) --- Framework/Core/include/Framework/ASoA.h | 27 ++++++++++++- Framework/Core/test/test_ASoA.cxx | 52 ++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index d5c384611f226..a3af88a2db16b 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -533,7 +533,7 @@ template using is_persistent_t = decltype(persistent_type_helper::test(nullptr)); template -using is_persistent_v = typename is_persistent_t::value; +constexpr auto is_persistent_v = is_persistent_t::value; template using is_external_index_t = typename std::conditional, std::true_type, std::false_type>::type; @@ -1261,6 +1261,21 @@ class Table return static_cast(*this).template getDynamicValue(); } + template + auto getValue() const + { + using COL = std::decay_t; + static_assert(is_dynamic_t() || is_persistent_v, "Should be persistent or dynamic column with no argument that has a return type convertable to float"); + return static_cast(static_cast(*this).get()); + } + + template + std::array getValues() const + { + static_assert(std::is_same_v || std::is_same_v, "The common return type should be float or double"); + return {getValue()...}; + } + using IP::size; using RowViewCore::operator++; @@ -1685,6 +1700,11 @@ std::tuple getRowData(arrow::Table* table, T rowIterator, decltype(auto) _Getter_() const \ { \ return *mColumnIterator; \ + } \ + \ + decltype(auto) get() const \ + { \ + return _Getter_(); \ } \ }; \ static const o2::framework::expressions::BindingNode _Getter_ { _Label_, typeid(_Name_).hash_code(), \ @@ -2315,6 +2335,11 @@ std::tuple getRowData(arrow::Table* table, T rowIterator, return boundGetter(std::make_index_sequence>{}, freeArgs...); \ } \ \ + type get() const \ + { \ + return _Getter_(); \ + } \ + \ template \ type boundGetter(std::integer_sequence&&, FreeArgs... freeArgs) const \ { \ diff --git a/Framework/Core/test/test_ASoA.cxx b/Framework/Core/test/test_ASoA.cxx index ffa6b4ea5a086..52496d3f40eab 100644 --- a/Framework/Core/test/test_ASoA.cxx +++ b/Framework/Core/test/test_ASoA.cxx @@ -10,10 +10,8 @@ // or submit itself to any jurisdiction. #include "Framework/ASoA.h" -#include "Framework/ASoAHelpers.h" #include "Framework/Expressions.h" #include "Framework/AnalysisHelpers.h" -#include "Framework/ExpressionHelpers.h" #include "gandiva/tree_expr_builder.h" #include "arrow/status.h" #include "gandiva/filter.h" @@ -1130,3 +1128,53 @@ TEST_CASE("TestArrayColumns") } } } + +namespace o2::aod +{ +namespace table +{ +DECLARE_SOA_COLUMN(One, one, int); +DECLARE_SOA_COLUMN(Two, two, float); +DECLARE_SOA_COLUMN(Three, three, double); +DECLARE_SOA_COLUMN(Four, four, int[2]); +DECLARE_SOA_DYNAMIC_COLUMN(Five, five, [](const int in[2]) -> float { return (float)in[0] / (float)in[1]; }); +} // namespace table +DECLARE_SOA_TABLE(MixTest, "AOD", "MIXTST", + table::One, table::Two, table::Three, table::Four, + table::Five); +} // namespace o2::aod +TEST_CASE("TestCombinedGetter") +{ + TableBuilder b; + auto writer = b.cursor(); + int f[2]; + for (auto i = 0; i < 20; ++i) { + f[0] = i; + f[1] = i + 1; + writer(0, i, o2::constants::math::PI * i, o2::constants::math::Almost0 * i, f); + } + auto t = b.finalize(); + o2::aod::MixTest mt{t}; + auto count = 0; + for (auto const& row : mt) { + auto features1 = row.getValues(); + auto features2 = row.getValues(); + auto features3 = row.getValues>(); + auto b1 = std::is_same_v, decltype(features1)>; + REQUIRE(b1); + auto b2 = std::is_same_v, decltype(features2)>; + REQUIRE(b2); + auto b3 = std::is_same_v, decltype(features3)>; + REQUIRE(b3); + REQUIRE(features1[0] == (float)count); + REQUIRE(features1[1] == (float)(o2::constants::math::Almost0 * count)); + + REQUIRE(features2[0] == (double)count); + REQUIRE(features2[1] == (double)(o2::constants::math::PI * count)); + REQUIRE(features2[2] == (double)(o2::constants::math::Almost0 * count)); + + REQUIRE(features3[0] == (float)(o2::constants::math::PI * count)); + REQUIRE(features3[1] == (float)((float)count / (float)(count + 1))); + ++count; + } +} From 64244ebbc4dbedb8c32fb916ac6218ee8dcfdc84 Mon Sep 17 00:00:00 2001 From: fmazzasc Date: Tue, 26 Sep 2023 10:43:51 +0200 Subject: [PATCH 154/324] Avoid crashes when CTP is not loaded --- Detectors/AOD/src/AODProducerWorkflowSpec.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index 287dfcab179a0..6b25286e504d0 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -2135,6 +2135,8 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) } else { masks = {0, 0}; } + } else { + masks = {0, 0}; } bcCursor(runNumber, bc, From 1dbb1b54c4bdce4e1fe0f5b53494fa5ef467b41b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= Date: Wed, 27 Sep 2023 11:29:41 +0200 Subject: [PATCH 155/324] Fix namespace pollution from `std` and `o2::constants` (#11851) * Remove std namespace from CCDBDownloader.h * Remove std namespace from DataBlockBase.h * Remove math namespace from AnalysisDataModel.h * Clean TPCSimulation/Digitizer.h * Clean SACDecoder.h --- CCDB/include/CCDB/CCDBDownloader.h | 2 -- .../FIT/raw/include/FITRaw/DataBlockBase.h | 2 -- .../include/TPCCalibration/SACDecoder.h | 1 - .../include/TPCSimulation/Digitizer.h | 2 -- .../include/Framework/AnalysisDataModel.h | 22 +++++++++---------- .../mctracks_to_aod_simple_task.cxx | 1 + 6 files changed, 11 insertions(+), 19 deletions(-) diff --git a/CCDB/include/CCDB/CCDBDownloader.h b/CCDB/include/CCDB/CCDBDownloader.h index ff1d97d68802d..031f656452fe8 100644 --- a/CCDB/include/CCDB/CCDBDownloader.h +++ b/CCDB/include/CCDB/CCDBDownloader.h @@ -29,8 +29,6 @@ typedef struct uv_signal_s uv_signal_t; typedef struct uv_async_s uv_async_t; typedef struct uv_handle_s uv_handle_t; -using namespace std; - namespace o2::ccdb { diff --git a/Detectors/FIT/raw/include/FITRaw/DataBlockBase.h b/Detectors/FIT/raw/include/FITRaw/DataBlockBase.h index 1e8827b90c2a3..1c95f354c6292 100644 --- a/Detectors/FIT/raw/include/FITRaw/DataBlockBase.h +++ b/Detectors/FIT/raw/include/FITRaw/DataBlockBase.h @@ -58,8 +58,6 @@ namespace o2 namespace fit { -using namespace std; - static constexpr size_t SIZE_WORD = 16; static constexpr size_t SIZE_WORD_GBT = 10; // should be changed to gloabal variable static constexpr size_t SIZE_MAX_PAGE = 8192; // should be changed to gloabal variable diff --git a/Detectors/TPC/calibration/include/TPCCalibration/SACDecoder.h b/Detectors/TPC/calibration/include/TPCCalibration/SACDecoder.h index bf8c3bf9e83bf..d16efc8995e8d 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/SACDecoder.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/SACDecoder.h @@ -31,7 +31,6 @@ #include "DataFormatsTPC/SAC.h" using o2::constants::lhc::LHCBunchSpacingMUS; -using std::size_t; namespace o2::tpc::sac { diff --git a/Detectors/TPC/simulation/include/TPCSimulation/Digitizer.h b/Detectors/TPC/simulation/include/TPCSimulation/Digitizer.h index 436fabfc9d620..359dc5d64b72d 100644 --- a/Detectors/TPC/simulation/include/TPCSimulation/Digitizer.h +++ b/Detectors/TPC/simulation/include/TPCSimulation/Digitizer.h @@ -22,8 +22,6 @@ #include -using std::vector; - class TTree; class TH3; diff --git a/Framework/Core/include/Framework/AnalysisDataModel.h b/Framework/Core/include/Framework/AnalysisDataModel.h index 79f6a5e854a2c..e409dba7db9da 100644 --- a/Framework/Core/include/Framework/AnalysisDataModel.h +++ b/Framework/Core/include/Framework/AnalysisDataModel.h @@ -21,8 +21,6 @@ #include "CommonConstants/ZDCConstants.h" #include "SimulationDataFormat/MCGenProperties.h" -using namespace o2::constants::math; - namespace o2 { namespace aod @@ -122,13 +120,13 @@ DECLARE_SOA_COLUMN(Snp, snp, float); //! DECLARE_SOA_COLUMN(Tgl, tgl, float); //! DECLARE_SOA_COLUMN(Signed1Pt, signed1Pt, float); //! (sign of charge)/Pt in c/GeV. Use pt() and sign() instead DECLARE_SOA_EXPRESSION_COLUMN(Phi, phi, float, //! Phi of the track, in radians within [0, 2pi) - ifnode(nasin(aod::track::snp) + aod::track::alpha < 0.0f, nasin(aod::track::snp) + aod::track::alpha + TwoPI, - ifnode(nasin(aod::track::snp) + aod::track::alpha >= TwoPI, nasin(aod::track::snp) + aod::track::alpha - TwoPI, + ifnode(nasin(aod::track::snp) + aod::track::alpha < 0.0f, nasin(aod::track::snp) + aod::track::alpha + o2::constants::math::TwoPI, + ifnode(nasin(aod::track::snp) + aod::track::alpha >= o2::constants::math::TwoPI, nasin(aod::track::snp) + aod::track::alpha - o2::constants::math::TwoPI, nasin(aod::track::snp) + aod::track::alpha))); DECLARE_SOA_EXPRESSION_COLUMN(Eta, eta, float, //! Pseudorapidity - -1.f * nlog(ntan(PIQuarter - 0.5f * natan(aod::track::tgl)))); + -1.f * nlog(ntan(o2::constants::math::PIQuarter - 0.5f * natan(aod::track::tgl)))); DECLARE_SOA_EXPRESSION_COLUMN(Pt, pt, float, //! Transverse momentum of the track in GeV/c - ifnode(nabs(aod::track::signed1Pt) <= Almost0, VeryBig, nabs(1.f / aod::track::signed1Pt))); + ifnode(nabs(aod::track::signed1Pt) <= o2::constants::math::Almost0, o2::constants::math::VeryBig, nabs(1.f / aod::track::signed1Pt))); DECLARE_SOA_DYNAMIC_COLUMN(IsWithinBeamPipe, isWithinBeamPipe, //! Is the track within the beam pipe (= successfully propagated to a collision vertex) [](float x) -> bool { return (std::fabs(x) < o2::constants::geom::XBeamPipeOuterRef); }); DECLARE_SOA_DYNAMIC_COLUMN(Sign, sign, //! Charge: positive: 1, negative: -1 @@ -156,18 +154,18 @@ DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! Momentum in z-direction in GeV/c }); DECLARE_SOA_EXPRESSION_COLUMN(P, p, float, //! Momentum in Gev/c - ifnode(nabs(aod::track::signed1Pt) <= Almost0, VeryBig, 0.5f * (ntan(PIQuarter - 0.5f * natan(aod::track::tgl)) + 1.f / ntan(PIQuarter - 0.5f * natan(aod::track::tgl))) / nabs(aod::track::signed1Pt))); + ifnode(nabs(aod::track::signed1Pt) <= o2::constants::math::Almost0, o2::constants::math::VeryBig, 0.5f * (ntan(o2::constants::math::PIQuarter - 0.5f * natan(aod::track::tgl)) + 1.f / ntan(o2::constants::math::PIQuarter - 0.5f * natan(aod::track::tgl))) / nabs(aod::track::signed1Pt))); DECLARE_SOA_DYNAMIC_COLUMN(Energy, energy, //! Track energy, computed under the mass assumption given as input [](float signed1Pt, float tgl, float mass) -> float { const auto pt = 1.f / std::abs(signed1Pt); - const auto p = 0.5f * (tan(PIQuarter - 0.5f * atan(tgl)) + 1.f / tan(PIQuarter - 0.5f * atan(tgl))) * pt; + const auto p = 0.5f * (tan(o2::constants::math::PIQuarter - 0.5f * atan(tgl)) + 1.f / tan(o2::constants::math::PIQuarter - 0.5f * atan(tgl))) * pt; return sqrt(p * p + mass * mass); }); DECLARE_SOA_DYNAMIC_COLUMN(Rapidity, rapidity, //! Track rapidity, computed under the mass assumption given as input [](float signed1Pt, float tgl, float mass) -> float { const auto pt = 1.f / std::abs(signed1Pt); const auto pz = pt * tgl; - const auto p = 0.5f * (tan(PIQuarter - 0.5f * atan(tgl)) + 1.f / tan(PIQuarter - 0.5f * atan(tgl))) * pt; + const auto p = 0.5f * (tan(o2::constants::math::PIQuarter - 0.5f * atan(tgl)) + 1.f / tan(o2::constants::math::PIQuarter - 0.5f * atan(tgl))) * pt; const auto energy = sqrt(p * p + mass * mass); return 0.5f * log((energy + pz) / (energy - pz)); }); @@ -458,11 +456,11 @@ DECLARE_SOA_COLUMN(TrackTimeRes, trackTimeRes, float); DECLARE_SOA_DYNAMIC_COLUMN(Sign, sign, //! Sign of the track eletric charge [](float signed1Pt) -> short { return (signed1Pt > 0) ? 1 : -1; }); DECLARE_SOA_EXPRESSION_COLUMN(Eta, eta, float, //! - -1.f * nlog(ntan(PIQuarter - 0.5f * natan(aod::fwdtrack::tgl)))); + -1.f * nlog(ntan(o2::constants::math::PIQuarter - 0.5f * natan(aod::fwdtrack::tgl)))); DECLARE_SOA_EXPRESSION_COLUMN(Pt, pt, float, //! ifnode(nabs(aod::fwdtrack::signed1Pt) < o2::constants::math::Almost0, o2::constants::math::VeryBig, nabs(1.f / aod::fwdtrack::signed1Pt))); DECLARE_SOA_EXPRESSION_COLUMN(P, p, float, //! - ifnode((nabs(aod::fwdtrack::signed1Pt) < o2::constants::math::Almost0) || (nabs(PIQuarter - 0.5f * natan(aod::fwdtrack::tgl)) < o2::constants::math::Almost0), o2::constants::math::VeryBig, 0.5f * (ntan(PIQuarter - 0.5f * natan(aod::fwdtrack::tgl)) + 1.f / ntan(PIQuarter - 0.5f * natan(aod::fwdtrack::tgl))) / nabs(aod::fwdtrack::signed1Pt))); + ifnode((nabs(aod::fwdtrack::signed1Pt) < o2::constants::math::Almost0) || (nabs(o2::constants::math::PIQuarter - 0.5f * natan(aod::fwdtrack::tgl)) < o2::constants::math::Almost0), o2::constants::math::VeryBig, 0.5f * (ntan(o2::constants::math::PIQuarter - 0.5f * natan(aod::fwdtrack::tgl)) + 1.f / ntan(o2::constants::math::PIQuarter - 0.5f * natan(aod::fwdtrack::tgl))) / nabs(aod::fwdtrack::signed1Pt))); DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! [](float pt, float phi) -> float { return pt * std::cos(phi); @@ -1360,7 +1358,7 @@ DECLARE_SOA_DYNAMIC_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, //! True if par [](uint8_t flags) -> bool { return (flags & o2::aod::mcparticle::enums::PhysicalPrimary) == o2::aod::mcparticle::enums::PhysicalPrimary; }); DECLARE_SOA_EXPRESSION_COLUMN(Phi, phi, float, //! Phi in the range [0, 2pi) - PI + natan2(-1.0f * aod::mcparticle::py, -1.0f * aod::mcparticle::px)); + o2::constants::math::PI + natan2(-1.0f * aod::mcparticle::py, -1.0f * aod::mcparticle::px)); DECLARE_SOA_EXPRESSION_COLUMN(Eta, eta, float, //! Pseudorapidity, conditionally defined to avoid FPEs ifnode((nsqrt(aod::mcparticle::px * aod::mcparticle::px + aod::mcparticle::py * aod::mcparticle::py + diff --git a/run/SimExamples/McTracksToAOD/mctracks_to_aod_simple_task.cxx b/run/SimExamples/McTracksToAOD/mctracks_to_aod_simple_task.cxx index 8c897712d50bf..e670b25befb40 100644 --- a/run/SimExamples/McTracksToAOD/mctracks_to_aod_simple_task.cxx +++ b/run/SimExamples/McTracksToAOD/mctracks_to_aod_simple_task.cxx @@ -16,6 +16,7 @@ using namespace o2; using namespace o2::framework; +using namespace o2::constants::math; struct AodConsumerTestTask { From 04683d7974d448b4d6c15ac3bf7b5a37a74daab1 Mon Sep 17 00:00:00 2001 From: noferini Date: Wed, 27 Sep 2023 16:55:18 +0200 Subject: [PATCH 156/324] adjust TS size for TOF sync calib --- prodtests/full-system-test/aggregator-workflow.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/prodtests/full-system-test/aggregator-workflow.sh b/prodtests/full-system-test/aggregator-workflow.sh index 10c0e38275319..c87485bf4e6e8 100755 --- a/prodtests/full-system-test/aggregator-workflow.sh +++ b/prodtests/full-system-test/aggregator-workflow.sh @@ -81,11 +81,11 @@ fi : ${INTEGRATEDCURR_TF_PER_SLOT:=150000} # setting for FT0, FV0, FDD and TOF if [[ $BEAMTYPE == "PbPb" ]]; then - : ${LHCPHASE_TF_PER_SLOT:=264} - : ${TOF_CHANNELOFFSETS_UPDATE:=3000} - : ${TOF_CHANNELOFFSETS_DELTA_UPDATE:=500} + : ${LHCPHASE_TF_PER_SLOT:=100000} + : ${TOF_CHANNELOFFSETS_UPDATE:=300000} + : ${TOF_CHANNELOFFSETS_DELTA_UPDATE:=50000} else - : ${LHCPHASE_TF_PER_SLOT:=26400} + : ${LHCPHASE_TF_PER_SLOT:=100000} : ${TOF_CHANNELOFFSETS_UPDATE:=300000} : ${TOF_CHANNELOFFSETS_DELTA_UPDATE:=50000} fi @@ -206,7 +206,7 @@ if [[ $AGGREGATOR_TASKS == BARREL_TF ]] || [[ $AGGREGATOR_TASKS == ALL ]]; then fi fi if [[ $CALIB_TOF_DIAGNOSTICS == 1 ]]; then - add_W o2-calibration-tof-diagnostic-workflow "--tf-per-slot 26400 --max-delay 1" "" 0 + add_W o2-calibration-tof-diagnostic-workflow "--tf-per-slot $LHCPHASE_TF_PER_SLOT --max-delay 1" "" 0 fi # TPC if [[ $CALIB_TPC_SCDCALIB == 1 ]]; then From d9ad5d8f75c0fa9cf052069ab98f1153022efaef Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 27 Sep 2023 14:49:52 +0200 Subject: [PATCH 157/324] GPU: Fix standalone multithreading, policy order check was not enabled --- GPU/Workflow/src/gpu-reco-workflow.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Workflow/src/gpu-reco-workflow.cxx b/GPU/Workflow/src/gpu-reco-workflow.cxx index 1150212451f1b..006785ec02318 100644 --- a/GPU/Workflow/src/gpu-reco-workflow.cxx +++ b/GPU/Workflow/src/gpu-reco-workflow.cxx @@ -179,7 +179,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) Inputs ggInputs; auto ggRequest = std::make_shared(false, true, false, true, true, o2::base::GRPGeomRequest::Aligned, ggInputs, true); - auto task = std::make_shared(&gPolicyData, cfg, tpcSectors, gTpcSectorMask, ggRequest); + auto task = std::make_shared(&gPolicyData, cfg, tpcSectors, gTpcSectorMask, ggRequest, &gPolicyOrderCheck); Inputs taskInputs = task->inputs(); std::move(ggInputs.begin(), ggInputs.end(), std::back_inserter(taskInputs)); gTask = task; From 90b11c9e776c7d5d6ca87ff3ac9d40020162bd51 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 27 Sep 2023 15:13:02 +0200 Subject: [PATCH 158/324] GPU: Delay only processing of async message not receiving, to fill completionPolicyQueue in time and do not deadlock --- GPU/Workflow/src/GPUWorkflowInternal.h | 2 +- GPU/Workflow/src/GPUWorkflowPipeline.cxx | 26 +++++++++++++++--------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/GPU/Workflow/src/GPUWorkflowInternal.h b/GPU/Workflow/src/GPUWorkflowInternal.h index 3a8aa0da54694..513d2ec6f0e28 100644 --- a/GPU/Workflow/src/GPUWorkflowInternal.h +++ b/GPU/Workflow/src/GPUWorkflowInternal.h @@ -84,7 +84,7 @@ struct GPURecoWorkflowSpec_PipelineInternals { std::condition_variable queueNotify; std::queue completionPolicyQueue; - bool pipelineSenderTerminating = false; + volatile bool pipelineSenderTerminating = false; std::mutex completionPolicyMutex; std::condition_variable completionPolicyNotify; diff --git a/GPU/Workflow/src/GPUWorkflowPipeline.cxx b/GPU/Workflow/src/GPUWorkflowPipeline.cxx index 83c96582fca36..c81c5a5478d4e 100644 --- a/GPU/Workflow/src/GPUWorkflowPipeline.cxx +++ b/GPU/Workflow/src/GPUWorkflowPipeline.cxx @@ -283,7 +283,7 @@ void GPURecoWorkflowSpec::RunReceiveThread() do { { std::unique_lock lk(mPipeline->stateMutex); - mPipeline->stateNotify.wait(lk, [this]() { return (mPipeline->runStarted && mPipeline->fmqState == fair::mq::State::Running && !mPipeline->endOfStreamReceived) || mPipeline->shouldTerminate; }); // Do not check mPipeline->fmqDevice->NewStatePending() since we wait for EndOfStream! + mPipeline->stateNotify.wait(lk, [this]() { return (mPipeline->fmqState == fair::mq::State::Running && !mPipeline->endOfStreamReceived) || mPipeline->shouldTerminate; }); // Do not check mPipeline->fmqDevice->NewStatePending() since we wait for EndOfStream! } if (mPipeline->shouldTerminate) { break; @@ -316,6 +316,20 @@ void GPURecoWorkflowSpec::RunReceiveThread() continue; } + { + std::lock_guard lk(mPipeline->completionPolicyMutex); + mPipeline->completionPolicyQueue.emplace(m->timeSliceId); + } + mPipeline->completionPolicyNotify.notify_one(); + + { + std::unique_lock lk(mPipeline->stateMutex); + mPipeline->stateNotify.wait(lk, [this]() { return (mPipeline->runStarted && !mPipeline->endOfStreamReceived) || mPipeline->shouldTerminate; }); + if (!mPipeline->runStarted) { + continue; + } + } + auto context = std::make_unique(); context->timeSliceId = m->timeSliceId; context->tfSettings = m->tfSettings; @@ -358,21 +372,13 @@ void GPURecoWorkflowSpec::RunReceiveThread() if (mPipeline->mNTFReceived++ >= mPipeline->workers.size()) { // Do not inject the first workers.size() TFs, since we need a first round of calib updates from DPL before starting enqueuePipelinedJob(&context->ptrs, nullptr, context.get(), false); } - { - std::lock_guard lk(mPipeline->completionPolicyMutex); - mPipeline->completionPolicyQueue.emplace(m->timeSliceId); - } - mPipeline->completionPolicyNotify.notify_one(); { std::lock_guard lk(mPipeline->queueMutex); mPipeline->pipelineQueue.emplace(std::move(context)); } mPipeline->queueNotify.notify_one(); } - { - std::lock_guard lk(mPipeline->completionPolicyMutex); - mPipeline->pipelineSenderTerminating = true; - } + mPipeline->pipelineSenderTerminating = true; mPipeline->completionPolicyNotify.notify_one(); } From 1035649b23a21b97121baebbf1e5359d3f8c32f6 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 27 Sep 2023 16:01:05 +0200 Subject: [PATCH 159/324] TPC: Fix SectorCompletionPolicy, should retry instead of wait if all inputs present --- .../include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h index 99bb5bc6513d7..33abded35624a 100644 --- a/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h +++ b/Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h @@ -200,7 +200,7 @@ class TPCSectorCompletionPolicy continue; } if (!(**orderCheck)(dph->startTime)) { - retVal = framework::CompletionPolicy::CompletionOp::Wait; + retVal = framework::CompletionPolicy::CompletionOp::Retry; } break; } From 9f8614b9ffecdc0c3fb3efdb9a4203b0f49e2c53 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Thu, 28 Sep 2023 11:23:03 +0200 Subject: [PATCH 160/324] svertexer: bug fix for tpc-only tracks Code did not get a reference to the object in the trackpool but made local copy, thus minR was never modified and left at zero which meant that most if not all tpc-only tracks were rejected in checkV0 due to invaild causality. Signed-off-by: Felix Schlepper --- Detectors/Vertexing/src/SVertexer.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/Vertexing/src/SVertexer.cxx b/Detectors/Vertexing/src/SVertexer.cxx index fda85b7e989fe..b8978a2310a44 100644 --- a/Detectors/Vertexing/src/SVertexer.cxx +++ b/Detectors/Vertexing/src/SVertexer.cxx @@ -1089,7 +1089,7 @@ bool SVertexer::processTPCTrack(const o2::tpc::TrackTPC& trTPC, GIndex gid, int const auto& vtx = mPVertices[vtxid]; auto twe = vtx.getTimeStamp(); int posneg = trTPC.getSign() < 0 ? 1 : 0; - auto trLoc = mTracksPool[posneg].emplace_back(TrackCand{trTPC, gid, {vtxid, vtxid}, 0.}); + auto& trLoc = mTracksPool[posneg].emplace_back(TrackCand{trTPC, gid, {vtxid, vtxid}, 0.}); auto err = correctTPCTrack(trLoc, trTPC, twe.getTimeStamp(), twe.getTimeStampError()); if (err < 0) { mTracksPool[posneg].pop_back(); // discard From 81786f2b8aeca4c7e6ffb071afd522877e92230d Mon Sep 17 00:00:00 2001 From: Roman Lietava Date: Thu, 28 Sep 2023 18:08:50 +0200 Subject: [PATCH 161/324] ctpdevL input scalers (#11970) * dev: scaler inputs dinished and tools * clang --- .../CTP/include/DataFormatsCTP/Scalers.h | 6 +- DataFormats/Detectors/CTP/src/Scalers.cxx | 72 +++++++++++++++++-- Detectors/CTP/macro/GetScalers.C | 23 +++--- 3 files changed, 87 insertions(+), 14 deletions(-) diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h index 85c9d30fef2f7..526e79f00f65d 100644 --- a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Scalers.h @@ -105,6 +105,8 @@ class CTPRunScalers uint32_t getRunNUmber() { return mRunNumber; }; int printRates(); int printIntegrals(); + int printInputRateAndIntegral(int inp); + int printClassBRateAndIntegral(int icls); // // static constexpr uint32_t NCOUNTERS = 1052; // v1 @@ -146,10 +148,10 @@ class CTPRunScalers std::vector mScalerRecordRaw; std::vector mScalerRecordO2; int processScalerLine(const std::string& line, int& level, int& nclasses); - int copyRawToO2ScalerRecord(const CTPScalerRecordRaw& rawrec, CTPScalerRecordO2& o2rec, overflows_t& classesoverflows); + int copyRawToO2ScalerRecord(const CTPScalerRecordRaw& rawrec, CTPScalerRecordO2& o2rec, overflows_t& classesoverflows, std::array& overflows); int updateOverflows(const CTPScalerRecordRaw& rec0, const CTPScalerRecordRaw& rec1, overflows_t& classesoverflows) const; int updateOverflows(const CTPScalerRaw& scal0, const CTPScalerRaw& scal1, std::array& overflow) const; - + int updateOverflowsInps(const CTPScalerRecordRaw& rec0, const CTPScalerRecordRaw& rec1, std::array& overflow) const; ClassDefNV(CTPRunScalers, 2); }; } // namespace ctp diff --git a/DataFormats/Detectors/CTP/src/Scalers.cxx b/DataFormats/Detectors/CTP/src/Scalers.cxx index 900645416fe52..ca313bccf6fdb 100644 --- a/DataFormats/Detectors/CTP/src/Scalers.cxx +++ b/DataFormats/Detectors/CTP/src/Scalers.cxx @@ -65,6 +65,7 @@ void CTPScalerRecordRaw::printStream(std::ostream& stream) const for (auto const& cnts : scalers) { cnts.printStream(stream); } + std::cout << "Inputs:" << scalersInps.size() << std::endl; for (auto const& dets : scalersInps) { stream << dets << " "; } @@ -77,6 +78,7 @@ void CTPScalerRecordO2::printStream(std::ostream& stream) const for (auto const& cnts : scalers) { cnts.printStream(stream); } + std::cout << "Inputs:" << scalersInps.size() << std::endl; for (auto const& dets : scalersInps) { stream << dets << " "; } @@ -273,10 +275,12 @@ int CTPRunScalers::convertRawToO2() overflows[i] = {0, 0, 0, 0, 0, 0}; } } + // Input overflows + std::array overflowsInputs = {48 * 0}; errorCounters eCnts; // 1st o2 rec is just copy CTPScalerRecordO2 o2rec; - copyRawToO2ScalerRecord(mScalerRecordRaw[0], o2rec, overflows); + copyRawToO2ScalerRecord(mScalerRecordRaw[0], o2rec, overflows, overflowsInputs); mScalerRecordO2.push_back(o2rec); int j = 1; for (uint32_t i = 1; i < mScalerRecordRaw.size(); i++) { @@ -285,7 +289,8 @@ int CTPRunScalers::convertRawToO2() // if (ret == 0) { CTPScalerRecordO2 o2rec; - copyRawToO2ScalerRecord(mScalerRecordRaw[i], o2rec, overflows); + ret = updateOverflowsInps(mScalerRecordRaw[i - 1], mScalerRecordRaw[i], overflowsInputs); + copyRawToO2ScalerRecord(mScalerRecordRaw[i], o2rec, overflows, overflowsInputs); mScalerRecordO2.push_back(o2rec); // Check consistency checkConsistency(mScalerRecordO2[j - 1], mScalerRecordO2[j], eCnts); @@ -295,7 +300,7 @@ int CTPRunScalers::convertRawToO2() eCnts.printStream(std::cout); return 0; } -int CTPRunScalers::copyRawToO2ScalerRecord(const CTPScalerRecordRaw& rawrec, CTPScalerRecordO2& o2rec, overflows_t& classesoverflows) +int CTPRunScalers::copyRawToO2ScalerRecord(const CTPScalerRecordRaw& rawrec, CTPScalerRecordO2& o2rec, overflows_t& classesoverflows, std::array& overflows) { if (rawrec.scalers.size() != (mClassMask.count())) { LOG(error) << "Inconsistent scaler record size:" << rawrec.scalers.size() << " Expected:" << mClassMask.count(); @@ -313,6 +318,10 @@ int CTPRunScalers::copyRawToO2ScalerRecord(const CTPScalerRecordRaw& rawrec, CTP o2scal.createCTPScalerO2FromRaw(rawscal, classesoverflows[k]); o2rec.scalers.push_back(o2scal); } + for (int i = 0; i < rawrec.scalersInps.size(); i++) { + uint64_t inpo2 = (uint64_t)(rawrec.scalersInps[i]) + 0xffffffffull * (uint64_t)(overflows[i]); + o2rec.scalersInps.push_back(inpo2); + } return 0; } int CTPRunScalers::checkConsistency(const CTPScalerO2& scal0, const CTPScalerO2& scal1, errorCounters& eCnts) const @@ -452,6 +461,26 @@ int CTPRunScalers::updateOverflows(const CTPScalerRaw& scal0, const CTPScalerRaw //std::cout << std::endl; return 0; } +// +int CTPRunScalers::updateOverflowsInps(const CTPScalerRecordRaw& rec0, const CTPScalerRecordRaw& rec1, std::array& overflow) const +{ + int NINPS = 48; + if (rec0.scalersInps.size() < NINPS) { + LOG(error) << "updateOverflowsInps.size < 48:" << rec0.scalersInps.size(); + return 1; + } + if (rec1.scalersInps.size() < NINPS) { + LOG(error) << "updateOverflowsInps.size < 48:" << rec1.scalersInps.size(); + return 2; + } + for (int i = 0; i < NINPS; i++) { + if (rec0.scalersInps[i] > rec1.scalersInps[i]) { + overflow[i] += 1; + } + } + return 0; +} +// int CTPRunScalers::printRates() { if (mScalerRecordO2.size() == 0) { @@ -507,7 +536,42 @@ int CTPRunScalers::printIntegrals() } return 0; } - +// +// Input counting 1..48 +int CTPRunScalers::printInputRateAndIntegral(int inp) +{ + if (mScalerRecordO2.size() == 0) { + LOG(info) << "ScalerRecord is empty, doing nothing"; + return 1; + } + double_t time0 = mScalerRecordO2[0].epochTime; + double_t timeL = mScalerRecordO2[mScalerRecordO2.size() - 1].epochTime; + int integral = mScalerRecordO2[mScalerRecordO2.size() - 1].scalersInps[inp - 1] - mScalerRecordO2[0].scalersInps[inp - 1]; + std::cout << "Scaler Integrals for run:" << mRunNumber << " duration:" << timeL - time0; + std::cout << " Input " << inp << " integral:" << integral << " rate:" << integral / (timeL - time0) << std::endl; + return 0; +} +// Prints class before counters for lumi +// Class counting 1..64 +int CTPRunScalers::printClassBRateAndIntegral(int icls) +{ + if (mScalerRecordO2.size() == 0) { + LOG(info) << "ScalerRecord is empty, doing nothing"; + return 1; + } + double_t time0 = mScalerRecordO2[0].epochTime; + double_t timeL = mScalerRecordO2[mScalerRecordO2.size() - 1].epochTime; + if (mScalerRecordO2[0].scalers.size() < icls) { + LOG(error) << "class number bigger than expected for this run:" << icls << "expexted smaller than:" << mScalerRecordO2[0].scalers.size(); + return 1; + } else { + int integral = mScalerRecordO2[mScalerRecordO2.size() - 1].scalers[icls - 1].lmBefore - mScalerRecordO2[0].scalers[icls - 1].lmBefore; + std::cout << "Scaler Integrals for run:" << mRunNumber << " duration:" << timeL - time0; + std::cout << " Class " << icls << " integral:" << integral << " rate:" << integral / (timeL - time0) << std::endl; + } + return 0; +} +// void CTPRunScalers::printLMBRateVsT() const { for (int i = 1; i < mScalerRecordO2.size(); i++) { // loop over time diff --git a/Detectors/CTP/macro/GetScalers.C b/Detectors/CTP/macro/GetScalers.C index 7cc13c03356eb..05fce0b657f5a 100644 --- a/Detectors/CTP/macro/GetScalers.C +++ b/Detectors/CTP/macro/GetScalers.C @@ -42,15 +42,22 @@ void GetScalers(std::string srun, long time, std::string ccdbHost = "http://ccdb // return; scl = mng.getScalersFromCCDB(time, srun, ok); if (ok == 1) { + scl.printStream(std::cout); scl.convertRawToO2(); - scl.printO2(std::cout); - scl.printFromZero(std::cout); - scl.printIntegrals(); - scl.printRates(); - // std::vector clsses; - // clsses = ctpcfg.getTriggerClassList(); - // std::cout << clsses.size() << std::endl; - // for(auto const& i : clsses) std::cout << i << std::endl; + // scl.printO2(std::cout); + // scl.printFromZero(std::cout); + // scl.printIntegrals(); + // scl.printRates(); + std::cout << "TVX,TSC,TCE,ZNC:" << std::endl; + scl.printInputRateAndIntegral(3); + scl.printInputRateAndIntegral(4); + scl.printInputRateAndIntegral(5); + scl.printInputRateAndIntegral(26); + std::cout << " TVX,TVX&TCE,TVX&TSC,TVX&VCH:" << std::endl; + scl.printClassBRateAndIntegral(3); + scl.printClassBRateAndIntegral(4); + scl.printClassBRateAndIntegral(5); + scl.printClassBRateAndIntegral(6); } else { std::cout << "Can not find run, please, check parameters" << std::endl; } From 8f1c9bbbec2854383a709102821b6b61c11b8234 Mon Sep 17 00:00:00 2001 From: shahoian Date: Wed, 27 Sep 2023 15:52:21 +0200 Subject: [PATCH 162/324] Disable strangeness tracking in pbpb (on in pp) by default --- prodtests/full-system-test/dpl-workflow.sh | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 07ef905a339b8..b9ac2d4027710 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -90,6 +90,8 @@ CTP_CONFIG= : ${ITSEXTRAERR:=} : ${TRACKTUNETPCINNER:=} : ${ITSTPC_CONFIG_KEY:=} +: ${AOD_INPUT:=$TRACK_SOURCES} +: ${AODPROD_OPT:=} [[ "0$DISABLE_ROOT_OUTPUT" == "00" ]] && DISABLE_ROOT_OUTPUT= @@ -143,12 +145,17 @@ fi if [[ $BEAMTYPE == "PbPb" ]]; then PVERTEXING_CONFIG_KEY+="pvertexer.maxChi2TZDebris=2000;" + : ${STRTRACKING:=" --disable-strangeness-tracker "} + AODPROD_OPT+=" --disable-strangeness-tracking " elif [[ $BEAMTYPE == "pp" ]]; then PVERTEXING_CONFIG_KEY+="pvertexer.maxChi2TZDebris=10;" + : ${STRTRACKING:=" "} fi if [[ $BEAMTYPE == "cosmic" ]]; then [[ -z ${ITS_CONFIG+x} ]] && ITS_CONFIG=" --tracking-mode cosmics" + : ${STRTRACKING:=" --disable-strangeness-tracker "} + AODPROD_OPT+=" --disable-strangeness-tracking " elif [[ $SYNCMODE == 1 ]]; then [[ -z ${ITS_CONFIG+x} ]] && ITS_CONFIG=" --tracking-mode sync" else @@ -496,10 +503,11 @@ has_detector_reco MCH && ( [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output ( [[ $BEAMTYPE == "cosmic" ]] || ! has_detector_reco ITS) && PVERTEX_CONFIG+=" --skip" has_detector_matching PRIMVTX && [[ ! -z "$VERTEXING_SOURCES" ]] && add_W o2-primary-vertexing-workflow "$DISABLE_MC $DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $PVERTEX_CONFIG --pipeline $(get_N primary-vertexing MATCH REST 1 PRIMVTX),$(get_N pvertex-track-matching MATCH REST 1 PRIMVTXMATCH)" "${PVERTEXING_CONFIG_KEY}" -if [[ $BEAMTYPE != "cosmic" ]]; then - : ${STRTRACKING:="--disable-strangeness-tracker"} - has_detectors_reco ITS && has_detector_matching SECVTX && has_detector_matching && STRTRACKING="" - has_detectors_reco ITS && has_detector_matching SECVTX && [[ ! -z "$SVERTEXING_SOURCES" ]] && add_W o2-secondary-vertexing-workflow "$DISABLE_MC $STRTRACKING $DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $TPC_CORR_SCALING --vertexing-sources $SVERTEXING_SOURCES --threads $SVERTEX_THREADS --pipeline $(get_N secondary-vertexing MATCH REST $SVERTEX_THREADS SECVTX)" +if [[ $BEAMTYPE != "cosmic" ]] && has_detectors_reco ITS && has_detector_matching SECVTX && [[ ! -z "$SVERTEXING_SOURCES" ]]; then + add_W o2-secondary-vertexing-workflow "$DISABLE_MC $STRTRACKING $DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $TPC_CORR_SCALING --vertexing-sources $SVERTEXING_SOURCES --threads $SVERTEX_THREADS --pipeline $(get_N secondary-vertexing MATCH REST $SVERTEX_THREADS SECVTX)" + SECTVTX_ON="1" +else + SECTVTX_ON="0" fi # --------------------------------------------------------------------------------------------------------------------- @@ -557,11 +565,7 @@ workflow_has_parameter GPU_DISPLAY && [[ $NUMAID == 0 ]] && add_W o2-gpu-display # --------------------------------------------------------------------------------------------------------------------- # AOD -: ${AOD_INPUT:=$TRACK_SOURCES} -: ${AODPROD_OPT:=} -( ! has_detector_matching SECVTX || ! has_detectors_reco ITS || [[ $BEAMTYPE == "cosmic" ]]) && AODPROD_OPT+=" --disable-secondary-vertices" -( ! has_detector_matching STRK || ! has_detector_matching SECVTX || ! has_detectors_reco ITS || [[ $BEAMTYPE == "cosmic" ]]) && AODPROD_OPT+=" --disable-strangeness-tracking" - +[[ ${SECTVTX_ON:-} != "1" ]] && AODPROD_OPT+=" --disable-secondary-vertices " workflow_has_parameter AOD && [[ ! -z "$AOD_INPUT" ]] && add_W o2-aod-producer-workflow "$AODPROD_OPT --info-sources $AOD_INPUT $DISABLE_ROOT_INPUT --aod-writer-keep dangling --aod-writer-resfile \"AO2D\" --aod-writer-resmode UPDATE $DISABLE_MC --pipeline $(get_N aod-producer-workflow AOD REST 1 AODPROD)" # --------------------------------------------------------------------------------------------------------------------- From 89a58a4404195fa1d876fc3708fdd8519ae615f6 Mon Sep 17 00:00:00 2001 From: swenzel Date: Wed, 27 Sep 2023 11:29:32 +0200 Subject: [PATCH 163/324] AODProducer: Code cleanup and optimization * use std::pair for CTP ClassMasks instead of std::vector. * avoid mem alloc which not necessary * initialize at declaration and reduce else statements --- Detectors/AOD/src/AODProducerWorkflowSpec.cxx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index 6b25286e504d0..f9dcccd0029fb 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -2111,7 +2111,7 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) fillStrangenessTrackingTables(recoData, trackedV0Cursor, trackedCascadeCursor, tracked3BodyCurs); // helper map for fast search of a corresponding class mask for a bc - std::unordered_map> bcToClassMask; + std::unordered_map> bcToClassMask; if (mInputSources[GID::CTP]) { LOG(debug) << "CTP input available"; for (auto& ctpDigit : ctpDigits) { @@ -2124,7 +2124,7 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) } // filling BC table - std::vector masks; + std::pair masks{0, 0}; bcCursor.reserve(bcsMap.size()); for (auto& item : bcsMap) { uint64_t bc = item.first; @@ -2132,16 +2132,12 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) auto bcClassPair = bcToClassMask.find(bc); if (bcClassPair != bcToClassMask.end()) { masks = bcClassPair->second; - } else { - masks = {0, 0}; } - } else { - masks = {0, 0}; } bcCursor(runNumber, bc, - masks[0], - masks[1]); + masks.first, + masks.second); } bcToClassMask.clear(); From f7de0aac5abada43fbaf3eda43dde237cbdae930 Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Tue, 9 May 2023 14:57:28 +0200 Subject: [PATCH 164/324] [EMCAL-918] Handling corrupted trailer words Corrupted trailer words are words with the trailer marker but an invalid trailer word code, for which the trailer word type cannot be determined. Handled in the RawReaderMemory as MinorRawDataError (non- crashing) --- .../EMCAL/base/include/EMCALBase/RCUTrailer.h | 5 ++ Detectors/EMCAL/base/src/RCUTrailer.cxx | 4 +- .../EMCALReconstruction/RawDecodingError.h | 15 ++++-- .../EMCALReconstruction/RawReaderMemory.h | 50 ++++++++++++++++++- .../reconstruction/src/RawReaderMemory.cxx | 5 +- .../test/testRawDecodingError.cxx | 30 +++++------ .../EMCALWorkflow/RawToCellConverterSpec.h | 3 ++ .../workflow/src/RawToCellConverterSpec.cxx | 20 ++++++++ 8 files changed, 111 insertions(+), 21 deletions(-) diff --git a/Detectors/EMCAL/base/include/EMCALBase/RCUTrailer.h b/Detectors/EMCAL/base/include/EMCALBase/RCUTrailer.h index 8723a7a68264b..ca82e60aa33ab 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/RCUTrailer.h +++ b/Detectors/EMCAL/base/include/EMCALBase/RCUTrailer.h @@ -153,6 +153,10 @@ class RCUTrailer /// \return Size of the payload as number of 32 bit workds uint32_t getPayloadSize() const { return mPayloadSize; } + /// \brief Get number of corrupted trailer words (undefined trailer word code) + /// \return Number of trailer word corruptions + uint32_t getTrailerWordCorruptions() const { return mWordCorruptions; } + /// \brief Get the firmware version /// \return Firmware version uint8_t getFirmwareVersion() const { return mFirmwareVersion; } @@ -438,6 +442,7 @@ class RCUTrailer uint8_t mFirmwareVersion = 0; ///< RCU firmware version uint32_t mTrailerSize = 0; ///< Size of the trailer (in number of 32 bit words) uint32_t mPayloadSize = 0; ///< Size of the payload (in nunber of 32 bit words) + uint32_t mWordCorruptions = 0; ///< Number of trailer word corruptions (decoding only) uint32_t mFECERRA = 0; ///< contains errors related to ALTROBUS transactions uint32_t mFECERRB = 0; ///< contains errors related to ALTROBUS transactions ErrorCounters mErrorCounter = {0, 0}; ///< Error counter registers diff --git a/Detectors/EMCAL/base/src/RCUTrailer.cxx b/Detectors/EMCAL/base/src/RCUTrailer.cxx index 8ab06d7a90bd9..7cc54f188bc33 100644 --- a/Detectors/EMCAL/base/src/RCUTrailer.cxx +++ b/Detectors/EMCAL/base/src/RCUTrailer.cxx @@ -14,6 +14,7 @@ #include #include "CommonConstants/LHCConstants.h" #include "EMCALBase/RCUTrailer.h" +#include using namespace o2::emcal; @@ -94,7 +95,8 @@ void RCUTrailer::constructFromRawPayload(const gsl::span payload mAltroConfig.mWord2 = parData & 0x1FFFFFF; break; default: - std::cerr << "Undefined parameter code " << parCode << ", ignore it !\n"; + LOG(warning) << "RCU trailer: Undefined parameter code " << parCode << " in word " << index << " (0x" << std::hex << word << std::dec << "), ignoring word"; + mWordCorruptions++; break; } } diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawDecodingError.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawDecodingError.h index 58f57d53a4441..7d68b7bb7a03f 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawDecodingError.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawDecodingError.h @@ -44,7 +44,8 @@ class RawDecodingError : public std::exception HEADER_INVALID, ///< Header in memory not belonging to requested superpage PAGE_START_INVALID, ///< Page position starting outside payload size PAYLOAD_INVALID, ///< Payload in memory not belonging to requested superpage - TRAILER_DECODING ///< Inconsistent trailer in memory (several trailer words missing the trailer marker) + TRAILER_DECODING, ///< Inconsistent trailer in memory (several trailer words missing the trailer marker) + TRAILER_INCOMPLETE ///< Incomplete trailer words (i.e. registers) }; /// \brief Constructor @@ -93,6 +94,8 @@ class RawDecodingError : public std::exception return 5; case ErrorType_t::TRAILER_DECODING: return 6; + case ErrorType_t::TRAILER_INCOMPLETE: + return 7; }; // can never reach this, due to enum class // just to make Werror happy @@ -101,7 +104,7 @@ class RawDecodingError : public std::exception /// \brief Get the number of error codes /// \return Number of error codes - static constexpr int getNumberOfErrorTypes() { return 7; } + static constexpr int getNumberOfErrorTypes() { return 8; } static ErrorType_t intToErrorType(unsigned int errortype) { @@ -109,7 +112,7 @@ class RawDecodingError : public std::exception static constexpr std::array errortypes = {{ErrorType_t::PAGE_NOTFOUND, ErrorType_t::HEADER_DECODING, ErrorType_t::PAYLOAD_DECODING, ErrorType_t::HEADER_INVALID, ErrorType_t::PAGE_START_INVALID, ErrorType_t::PAYLOAD_INVALID, - ErrorType_t::TRAILER_DECODING}}; + ErrorType_t::TRAILER_DECODING, ErrorType_t::TRAILER_INCOMPLETE}}; return errortypes[errortype]; } @@ -137,6 +140,8 @@ class RawDecodingError : public std::exception return "PayloadCorruption"; case ErrorType_t::TRAILER_DECODING: return "TrailerDecoding"; + case ErrorType_t::TRAILER_INCOMPLETE: + return "TrailerIncomplete"; }; return "Undefined error"; } @@ -177,6 +182,8 @@ class RawDecodingError : public std::exception return "Payload corruption"; case ErrorType_t::TRAILER_DECODING: return "Trailer decoding"; + case ErrorType_t::TRAILER_INCOMPLETE: + return "Trailer incomplete"; }; return "Undefined error"; } @@ -217,6 +224,8 @@ class RawDecodingError : public std::exception return "Access to payload not belonging to requested superpage"; case ErrorType_t::TRAILER_DECODING: return "Inconsistent trailer in memory"; + case ErrorType_t::TRAILER_INCOMPLETE: + return "Incomplete trailer"; }; return "Undefined error"; } diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawReaderMemory.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawReaderMemory.h index 843bda5f8398b..463fe4981b7cf 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawReaderMemory.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawReaderMemory.h @@ -11,11 +11,13 @@ #ifndef ALICEO2_EMCAL_RAWREADERMEMORY_H #define ALICEO2_EMCAL_RAWREADERMEMORY_H +#include #include #include #include "EMCALBase/RCUTrailer.h" #include "EMCALReconstruction/RawBuffer.h" +#include "EMCALReconstruction/RawDecodingError.h" #include "EMCALReconstruction/RawPayload.h" #include "Headers/RAWDataHeader.h" #include "Headers/RDHAny.h" @@ -36,6 +38,46 @@ namespace emcal class RawReaderMemory { public: + /// \class MinorError + /// \brief Minor (non-crashing) raw decoding errors + /// + /// Minor errors share the same codes as major raw decoding errors, + /// however are not crashing. + class MinorError + { + public: + /// \brief Dummy constructor + MinorError() = default; + + /// \brief Main constructor + /// \param errortype Type of the error + /// \param feeID ID of the FEE equipment + MinorError(RawDecodingError::ErrorType_t errortype, int feeID) : mErrorType(errortype), mFEEID(feeID) {} + + /// \brief Destructor + ~MinorError() = default; + + /// \brief Set the type of the error + /// \param errortype Type of the error + void setErrorType(RawDecodingError::ErrorType_t errortype) { mErrorType = errortype; } + + /// \brief Set the ID of the FEE equipment + /// \param feeID ID of the FEE + void setFEEID(int feeID) { mFEEID = feeID; } + + /// \brief Get type of the error + /// \return Type of the error + RawDecodingError::ErrorType_t getErrorType() const { return mErrorType; } + + /// \brief Get ID of the FEE + /// \return ID of the FEE + int getFEEID() const { return mFEEID; } + + private: + RawDecodingError::ErrorType_t mErrorType; ///< Type of the error + int mFEEID; ///< ID of the FEC responsible for the ERROR + }; + /// \brief Constructor RawReaderMemory(const gsl::span rawmemory); @@ -58,8 +100,7 @@ class RawReaderMemory /// \brief Read next payload from the stream /// /// Read the next pages until the stop bit is found. - void - next(); + void next(); /// \brief Read the next page from the stream (single DMA page) /// \param resetPayload If true the raw payload is reset @@ -85,6 +126,10 @@ class RawReaderMemory /// \return Raw Payload of the data until the stop bit is received. const RawPayload& getPayload() const { return mRawPayload; } + /// \brief Get minor (non-crashing) raw decoding errors + /// \return Minor raw decoding errors + gsl::span getMinorErrors() const { return mMinorErrors; } + /// \brief Return size of the payload /// \return size of the payload int getPayloadSize() const { return mRawPayload.getPayloadSize(); } @@ -123,6 +168,7 @@ class RawReaderMemory int mCurrentFEE = -1; ///< Current FEE in the data stream bool mRawHeaderInitialized = false; ///< RDH for current page initialized bool mPayloadInitialized = false; ///< Payload for current page initialized + std::vector mMinorErrors; ///< Minor raw decoding errors ClassDefNV(RawReaderMemory, 1); }; diff --git a/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx b/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx index a9f15b3adeeb4..7f247eee2fbba 100644 --- a/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx +++ b/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx @@ -12,7 +12,6 @@ #include #include #include "EMCALReconstruction/RawReaderMemory.h" -#include "EMCALReconstruction/RawDecodingError.h" #include "DetectorsRaw/RDHUtils.h" using namespace o2::emcal; @@ -51,6 +50,7 @@ void RawReaderMemory::next() { mRawPayload.reset(); mCurrentTrailer.reset(); + mMinorErrors.clear(); bool isDataTerminated = false; do { nextPage(false); @@ -150,6 +150,9 @@ void RawReaderMemory::nextPage(bool doResetPayload) mCurrentTrailer.setPayloadSize(mCurrentTrailer.getPayloadSize() + trailer.getPayloadSize()); } payloadWithoutTrailer = gsl::span(mRawBuffer.getDataWords().data(), mRawBuffer.getDataWords().size() - trailer.getTrailerSize()); + if (trailer.getTrailerWordCorruptions()) { + mMinorErrors.emplace_back(RawDecodingError::ErrorType_t::TRAILER_INCOMPLETE, mCurrentFEE); + } } catch (RCUTrailer::Error& e) { throw RawDecodingError(RawDecodingError::ErrorType_t::TRAILER_DECODING, mCurrentFEE); } diff --git a/Detectors/EMCAL/reconstruction/test/testRawDecodingError.cxx b/Detectors/EMCAL/reconstruction/test/testRawDecodingError.cxx index 87004f88c09a1..02b0d8addb031 100644 --- a/Detectors/EMCAL/reconstruction/test/testRawDecodingError.cxx +++ b/Detectors/EMCAL/reconstruction/test/testRawDecodingError.cxx @@ -28,37 +28,39 @@ void testThrow(RawDecodingError::ErrorType_t errtype, unsigned int feeID) BOOST_AUTO_TEST_CASE(RawDecodingError_test) { - BOOST_CHECK_EQUAL(RawDecodingError::getNumberOfErrorTypes(), 7); - std::array errornames = {{"PageNotFound", + BOOST_CHECK_EQUAL(RawDecodingError::getNumberOfErrorTypes(), 8); + std::array errornames = {{"PageNotFound", "HeaderDecoding", "PayloadDecoding", "HeaderCorruption", "PageStartInvalid", "PayloadCorruption", - "TrailerDecoding"}}, + "TrailerDecoding", + "TrailerIncomplete"}}, errortitles = {{"Page not found", "Header decoding", "Payload decoding", "Header corruption", "Page start invalid", "Payload corruption", - "Trailer decoding"}}, + "Trailer decoding", + "Trailer incomplete"}}, errordescriptions = {{"Page with requested index not found", "RDH of page cannot be decoded", "Payload of page cannot be decoded", "Access to header not belonging to requested superpage", "Page decoding starting outside payload size", "Access to payload not belonging to requested superpage", - "Inconsistent trailer in memory"}}; - std::array errortypes = {{ - RawDecodingError::ErrorType_t::PAGE_NOTFOUND, - RawDecodingError::ErrorType_t::HEADER_DECODING, - RawDecodingError::ErrorType_t::PAYLOAD_DECODING, - RawDecodingError::ErrorType_t::HEADER_INVALID, - RawDecodingError::ErrorType_t::PAGE_START_INVALID, - RawDecodingError::ErrorType_t::PAYLOAD_INVALID, - RawDecodingError::ErrorType_t::TRAILER_DECODING, - }}; + "Inconsistent trailer in memory", + "Incomplete trailer"}}; + std::array errortypes = {{RawDecodingError::ErrorType_t::PAGE_NOTFOUND, + RawDecodingError::ErrorType_t::HEADER_DECODING, + RawDecodingError::ErrorType_t::PAYLOAD_DECODING, + RawDecodingError::ErrorType_t::HEADER_INVALID, + RawDecodingError::ErrorType_t::PAGE_START_INVALID, + RawDecodingError::ErrorType_t::PAYLOAD_INVALID, + RawDecodingError::ErrorType_t::TRAILER_DECODING, + RawDecodingError::ErrorType_t::TRAILER_INCOMPLETE}}; for (int errortype = 0; errortype < RawDecodingError::getNumberOfErrorTypes(); errortype++) { BOOST_CHECK_EQUAL(RawDecodingError::ErrorTypeToInt(errortypes[errortype]), errortype); BOOST_CHECK_EQUAL(RawDecodingError::intToErrorType(errortype), errortypes[errortype]); diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h index ee07bb4c282e4..a90a0f1718397 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h @@ -25,6 +25,7 @@ #include "EMCALBase/Geometry.h" #include "EMCALBase/Mapper.h" #include "EMCALReconstruction/CaloRawFitter.h" +#include "EMCALReconstruction/RawReaderMemory.h" #include "EMCALReconstruction/RecoContainer.h" #include "EMCALReconstruction/ReconstructionErrors.h" #include "EMCALWorkflow/CalibLoader.h" @@ -236,6 +237,8 @@ class RawToCellConverterSpec : public framework::Task void handlePageError(const RawDecodingError& e); + void handleMinorPageError(const RawReaderMemory::MinorError& e); + header::DataHeader::SubSpecificationType mSubspecification = 0; ///< Subspecification for output channels int mNoiseThreshold = 0; ///< Noise threshold in raw fit int mNumErrorMessages = 0; ///< Current number of error messages diff --git a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx index f2833afb0d230..d1ec38537d4c3 100644 --- a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx +++ b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx @@ -168,6 +168,10 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) // the page format does not follow the expected format continue; } + for (auto& e : rawreader.getMinorErrors()) { + handleMinorPageError(e); + // For minor errors we do not need to skip the page, just print and send the error to the QC + } auto& header = rawreader.getRawHeader(); auto triggerBC = raw::RDHUtils::getTriggerBC(header); @@ -691,6 +695,22 @@ void RawToCellConverterSpec::handlePageError(const RawDecodingError& e) } } +void RawToCellConverterSpec::handleMinorPageError(const RawReaderMemory::MinorError& e) +{ + if (mCreateRawDataErrors) { + mOutputDecoderErrors.emplace_back(e.getFEEID(), ErrorTypeFEE::ErrorSource_t::PAGE_ERROR, RawDecodingError::ErrorTypeToInt(e.getErrorType()), -1, -1); + } + if (mNumErrorMessages < mMaxErrorMessages) { + LOG(warning) << " Page decoding: " << RawDecodingError::getErrorCodeDescription(e.getErrorType()) << " in FEE ID " << e.getFEEID(); + mNumErrorMessages++; + if (mNumErrorMessages == mMaxErrorMessages) { + LOG(warning) << "Max. amount of error messages (" << mMaxErrorMessages << " reached, further messages will be suppressed"; + } + } else { + mErrorMessagesSuppressed++; + } +} + void RawToCellConverterSpec::sendData(framework::ProcessingContext& ctx, const std::vector& cells, const std::vector& triggers, const std::vector& decodingErrors) const { constexpr auto originEMC = o2::header::gDataOriginEMC; From 396d881ae16d676b350053d370d016044367ce4d Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Thu, 28 Sep 2023 11:51:34 +0200 Subject: [PATCH 165/324] [EMCAL-1045] Skip FMQ payload in case of corrupted RDH In case RDH header decoding fails the offset to the next page cannot be reliably determined, consequently the payload needs to be skipped. Other errors are kept as minor errors and only the page is skipped. --- Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx index d1ec38537d4c3..cebbd69eef947 100644 --- a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx +++ b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx @@ -147,7 +147,6 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) std::vector filter{{"filter", framework::ConcreteDataTypeMatcher(originEMC, descRaw)}}; int firstEntry = 0; for (const auto& rawData : framework::InputRecordWalker(ctx.inputs(), filter)) { - // Skip SOX headers auto rdhblock = reinterpret_cast(rawData.payload); if (o2::raw::RDHUtils::getHeaderSize(rdhblock) == static_cast(o2::framework::DataRefUtils::getPayloadSize(rawData))) { @@ -163,6 +162,11 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) rawreader.next(); } catch (RawDecodingError& e) { handlePageError(e); + if (e.getErrorType() == RawDecodingError::ErrorType_t::HEADER_DECODING || e.getErrorType() == RawDecodingError::ErrorType_t::HEADER_INVALID) { + // We must break in case of header decoding as the offset to the next payload is lost + // consequently the parser does not know where to continue leading to an infinity loop + break; + } // We must skip the page as payload is not consistent // otherwise the next functions will rethrow the exceptions as // the page format does not follow the expected format From 19633b454c0fb469eb781264a7e30447210660d5 Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Thu, 28 Sep 2023 11:59:38 +0200 Subject: [PATCH 166/324] [EMCAL-534] Remove message about missing trailer word from AltroDecoder The message is handled in the RawToCellConverter and pass to the raw error QC, handling in the AltroDecoder is legacy and became rather confusing to the shift crew. --- Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx b/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx index e1b1294a6349d..1e0cdfc36003d 100644 --- a/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx +++ b/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx @@ -42,7 +42,6 @@ void AltroDecoder::readRCUTrailer() gsl::span payloadwords(payloadwordsOrig.data(), payloadwordsOrig.size()); mRCUTrailer.constructFromRawPayload(payloadwords); } catch (RCUTrailer::Error& e) { - LOG(error) << "Error while decoding RCU trailer: " << e.what(); throw AltroDecoderError(AltroDecoderError::ErrorType_t::RCU_TRAILER_ERROR, fmt::format("{} {}", AltroDecoderError::getErrorTypeDescription(AltroDecoderError::ErrorType_t::RCU_TRAILER_ERROR), e.what())); } } From befad7dbdbc80db90e0249623eebeac25036dfc0 Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Thu, 28 Sep 2023 13:20:35 +0200 Subject: [PATCH 167/324] [EMCAL-834] Discard only events instead of TF in link checker Only reject those events that have missing links within a timeframe, and keep events which have all links. For events rejected add an empty TriggerRecord with additional trigger bit masking incompletes as rejected. --- .../include/DataFormatsEMCAL/Constants.h | 5 ++ .../include/DataFormatsEMCAL/TriggerRecord.h | 5 +- .../Detectors/EMCAL/src/TriggerRecord.cxx | 7 +++ .../workflow/src/RawToCellConverterSpec.cxx | 55 ++++++++++--------- 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Constants.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Constants.h index 103a9419b5e08..72eb2a9e272b9 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Constants.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Constants.h @@ -103,6 +103,11 @@ constexpr int MAX_RANGE_ADC = 0x3FF; ///< Dynamic range of the ADCs (1 constexpr double EMCAL_TRU_ADCENERGY = 0.0786; ///< resolution of the TRU digitizer, @TODO check exact value } // namespace constants +namespace triggerbits +{ +constexpr uint32_t Inc = 0x1 << 20; ///< trigger bit marking incomplete event +} + enum FitAlgorithm { Standard = 0, ///< Standard raw fitter Gamma2 = 1, ///< Gamma2 raw fitter diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/TriggerRecord.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/TriggerRecord.h index a7e1f72ca1baf..1529eff104400 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/TriggerRecord.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/TriggerRecord.h @@ -61,8 +61,9 @@ class TriggerRecord /// \enum TriggerBitsCoded_t /// \brief Position of trigger classes in compressed format enum TriggerBitsCoded_t { - PHYSTRIGGER, ///< Physics trigger - CALIBTRIGGER ///< Calib trigger + PHYSTRIGGER, ///< Physics trigger + CALIBTRIGGER, ///< Calib trigger + REJECTINCOMPLETE ///< Rejected as incomplete }; BCData mBCData; /// Bunch crossing data of the trigger DataRange mDataRange; /// Index of the triggering event (event index and first entry in the container) diff --git a/DataFormats/Detectors/EMCAL/src/TriggerRecord.cxx b/DataFormats/Detectors/EMCAL/src/TriggerRecord.cxx index f380b944f807d..7ca716dbb4ea2 100644 --- a/DataFormats/Detectors/EMCAL/src/TriggerRecord.cxx +++ b/DataFormats/Detectors/EMCAL/src/TriggerRecord.cxx @@ -13,6 +13,7 @@ #include #include "DataFormatsEMCAL/TriggerRecord.h" #include "CommonConstants/Triggers.h" +#include "DataFormatsEMCAL/Constants.h" namespace o2 { @@ -29,6 +30,9 @@ uint16_t TriggerRecord::getTriggerBitsCompressed() const if (mTriggerBits & o2::trigger::Cal) { result |= 1 << TriggerBitsCoded_t::CALIBTRIGGER; } + if (mTriggerBits & o2::emcal::triggerbits::Inc) { + result |= 1 << TriggerBitsCoded_t::REJECTINCOMPLETE; + } return result; } @@ -41,6 +45,9 @@ void TriggerRecord::setTriggerBitsCompressed(uint16_t triggerbits) if (triggerbits & (1 << TriggerBitsCoded_t::CALIBTRIGGER)) { mTriggerBits |= o2::trigger::Cal; } + if (triggerbits & (1 << TriggerBitsCoded_t::REJECTINCOMPLETE)) { + mTriggerBits |= o2::emcal::triggerbits::Inc; + } } void TriggerRecord::printStream(std::ostream& stream) const diff --git a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx index cebbd69eef947..06778a40166c4 100644 --- a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx +++ b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx @@ -338,6 +338,7 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) } } + std::bitset<46> bitSetActiveLinks; if (mActiveLinkCheck) { // build expected active mask from DCS FeeDCS* feedcs = mCalibHandler->getFEEDCS(); @@ -347,32 +348,7 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) list0.set(21, false); list1.set(7, false); // must be 0x307FFFDFFFFF if all links are active - std::bitset<46> bitSetActiveLinks((list1.to_ullong() << 32) + list0.to_ullong()); - - // Check if we have received pages from all active links - // If not we cannot trust the timeframe and must send - // empty containers - bool hasMissingLinks = false; - for (const auto& [globalBC, activelinks] : bcFreq) { - if (activelinks != bitSetActiveLinks) { - hasMissingLinks = true; - LOG(error) << "Not all EMC active links contributed in global BCid=" << globalBC << ": mask=" << (activelinks ^ bitSetActiveLinks); - if (mCreateRawDataErrors) { - for (std::size_t ilink = 0; ilink < bitSetActiveLinks.size(); ilink++) { - if (!bitSetActiveLinks.test(ilink)) { - continue; - } - if (!activelinks.test(ilink)) { - mOutputDecoderErrors.emplace_back(ilink, ErrorTypeFEE::ErrorSource_t::LINK_ERROR, 0, -1, -1); - } - } - } - } - } - if (hasMissingLinks) { - sendData(ctx, mOutputCells, mOutputTriggerRecords, mOutputDecoderErrors); - return; - } + bitSetActiveLinks = std::bitset<46>((list1.to_ullong() << 32) + list0.to_ullong()); } // Loop over BCs, sort cells with increasing tower ID and write to output containers @@ -381,6 +357,32 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) int ncellsEvent = 0, nLEDMONsEvent = 0; int eventstart = mOutputCells.size(); auto& currentevent = eventIterator.nextEvent(); + const auto interaction = currentevent.getInteractionRecord(); + if (mActiveLinkCheck) { + // check for current event if all links are present + // discard event if not all links are present + auto bcfreqFound = bcFreq.find(interaction.toLong()); + if (bcfreqFound != bcFreq.end()) { + const auto& activelinks = bcfreqFound->second; + if (activelinks != bitSetActiveLinks) { + LOG(error) << "Not all EMC active links contributed in global BCid=" << interaction.toLong() << ": mask=" << (activelinks ^ bitSetActiveLinks); + if (mCreateRawDataErrors) { + for (std::size_t ilink = 0; ilink < bitSetActiveLinks.size(); ilink++) { + if (!bitSetActiveLinks.test(ilink)) { + continue; + } + if (!activelinks.test(ilink)) { + mOutputDecoderErrors.emplace_back(ilink, ErrorTypeFEE::ErrorSource_t::LINK_ERROR, 0, -1, -1); + } + } + } + // discard event + // create empty trigger record with dedicated trigger bit marking as rejected + mOutputTriggerRecords.emplace_back(interaction, currentevent.getTriggerBits() | o2::emcal::triggerbits::Inc, eventstart, 0); + continue; + } + } + } // Add cells if (currentevent.getNumberOfCells()) { LOG(debug) << "Event has " << currentevent.getNumberOfCells() << " cells"; @@ -393,7 +395,6 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) currentevent.sortCells(true); nLEDMONsEvent = bookEventCells(currentevent.getLEDMons(), true); } - const auto interaction = currentevent.getInteractionRecord(); LOG(debug) << "Next event [Orbit " << interaction.orbit << ", BC (" << interaction.bc << "]: Accepted " << ncellsEvent << " cells and " << nLEDMONsEvent << " LEDMONS"; mOutputTriggerRecords.emplace_back(interaction, currentevent.getTriggerBits(), eventstart, ncellsEvent + nLEDMONsEvent); } From ecc6f7049ca9a78394d7bae62ee50af0b9ed8136 Mon Sep 17 00:00:00 2001 From: noferini Date: Fri, 29 Sep 2023 15:16:38 +0200 Subject: [PATCH 168/324] fix in TOF matcher for calib --- Detectors/GlobalTracking/src/MatchTOF.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/Detectors/GlobalTracking/src/MatchTOF.cxx b/Detectors/GlobalTracking/src/MatchTOF.cxx index 5d09e96951ff2..81492a6fd7ae5 100644 --- a/Detectors/GlobalTracking/src/MatchTOF.cxx +++ b/Detectors/GlobalTracking/src/MatchTOF.cxx @@ -1187,8 +1187,6 @@ void MatchTOF::doMatchingForTPC(int sec) //______________________________________________ int MatchTOF::findFITIndex(int bc, const gsl::span& FITRecPoints, unsigned long firstOrbit) { - bc -= o2::tof::Geo::LATENCYWINDOW_IN_BC; - if (FITRecPoints.size() == 0) { return -1; } From 5278410f8ede9cf862b360144aaf7c75e6835c2e Mon Sep 17 00:00:00 2001 From: Fabrizio Grosa Date: Thu, 28 Sep 2023 11:13:38 +0200 Subject: [PATCH 169/324] [ITS3] Implement small fixes for ITS3 geometry --- Detectors/ITSMFT/ITS/simulation/src/Detector.cxx | 4 ++-- Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx b/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx index 7989568db80fc..05c3818032aa0 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx +++ b/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx @@ -662,12 +662,12 @@ void Detector::createMaterials() // ERG Duocel o2::base::Detector::Material(39, "ERGDUOCEL$", 12.0107, 6, 0.06, 999, 999); - o2::base::Detector::Medium(39, "ERGDUOCEL$", 33, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + o2::base::Detector::Medium(39, "ERGDUOCEL$", 39, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); // Impregnated carbon fleece // (as educated guess we assume 50% carbon fleece 50% Araldite glue) o2::base::Detector::Material(40, "IMPREG_FLEECE$", 12.0107, 6, 0.5 * (dAraldite + 0.4), 999, 999); - o2::base::Detector::Medium(40, "IMPREG_FLEECE$", 34, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); + o2::base::Detector::Medium(40, "IMPREG_FLEECE$", 40, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi); } void Detector::EndOfEvent() { Reset(); } diff --git a/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx b/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx index 8ab06105e00c5..774b600ac3a09 100644 --- a/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx +++ b/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx @@ -68,7 +68,7 @@ void ITS3Layer::createLayer(TGeoVolume* motherVolume, double radiusBetweenLayer) TGeoVolume* volHalfLayer[nElements - 1]; for (int iEl{0}; iEl < nElements - 1; ++iEl) { TGeoMedium* med = (iEl <= 2) ? medSi : medAir; - if (iEl == 4) { + if (iEl == 3) { halfLayer[iEl] = new TGeoTubeSeg(rmin, rmax + radiusBetweenLayer, mZLen / 2, phiGap, piDeg - phiGap); volHalfLayer[iEl] = new TGeoVolume(names[iEl].data(), halfLayer[iEl], med); createCarbonFoamStructure(volHalfLayer[iEl], radiusBetweenLayer); @@ -180,7 +180,7 @@ void ITS3Layer::createLayerWithDeadZones(TGeoVolume* motherVolume, double radius } else { volHalfLayer[iEl] = new TGeoVolume(names[iEl].data(), halfLayer[iEl][0], med); volHalfLayer[iEl]->SetUniqueID(mChipTypeID); - if (iEl == 4) { + if (iEl == 3) { createCarbonFoamStructure(volHalfLayer[iEl], radiusBetweenLayer); volHalfLayer[iEl]->SetVisibility(true); volHalfLayer[iEl]->SetLineColor(kGray + 2); From b3c76bac223107e63e441442e956fe5f55907c88 Mon Sep 17 00:00:00 2001 From: swenzel Date: Wed, 27 Sep 2023 11:19:11 +0200 Subject: [PATCH 170/324] Disable simulation shared mem on APPLE Does no longer compile with XCode15 and in any case never worked correctly. --- Common/Utils/include/CommonUtils/ShmManager.h | 2 +- Common/Utils/src/ShmManager.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/Utils/include/CommonUtils/ShmManager.h b/Common/Utils/include/CommonUtils/ShmManager.h index ff288675db642..9b2029df658fd 100644 --- a/Common/Utils/include/CommonUtils/ShmManager.h +++ b/Common/Utils/include/CommonUtils/ShmManager.h @@ -26,7 +26,7 @@ #include #include -#if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) +#if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) && !defined(__APPLE__) // this shared mem mode is meant for compiled stuff in o2-sim; not for ROOT sessions #define USESHM 1 #endif diff --git a/Common/Utils/src/ShmManager.cxx b/Common/Utils/src/ShmManager.cxx index cb3af5dedf380..26b30be062220 100644 --- a/Common/Utils/src/ShmManager.cxx +++ b/Common/Utils/src/ShmManager.cxx @@ -119,8 +119,8 @@ bool ShmManager::createGlobalSegment(int nsegments) return false; } - LOG(info) << "CREATING SIM SHARED MEM SEGMENT FOR " << nsegments << " WORKERS"; #ifdef USESHM + LOG(info) << "CREATING SIM SHARED MEM SEGMENT FOR " << nsegments << " WORKERS"; // LOG(info) << "SIZEOF ShmMetaInfo " << sizeof(ShmMetaInfo); const auto totalsize = sizeof(ShmMetaInfo) + SHMPOOLSIZE * nsegments; if ((mShmID = shmget(IPC_PRIVATE, totalsize, IPC_CREAT | 0666)) == -1) { From 3097678f7a41f8b11fce9ecc324653e481990d16 Mon Sep 17 00:00:00 2001 From: mwinn2 Date: Fri, 6 Jan 2023 11:25:24 +0100 Subject: [PATCH 171/324] added getPitch for DEDigitizer calc. average position sync with mch_hit_improvements_4 fix cherrypick restore header Clang clang clang fixes Philippe typo --- .../include/MCHSimulation/Response.h | 18 ++++++++++ .../MUON/MCH/Simulation/src/DEDigitizer.cxx | 20 +++++++++-- .../MUON/MCH/Simulation/src/Response.cxx | 35 +++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h index 03b30778f7c11..c9c46a846f2ea 100644 --- a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h +++ b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h @@ -34,6 +34,7 @@ class Response ~Response() = default; float getChargeSpread() const { return mChargeSpread; } + float getPitch() const { return mPitch; } float getSigmaIntegration() const { return mSigmaIntegration; } bool isAboveThreshold(float charge) const { return charge > mChargeThreshold; } @@ -64,6 +65,21 @@ class Response /// compute the number of samples corresponding to the charge in ADC units uint32_t nSamples(float charge) const; + /// Ratio of particle mean eloss with respect MIP's Khalil Boudjemline, sep 2003, PhD.Thesis and Particle Data Book + float eLossRatio(float logbetagamma) const; + /// ToDo: check Aliroot formula vs PDG, if really log_10 and not ln or bug in Aliroot + + /// Angle effect in tracking chambers at theta =10 degres as a function of ElossRatio (Khalil BOUDJEMLINE sep 2003 Ph.D Thesis) (in micrometers) + float angleEffect10(float elossratio) const; + + /// Angle effect: Normalisation form theta=10 degres to theta between 0 and 10 (Khalil BOUDJEMLINE sep 2003 Ph.D Thesis) + /// Angle with respect to the wires assuming that chambers are perpendicular to the z axis. + float angleEffectNorma(float elossratio) const; + + /// Magnetic field effect: Normalisation form theta=16 degres (eq. 10 degrees B=0) to theta between -20 and 20 (Lamia Benhabib jun 2006 ) + /// Angle with respect to the wires assuming that chambers are perpendicular to the z axis. + float magAngleEffectNorma(float angle, float bfield) const; + private: MathiesonOriginal mMathieson{}; ///< Mathieson function float mPitch = 0.f; ///< anode-cathode pitch (cm) @@ -72,6 +88,8 @@ class Response float mSigmaIntegration = 0.f; ///< number of sigmas used for charge distribution float mChargeCorr = 0.f; ///< amplitude of charge correlation between cathodes float mChargeThreshold = 0.f; ///< minimum fraction of charge considered + bool mAngleEffect = true; ///< switch for angle effect influencing charge deposition + bool mMagnetEffect = true; ///< switch for magnetic field influencing charge deposition }; } // namespace mch } // namespace o2 diff --git a/Detectors/MUON/MCH/Simulation/src/DEDigitizer.cxx b/Detectors/MUON/MCH/Simulation/src/DEDigitizer.cxx index 8d0988b76a7e6..7cb6814226555 100644 --- a/Detectors/MUON/MCH/Simulation/src/DEDigitizer.cxx +++ b/Detectors/MUON/MCH/Simulation/src/DEDigitizer.cxx @@ -56,9 +56,25 @@ void DEDigitizer::processHit(const Hit& hit, const InteractionRecord& collisionT auto chargeNonBending = charge / chargeCorr; // local position of the charge distribution - math_utils::Point3D pos(hit.GetX(), hit.GetY(), hit.GetZ()); + auto exitPoint = hit.exitPoint(); + auto entrancePoint = hit.entrancePoint(); + math_utils::Point3D lexit{}; + math_utils::Point3D lentrance{}; + mTransformation.MasterToLocal(exitPoint, lexit); + mTransformation.MasterToLocal(entrancePoint, lentrance); + + auto hitlengthZ = lentrance.Z() - lexit.Z(); + auto pitch = mResponse.getPitch(); + math_utils::Point3D lpos{}; - mTransformation.MasterToLocal(pos, lpos); + + if (abs(hitlengthZ) > pitch * 1.99) { + lpos.SetXYZ((lexit.X() + lentrance.X()) / 2., (lexit.Y() + lentrance.Y()) / 2., (lexit.Z() + lentrance.Z()) / 2.); + } else { + lpos.SetXYZ(lexit.X(), // take Bragg peak coordinates assuming electron drift parallel to z + lexit.Y(), // take Bragg peak coordinates assuming electron drift parallel to z + 0.0); // take wire position global coordinate negative + } auto localX = mResponse.getAnod(lpos.X()); auto localY = lpos.Y(); diff --git a/Detectors/MUON/MCH/Simulation/src/Response.cxx b/Detectors/MUON/MCH/Simulation/src/Response.cxx index 985b8d5575234..5c990284eee71 100644 --- a/Detectors/MUON/MCH/Simulation/src/Response.cxx +++ b/Detectors/MUON/MCH/Simulation/src/Response.cxx @@ -89,3 +89,38 @@ uint32_t Response::nSamples(float charge) const double signalParam[3] = {14., 13., 1.5}; return std::round(std::pow(charge / signalParam[1], 1. / signalParam[2]) + signalParam[0]); } +//_____________________________________________________________________ +float Response::eLossRatio(float logbetagamma) const +{ + // Ratio of particle mean eloss with respect MIP's Khalil Boudjemline, sep 2003, PhD.Thesis and Particle Data Book + /// copied from aliroot AliMUONv1.cxx + float eLossRatioParam[5] = {1.02138, -9.54149e-02, +7.83433e-02, -9.98208e-03, +3.83279e-04}; + return eLossRatioParam[0] + eLossRatioParam[1] * logbetagamma + eLossRatioParam[2] * std::pow(logbetagamma, 2) + eLossRatioParam[3] * std::pow(logbetagamma, 3) + eLossRatioParam[4] * std::pow(logbetagamma, 4); +} +//_____________________________________________________________________ +float Response::angleEffect10(float elossratio) const +{ + /// Angle effect in tracking chambers at theta =10 degres as a function of ElossRatio (Khalil BOUDJEMLINE sep 2003 Ph.D Thesis) (in micrometers) + /// copied from aliroot AliMUONv1.cxx + float angleEffectParam[3] = {1.90691e+02, -6.62258e+01, 1.28247e+01}; + return angleEffectParam[0] + angleEffectParam[1] * elossratio + angleEffectParam[2] * std::pow(elossratio, 2); +} +//_____________________________________________________________________ +float Response::angleEffectNorma(float elossratio) const +{ + /// Angle effect: Normalisation form theta=10 degres to theta between 0 and 10 (Khalil BOUDJEMLINE sep 2003 Ph.D Thesis) + /// Angle with respect to the wires assuming that chambers are perpendicular to the z axis. + /// copied from aliroot AliMUONv1.cxx + float angleEffectParam[4] = {4.148, -6.809e-01, 5.151e-02, -1.490e-03}; + return angleEffectParam[0] + angleEffectParam[1] * elossratio + angleEffectParam[2] * std::pow(elossratio, 2) + angleEffectParam[3] * std::pow(elossratio, 3); +} +//_____________________________________________________________________ +float Response::magAngleEffectNorma(float angle, float bfield) const +{ + /// Magnetic field effect: Normalisation form theta=16 degres (eq. 10 degrees B=0) to theta between -20 and 20 (Lamia Benhabib jun 2006 ) + /// Angle with respect to the wires assuming that chambers are perpendicular to the z axis. + /// copied from aliroot AliMUONv1.cxx + float angleEffectParam[7] = {8.6995, 25.4022, 13.8822, 2.4717, 1.1551, -0.0624, 0.0012}; + float aux = std::abs(angle - angleEffectParam[0] * bfield); + return 121.24 / ((angleEffectParam[1] + angleEffectParam[2] * std::abs(bfield)) + angleEffectParam[3] * aux + angleEffectParam[4] * std::pow(aux, 2) + angleEffectParam[5] * std::pow(aux, 3) + angleEffectParam[6] * std::pow(aux, 4)); +} From 651d27fd0f34adddfba07aeeeb5ade7a413b8d72 Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 29 Sep 2023 21:48:53 +0200 Subject: [PATCH 172/324] Stop CTFreader asap to avoid empty run cycle --- Detectors/CTF/workflow/src/CTFReaderSpec.cxx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx index e105dabc3b58c..13f78afd57ff9 100644 --- a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx @@ -195,10 +195,6 @@ void CTFReaderSpec::run(ProcessingContext& pc) mInput.tfRateLimit = std::stoi(pc.services().get().device()->fConfig->GetValue("timeframes-rate-limit")); } std::string tfFileName; - if (mCTFCounter >= mInput.maxTFs || (!mInput.ctfIDs.empty() && mSelIDEntry >= mInput.ctfIDs.size())) { // done - LOG(info) << "All CTFs from selected range were injected, stopping"; - mRunning = false; - } while (mRunning) { if (mCTFTree) { // there is a tree open with multiple CTF @@ -228,6 +224,14 @@ void CTFReaderSpec::run(ProcessingContext& pc) LOG(info) << "Reading CTF input " << ' ' << tfFileName; openCTFFile(tfFileName); } + + if (mCTFCounter >= mInput.maxTFs || (!mInput.ctfIDs.empty() && mSelIDEntry >= mInput.ctfIDs.size())) { // done + LOG(info) << "All CTFs from selected range were injected, stopping"; + mRunning = false; + } else if (mRunning && !mCTFTree && mFileFetcher->getNextFileInQueue().empty()) { // previous tree was done, can we read more? + mRunning = false; + } + if (!mRunning) { pc.services().get().endOfStream(); pc.services().get().readyToQuit(QuitRequest::Me); From 3df9451b9abf017abd36f350a5082a7bfd10ee09 Mon Sep 17 00:00:00 2001 From: Francesco Mazzaschi <43742195+fmazzasc@users.noreply.github.com> Date: Sat, 30 Sep 2023 15:26:40 +0200 Subject: [PATCH 173/324] Strangeness tracking: tighter cut on grid granularity (#11979) * Strangeness tracking: tighter cut on grid granularity * Please consider the following formatting changes --------- Co-authored-by: ALICE Action Bot --- .../include/StrangenessTracking/IndexTableUtils.h | 2 +- .../StrangenessTracking/StrangenessTrackingConfigParam.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/IndexTableUtils.h b/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/IndexTableUtils.h index bfa2362155983..e7ae53d8f4d55 100644 --- a/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/IndexTableUtils.h +++ b/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/IndexTableUtils.h @@ -27,7 +27,7 @@ struct IndexTableUtils { int getPhiBin(float phi); int getBinIndex(float eta, float phi); std::vector getBinRect(float eta, float phi, float deltaEta, float deltaPhi); - int mEtaBins = 64, mPhiBins = 64; + int mEtaBins = 128, mPhiBins = 128; float minEta = -1.5, maxEta = 1.5; float minPhi = 0., maxPhi = 2 * TMath::Pi(); }; diff --git a/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/StrangenessTrackingConfigParam.h b/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/StrangenessTrackingConfigParam.h index bc4ef7a8637a4..3b0226dbcdba7 100644 --- a/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/StrangenessTrackingConfigParam.h +++ b/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/StrangenessTrackingConfigParam.h @@ -27,8 +27,8 @@ struct StrangenessTrackingParamConfig : public o2::conf::ConfigurableParamHelper // parameters float mRadiusTolIB = .3; // Radius tolerance for matching V0s in the IB float mRadiusTolOB = .1; // Radius tolerance for matching V0s in the OB - float mPhiBinSize = 0.1; // Phi bin size for the matching grid - float mEtaBinSize = 0.1; // Eta bin size for the matching grid + float mPhiBinSize = 0.02; // Phi bin size for the matching grid + float mEtaBinSize = 0.01; // Eta bin size for the matching grid float mMinMotherClus = 3.; // minimum number of cluster to be attached to the mother float mMaxChi2 = 50; // Maximum matching chi2 bool mVertexMatching = true; // Flag to enable/disable vertex matching From dad2a17d1c9761e625ae2a42c2c4d6064325ea0c Mon Sep 17 00:00:00 2001 From: shahoian Date: Sat, 30 Sep 2023 14:06:20 +0200 Subject: [PATCH 174/324] Fix CTP entropy encoder to handle dummy lumi inputs --- Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx b/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx index 3e51226b687c4..7ad4f821c12a9 100644 --- a/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx @@ -50,9 +50,19 @@ void EntropyEncoderSpec::run(ProcessingContext& pc) mTimer.Start(false); mCTFCoder.updateTimeDependentParams(pc, true); auto digits = pc.inputs().get>("digits"); + static LumiInfo lumiPrev; + const int maxDumRep = 5; + int dumRep = 0; LumiInfo lumi{}; if (!mNoLumi) { - lumi = pc.inputs().get("CTPLumi"); + if (pc.inputs().get>("CTPLumi").size() == sizeof(LumiInfo)) { + lumiPrev = lumi = pc.inputs().get("CTPLumi"); + } else { + if (dumRep < maxDumRep && lumiPrev.nHBFCounted == 0 && lumiPrev.nHBFCountedFV0 == 0) { + LOGP(alarm, "Previous TF lumi used to substitute dummy input is empty, warning {} of {}", ++dumRep, maxDumRep); + } + lumi = lumiPrev; + } } auto& buffer = pc.outputs().make>(Output{"CTP", "CTFDATA", 0, Lifetime::Timeframe}); auto iosize = mCTFCoder.encode(buffer, digits, lumi); From 0d253968eb1465b7da8c61b61d852b7f45dc289e Mon Sep 17 00:00:00 2001 From: shahoian Date: Sat, 30 Sep 2023 14:40:29 +0200 Subject: [PATCH 175/324] Protect CorrectionMapsLoader against dummy LumiInfo --- .../TPC/calibration/src/CorrectionMapsLoader.cxx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx b/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx index ae955a1ef312b..48426044bec87 100644 --- a/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx +++ b/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx @@ -42,8 +42,19 @@ void CorrectionMapsLoader::extractCCDBInputs(ProcessingContext& pc) { pc.inputs().get("tpcCorrMap"); pc.inputs().get("tpcCorrMapRef"); // not used at the moment + const int maxDumRep = 5; + int dumRep = 0; + o2::ctp::LumiInfo lumiObj; + static o2::ctp::LumiInfo lumiPrev; if (getUseCTPLumi() && mInstLumiOverride <= 0.) { - auto lumiObj = pc.inputs().get("CTPLumi"); + if (pc.inputs().get>("CTPLumi").size() == sizeof(o2::ctp::LumiInfo)) { + lumiPrev = lumiObj = pc.inputs().get("CTPLumi"); + } else { + if (dumRep < maxDumRep && lumiPrev.nHBFCounted == 0 && lumiPrev.nHBFCountedFV0 == 0) { + LOGP(alarm, "Previous TF lumi used to substitute dummy input is empty, warning {} of {}", ++dumRep, maxDumRep); + } + lumiObj = lumiPrev; + } setInstLumi(mInstLumiFactor * (mCTPLumiSource == 0 ? lumiObj.getLumi() : lumiObj.getLumiAlt())); } } From 340cfa59602d555650e204123a3101a40880aa47 Mon Sep 17 00:00:00 2001 From: shahoian Date: Sat, 30 Sep 2023 15:01:29 +0200 Subject: [PATCH 176/324] Protect RecoContainer against empty LumiInfo input --- DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx index 257d43089b9b6..4c244b61bc5f8 100644 --- a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx +++ b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx @@ -1122,7 +1122,9 @@ void RecoContainer::addMIDClusters(ProcessingContext& pc, bool mc) void RecoContainer::addCTPDigits(ProcessingContext& pc, bool mc) { commonPool[GTrackID::CTP].registerContainer(pc.inputs().get>("CTPDigits"), CLUSTERS); - mCTPLumi = pc.inputs().get("CTPLumi"); + if (pc.inputs().get>("CTPLumi").size() == sizeof(o2::ctp::LumiInfo)) { + mCTPLumi = pc.inputs().get("CTPLumi"); + } if (mc) { // pc.inputs().get*>("CTPDigitsMC"); } From 2ff6fbf985e4e4002519ce0cd0958fc82e5dba01 Mon Sep 17 00:00:00 2001 From: freidt Date: Sat, 30 Sep 2023 19:20:00 +0200 Subject: [PATCH 177/324] ALPIDE event decoding: added FLUSHED_INCOMPLETE and STROBE_EXTENDED (#11988) * ALPIDE event decoding: added errors for FLUSHED_INCOMPLETE and STROBE_EXTENDED * Please consider the following formatting changes --------- Co-authored-by: ALICE Action Bot --- .../include/ITSMFTReconstruction/AlpideCoder.h | 6 ++++++ .../include/ITSMFTReconstruction/DecodingStat.h | 10 ++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h index f36473b2c7899..663f7dfaf958a 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h @@ -89,6 +89,8 @@ class AlpideCoder static constexpr uint8_t MaskErrBusyViolation = 0x1 << 3; static constexpr uint8_t MaskErrDataOverrun = 0x3 << 2; static constexpr uint8_t MaskErrFatal = 0x7 << 1; + static constexpr uint8_t MaskErrFlushedIncomplete = 0x1 << 2; + static constexpr uint8_t MaskErrStrobeExtended = 0x1 << 1; static constexpr uint32_t MaskTimeStamp = 0xff; // Time stamps as BUNCH_COUNTER[10:3] bits static constexpr uint32_t MaskReserved = 0xff; // mask for reserved byte static constexpr uint32_t MaskHitMap = 0x7f; // mask for hit map: at most 7 hits in bits (0:6) @@ -133,6 +135,10 @@ class AlpideCoder chipData.setError(ChipStat::DataOverrun); } else if (roErr == MaskErrFatal) { chipData.setError(ChipStat::Fatal); + } else if (roErr == MaskErrFlushedIncomplete) { + chipData.setError(ChipStat::FlushedIncomplete); + } else if (roErr == MaskErrStrobeExtended) { + chipData.setError(ChipStat::StrobeExtended); } #endif }; diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DecodingStat.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DecodingStat.h index 9843b1b0e2a40..e983cec3e26f7 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DecodingStat.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DecodingStat.h @@ -65,6 +65,8 @@ struct ChipStat { InterleavedChipData, // Chip data interleaved on the cable TruncatedBuffer, // truncated buffer, 0 padding TrailerAfterHeader, // trailer seen after header w/o FE of FD set + FlushedIncomplete, // ALPIDE MEB was flushed by the busy handling + StrobeExtended, // ALPIDE received a second trigger while the strobe was still open NErrorsDefined }; @@ -99,7 +101,9 @@ struct ChipStat { "DColumns non-increasing", // DColumns non increasing "Chip data interleaved on the cable", // Chip data interleaved on the cable "TruncatedBuffer", // truncated buffer, 0 padding - "TrailerAfterHeader" // trailer seen after header w/o FE of FD set + "TrailerAfterHeader", // trailer seen after header w/o FE of FD set + "FlushedIncomplete", // ALPIDE MEB was flushed by the busy handling + "StrobeExtended" // ALPIDE received a second trigger while the strobe was still open }; static constexpr std::array ErrActions = { @@ -133,7 +137,9 @@ struct ChipStat { ErrActPropagate | ErrActDump, // DColumns non increasing ErrActPropagate | ErrActDump, // Chip data interleaved on the cable ErrActPropagate | ErrActDump, // Truncated buffer while something was expected - ErrActPropagate | ErrActDump // trailer seen after header w/o FE of FD set + ErrActPropagate | ErrActDump, // trailer seen after header w/o FE of FD set + ErrActPropagate | ErrActDump, // ALPIDE MEB was flushed by the busy handling + ErrActPropagate | ErrActDump // ALPIDE received a second trigger while the strobe was still open }; uint16_t feeID = -1; size_t nHits = 0; From 27ad4d8ee887172e4f6f9f18b3cbd0d11782140a Mon Sep 17 00:00:00 2001 From: shahoian Date: Sat, 30 Sep 2023 21:32:52 +0200 Subject: [PATCH 178/324] add tpc-triggers to tpc-reco when root output is requested --- prodtests/full-system-test/dpl-workflow.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index b9ac2d4027710..e5590a6497ccd 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -461,7 +461,7 @@ has_detector_reco TRD && ! has_detector_from_global_reader TRD && add_W o2-trd-t has_detectors_reco ITS TPC && has_detector_matching ITSTPC && add_W o2-tpcits-match-workflow "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $SEND_ITSTPC_DTGL $TPC_CORR_SCALING --nthreads $ITSTPC_THREADS --pipeline $(get_N itstpc-track-matcher MATCH REST $ITSTPC_THREADS TPCITS)" "$ITSTPC_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" has_detector_reco TRD && [[ ! -z "$TRD_SOURCES" ]] && add_W o2-trd-global-tracking "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TRD_CONFIG $TRD_FILTER_CONFIG $TPC_CORR_SCALING --track-sources $TRD_SOURCES --pipeline $(get_N trd-globaltracking_TPC_ITS-TPC_ TRD REST 1 TRDTRK),$(get_N trd-globaltracking_TPC_FT0_ITS-TPC_ TRD REST 1 TRDTRK)" "$TRD_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" has_detector_reco TOF && [[ ! -z "$TOF_SOURCES" ]] && add_W o2-tof-matcher-workflow "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TPC_CORR_SCALING --track-sources $TOF_SOURCES --pipeline $(get_N tof-matcher TOF REST 1 TOFMATCH)" "$ITSMFT_STROBES;$ITSEXTRAERR" -has_detectors TPC && [[ -z "$DISABLE_ROOT_OUTPUT" && "${SKIP_TPC_CLUSTERSTRACKS_OUTPUT:-}" != 1 ]] && add_W o2-tpc-reco-workflow "--input-type pass-through --output-type clusters,tracks,send-clusters-per-sector $DISABLE_MC" +has_detectors TPC && [[ -z "$DISABLE_ROOT_OUTPUT" && "${SKIP_TPC_CLUSTERSTRACKS_OUTPUT:-}" != 1 ]] && add_W o2-tpc-reco-workflow "--input-type pass-through --output-type clusters,tpc-triggers,tracks,send-clusters-per-sector $DISABLE_MC" # --------------------------------------------------------------------------------------------------------------------- # Reconstruction workflows normally active only in async mode in async mode ($LIST_OF_ASYNC_RECO_STEPS), but can be forced via $WORKFLOW_EXTRA_PROCESSING_STEPS From 8259cd3ca661350db7881de264838d41c3251cbc Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Fri, 29 Sep 2023 13:47:56 +0200 Subject: [PATCH 179/324] TPC: add option to not sample first n TFs --- Detectors/TPC/workflow/src/MIPTrackFilterSpec.cxx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Detectors/TPC/workflow/src/MIPTrackFilterSpec.cxx b/Detectors/TPC/workflow/src/MIPTrackFilterSpec.cxx index 6be5977e42717..6c90bfc86b536 100644 --- a/Detectors/TPC/workflow/src/MIPTrackFilterSpec.cxx +++ b/Detectors/TPC/workflow/src/MIPTrackFilterSpec.cxx @@ -52,6 +52,7 @@ class MIPTrackFilterDevice : public Task unsigned int mProcessEveryNthTF{1}; ///< process every Nth TF only int mMaxTracksPerTF{-1}; ///< max number of MIP tracks processed per TF uint32_t mTFCounter{0}; ///< counter to keep track of the TFs + int mProcessNFirstTFs{0}; ///< number of first TFs which are not sampled }; void MIPTrackFilterDevice::init(framework::InitContext& ic) @@ -70,6 +71,7 @@ void MIPTrackFilterDevice::init(framework::InitContext& ic) if (mProcessEveryNthTF <= 0) { mProcessEveryNthTF = 1; } + mProcessNFirstTFs = ic.options().get("process-first-n-TFs"); if (mProcessEveryNthTF > 1) { std::mt19937 rng(std::time(nullptr)); @@ -87,8 +89,8 @@ void MIPTrackFilterDevice::init(framework::InitContext& ic) void MIPTrackFilterDevice::run(ProcessingContext& pc) { - if (mTFCounter++ % mProcessEveryNthTF) { - const auto currentTF = processing_helpers::getCurrentTF(pc); + const auto currentTF = processing_helpers::getCurrentTF(pc); + if ((mTFCounter++ % mProcessEveryNthTF) && (currentTF >= mProcessNFirstTFs)) { LOGP(info, "Skipping TF {}", currentTF); return; } @@ -153,7 +155,8 @@ DataProcessorSpec getMIPTrackFilterSpec() {"max-dedx", VariantType::Double, 200., {"maximum dEdx cut"}}, {"min-clusters", VariantType::Int, 60, {"minimum number of clusters in a track"}}, {"processEveryNthTF", VariantType::Int, 1, {"Using only a fraction of the data: 1: Use every TF, 10: Process only every tenth TF."}}, - {"maxTracksPerTF", VariantType::Int, -1, {"Maximum number of processed tracks per TF (-1 for processing all tracks)"}}}}; + {"maxTracksPerTF", VariantType::Int, -1, {"Maximum number of processed tracks per TF (-1 for processing all tracks)"}}, + {"process-first-n-TFs", VariantType::Int, 1, {"Number of first TFs which are not sampled"}}}}; } } // namespace o2::tpc From 0e048b7e55ed46f934b2625be864e6d643891e14 Mon Sep 17 00:00:00 2001 From: shahoian Date: Sun, 1 Oct 2023 01:08:42 +0200 Subject: [PATCH 180/324] TrackStudy should process only selected sources --- .../study/src/TrackingStudy.cxx | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx index 22eb1111aed5b..daa3617c74dfc 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx @@ -129,21 +129,25 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) static_cast(pve) = pv; float bestTimeDiff = 1000, bestTime = -999, bestAmp = -1; - for (int ift0 = vtref.getFirstEntryOfSource(GTrackID::FT0); ift0 < vtref.getFirstEntryOfSource(GTrackID::FT0) + vtref.getEntriesOfSource(GTrackID::FT0); ift0++) { - const auto& ft0 = FITInfo[trackIndex[ift0]]; - if (ft0.isValidTime(o2::ft0::RecPoints::TimeMean) && ft0.getTrigger().getAmplA() + ft0.getTrigger().getAmplC() > 20) { - auto fitTime = ft0.getInteractionRecord().differenceInBCMUS(recoData.startIR); - if (std::abs(fitTime - pv.getTimeStamp().getTimeStamp()) < bestTimeDiff) { - bestTimeDiff = fitTime - pv.getTimeStamp().getTimeStamp(); - bestTime = fitTime; - bestAmp = ft0.getTrigger().getAmplA() + ft0.getTrigger().getAmplC(); + if (mTracksSrc[GTrackID::FT0]) { + for (int ift0 = vtref.getFirstEntryOfSource(GTrackID::FT0); ift0 < vtref.getFirstEntryOfSource(GTrackID::FT0) + vtref.getEntriesOfSource(GTrackID::FT0); ift0++) { + const auto& ft0 = FITInfo[trackIndex[ift0]]; + if (ft0.isValidTime(o2::ft0::RecPoints::TimeMean) && ft0.getTrigger().getAmplA() + ft0.getTrigger().getAmplC() > 20) { + auto fitTime = ft0.getInteractionRecord().differenceInBCMUS(recoData.startIR); + if (std::abs(fitTime - pv.getTimeStamp().getTimeStamp()) < bestTimeDiff) { + bestTimeDiff = fitTime - pv.getTimeStamp().getTimeStamp(); + bestTime = fitTime; + bestAmp = ft0.getTrigger().getAmplA() + ft0.getTrigger().getAmplC(); + } } } + } else { + LOGP(warn, "FT0 is not requested, cannot set complete vertex info"); } pve.FT0Amp = bestAmp; pve.FT0Time = bestTime; for (int is = 0; is < GTrackID::NSources; is++) { - if (!GTrackID::getSourceDetectorsMask(is)[GTrackID::ITS]) { + if (!GTrackID::getSourceDetectorsMask(is)[GTrackID::ITS] || !mTracksSrc[is] || !recoData.isTrackSourceLoaded(is)) { continue; } int idMin = vtref.getFirstEntryOfSource(is), idMax = idMin + vtref.getEntriesOfSource(is); From d7f3b03a33d63c09025bec2b16c4aea6097ca4c3 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 29 Sep 2023 16:16:57 +0200 Subject: [PATCH 181/324] GPU Workflow: Fix refactoring of input processing --- GPU/Workflow/src/GPUWorkflowSpec.cxx | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index c47d86832df41..be154df03d08c 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -582,21 +582,6 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) lastTFCounter = tinfo.tfCounter; } - if (mTPCSectorMask != 0xFFFFFFFFF) { - // Clean out the unused sectors, such that if they were present by chance, they are not processed, and if the values are uninitialized, we should not crash - for (unsigned int i = 0; i < NSectors; i++) { - if (!(mTPCSectorMask & (1ul << i))) { - if (ptrs.tpcZS) { - for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { - tpcZS.slice[i].zsPtr[j] = nullptr; - tpcZS.slice[i].nZSPtr[j] = nullptr; - tpcZS.slice[i].count[j] = 0; - } - } - } - } - } - o2::globaltracking::RecoContainer inputTracksTRD; decltype(o2::trd::getRecoInputContainer(pc, &ptrs, &inputTracksTRD)) trdInputContainer; if (mSpecConfig.readTRDtracklets) { @@ -627,6 +612,21 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) ptrs.clustersNative = &inputsClustersDigits->clusterIndex; } + if (mTPCSectorMask != 0xFFFFFFFFF) { + // Clean out the unused sectors, such that if they were present by chance, they are not processed, and if the values are uninitialized, we should not crash + for (unsigned int i = 0; i < NSectors; i++) { + if (!(mTPCSectorMask & (1ul << i))) { + if (ptrs.tpcZS) { + for (unsigned int j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { + tpcZS.slice[i].zsPtr[j] = nullptr; + tpcZS.slice[i].nZSPtr[j] = nullptr; + tpcZS.slice[i].count[j] = 0; + } + } + } + } + } + GPUTrackingInOutDigits tpcDigitsMap; GPUTPCDigitsMCInput tpcDigitsMapMC; if (doInputDigits) { From 701fc29703447a361747c57bb14ace869d76a16c Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sat, 30 Sep 2023 15:21:31 +0200 Subject: [PATCH 182/324] GPU: Clean up deletion of old calib objects --- .../include/GPUWorkflow/GPUWorkflowSpec.h | 32 ++-- GPU/Workflow/src/GPUWorkflowSpec.cxx | 26 ++- GPU/Workflow/src/GPUWorkflowTPC.cxx | 161 +++++++++--------- 3 files changed, 110 insertions(+), 109 deletions(-) diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index ae7fe2d462d41..18aa671d7e380 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -28,6 +28,7 @@ #include #include #include +#include class TStopwatch; namespace fair::mq @@ -141,6 +142,14 @@ class GPURecoWorkflowSpec : public o2::framework::Task void deinitialize(); private: + struct calibObjectStruct { + std::unique_ptr mFastTransform; + std::unique_ptr mFastTransformRef; + std::unique_ptr mFastTransformHelper; + std::unique_ptr mTPCPadGainCalib; + std::unique_ptr mdEdxCalibContainer; + }; + /// initialize TPC options from command line void initFunctionTPCCalib(o2::framework::InitContext& ic); void initFunctionITS(o2::framework::InitContext& ic); @@ -149,12 +158,12 @@ class GPURecoWorkflowSpec : public o2::framework::Task void finaliseCCDBITS(o2::framework::ConcreteDataMatcher& matcher, void* obj); /// asking for newer calib objects template - bool fetchCalibsCCDBTPC(o2::framework::ProcessingContext& pc, T& newCalibObjects); + bool fetchCalibsCCDBTPC(o2::framework::ProcessingContext& pc, T& newCalibObjects, calibObjectStruct& oldCalibObjects); bool fetchCalibsCCDBITS(o2::framework::ProcessingContext& pc); - /// storing the new calib objects by overwritting the old calibs - void cleanOldCalibsTPCPtrs(); + /// delete old calib objects no longer needed + void cleanOldCalibsTPCPtrs(calibObjectStruct& oldCalibObjects); - void doCalibUpdates(o2::framework::ProcessingContext& pc); + void doCalibUpdates(o2::framework::ProcessingContext& pc, calibObjectStruct& oldCalibObjects); void doTrackTuneTPC(GPUTrackingInOutPointers& ptrs, char* buffout); @@ -178,18 +187,12 @@ class GPURecoWorkflowSpec : public o2::framework::Task std::function mPolicyOrder; std::unique_ptr mGPUReco; std::unique_ptr mDisplayFrontend; - std::unique_ptr mFastTransform; - std::unique_ptr mFastTransformRef; - std::unique_ptr mFastTransformNew; - std::unique_ptr mFastTransformRefNew; - std::unique_ptr mFastTransformHelper; - std::unique_ptr mFastTransformHelperNew; - - std::unique_ptr mTPCPadGainCalib; + + calibObjectStruct mCalibObjects; + std::unique_ptr mdEdxCalibContainerBufferNew; std::unique_ptr mTPCPadGainCalibBufferNew; + std::queue mOldCalibObjects; std::unique_ptr mTPCZSLinkMapping; - std::unique_ptr mdEdxCalibContainer; - std::unique_ptr mdEdxCalibContainerBufferNew; std::unique_ptr mTPCVDriftHelper; std::unique_ptr mTRDGeometry; std::unique_ptr mConfig; @@ -223,7 +226,6 @@ class GPURecoWorkflowSpec : public o2::framework::Task bool mITSGeometryCreated = false; bool mTRDGeometryCreated = false; bool mPropagatorInstanceCreated = false; - bool mMustUpdateFastTransform = false; bool mITSRunVertexer = false; bool mITSCosmicsProcessing = false; std::string mITSMode = "sync"; diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index be154df03d08c..e308c5143f54c 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -247,9 +247,9 @@ void GPURecoWorkflowSpec::init(InitContext& ic) // initialize TPC calib objects initFunctionTPCCalib(ic); - mConfig->configCalib.fastTransform = mFastTransformHelper->getCorrMap(); - mConfig->configCalib.fastTransformRef = mFastTransformHelper->getCorrMapRef(); - mConfig->configCalib.fastTransformHelper = mFastTransformHelper.get(); + mConfig->configCalib.fastTransform = mCalibObjects.mFastTransformHelper->getCorrMap(); + mConfig->configCalib.fastTransformRef = mCalibObjects.mFastTransformHelper->getCorrMapRef(); + mConfig->configCalib.fastTransformHelper = mCalibObjects.mFastTransformHelper.get(); if (mConfig->configCalib.fastTransform == nullptr) { throw std::invalid_argument("GPU workflow: initialization of the TPC transformation failed"); } @@ -501,14 +501,20 @@ int GPURecoWorkflowSpec::runMain(o2::framework::ProcessingContext* pc, GPUTracki } } - cleanOldCalibsTPCPtrs(); // setting TPC calibration objects - if (!mSpecConfig.enableDoublePipeline) { // TODO: Why is this needed for double-pipeline? mGPUReco->Clear(false, threadIndex); // clean non-output memory used by GPU Reconstruction } return retVal; } +void GPURecoWorkflowSpec::cleanOldCalibsTPCPtrs(calibObjectStruct& oldCalibObjects) +{ + if (mOldCalibObjects.size() > 0) { + mOldCalibObjects.pop(); + } + mOldCalibObjects.emplace(std::move(oldCalibObjects)); +} + void GPURecoWorkflowSpec::run(ProcessingContext& pc) { constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR; @@ -746,7 +752,8 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) const auto& holdData = o2::tpc::TPCTrackingDigitsPreCheck::runPrecheck(&ptrs, mConfig.get()); - doCalibUpdates(pc); + calibObjectStruct oldCalibObjects; + doCalibUpdates(pc, oldCalibObjects); lockDecodeInput.reset(); @@ -784,6 +791,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) if (retVal != 0) { debugTFDump = true; } + cleanOldCalibsTPCPtrs(oldCalibObjects); o2::utils::DebugStreamer::instance()->flush(); // flushing debug output to file @@ -959,7 +967,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) LOG(info) << "GPU Reoncstruction time for this TF " << mTimer->CpuTime() - cput << " s (cpu), " << mTimer->RealTime() - realt << " s (wall)"; } -void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc) +void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc, calibObjectStruct& oldCalibObjects) { GPUCalibObjectsConst newCalibObjects; GPUNewCalibValues newCalibValues; @@ -1011,7 +1019,7 @@ void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc) mTRDGeometryCreated = true; } } - needCalibUpdate = fetchCalibsCCDBTPC(pc, newCalibObjects) || needCalibUpdate; + needCalibUpdate = fetchCalibsCCDBTPC(pc, newCalibObjects, oldCalibObjects) || needCalibUpdate; if (mSpecConfig.runITSTracking) { needCalibUpdate = fetchCalibsCCDBITS(pc) || needCalibUpdate; } @@ -1069,7 +1077,7 @@ Inputs GPURecoWorkflowSpec::inputs() inputs.emplace_back("tpcthreshold", gDataOriginTPC, "PADTHRESHOLD", 0, Lifetime::Condition, ccdbParamSpec("TPC/Config/FEEPad")); o2::tpc::VDriftHelper::requestCCDBInputs(inputs); Options optsDummy; - mFastTransformHelper->requestCCDBInputs(inputs, optsDummy, mSpecConfig.requireCTPLumi, mSpecConfig.lumiScaleMode); // option filled here is lost + mCalibObjects.mFastTransformHelper->requestCCDBInputs(inputs, optsDummy, mSpecConfig.requireCTPLumi, mSpecConfig.lumiScaleMode); // option filled here is lost } if (mSpecConfig.decompressTPC) { inputs.emplace_back(InputSpec{"input", ConcreteDataTypeMatcher{gDataOriginTPC, mSpecConfig.decompressTPCFromROOT ? o2::header::DataDescription("COMPCLUSTERS") : o2::header::DataDescription("COMPCLUSTERSFLAT")}, Lifetime::Timeframe}); diff --git a/GPU/Workflow/src/GPUWorkflowTPC.cxx b/GPU/Workflow/src/GPUWorkflowTPC.cxx index f41902021577a..d522c16b6e07c 100644 --- a/GPU/Workflow/src/GPUWorkflowTPC.cxx +++ b/GPU/Workflow/src/GPUWorkflowTPC.cxx @@ -98,45 +98,45 @@ namespace o2::gpu void GPURecoWorkflowSpec::initFunctionTPCCalib(InitContext& ic) { - mdEdxCalibContainer.reset(new o2::tpc::CalibdEdxContainer()); + mCalibObjects.mdEdxCalibContainer.reset(new o2::tpc::CalibdEdxContainer()); mTPCVDriftHelper.reset(new o2::tpc::VDriftHelper()); - mFastTransformHelper.reset(new o2::tpc::CorrectionMapsLoader()); - mFastTransform = std::move(o2::tpc::TPCFastTransformHelperO2::instance()->create(0)); - mFastTransformRef = std::move(o2::tpc::TPCFastTransformHelperO2::instance()->create(0)); - mFastTransformHelper->setCorrMap(mFastTransform.get()); // just to reserve the space - mFastTransformHelper->setCorrMapRef(mFastTransformRef.get()); - mFastTransformHelper->setLumiScaleMode(mSpecConfig.lumiScaleMode); + mCalibObjects.mFastTransformHelper.reset(new o2::tpc::CorrectionMapsLoader()); + mCalibObjects.mFastTransform = std::move(o2::tpc::TPCFastTransformHelperO2::instance()->create(0)); + mCalibObjects.mFastTransformRef = std::move(o2::tpc::TPCFastTransformHelperO2::instance()->create(0)); + mCalibObjects.mFastTransformHelper->setCorrMap(mCalibObjects.mFastTransform.get()); // just to reserve the space + mCalibObjects.mFastTransformHelper->setCorrMapRef(mCalibObjects.mFastTransformRef.get()); + mCalibObjects.mFastTransformHelper->setLumiScaleMode(mSpecConfig.lumiScaleMode); if (mSpecConfig.outputTracks) { - mFastTransformHelper->init(ic); + mCalibObjects.mFastTransformHelper->init(ic); } if (mConfParam->dEdxDisableTopologyPol) { LOGP(info, "Disabling loading of track topology correction using polynomials from CCDB"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol); + mCalibObjects.mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol); } if (mConfParam->dEdxDisableThresholdMap) { LOGP(info, "Disabling loading of threshold map from CCDB"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalThresholdMap); + mCalibObjects.mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalThresholdMap); } if (mConfParam->dEdxDisableGainMap) { LOGP(info, "Disabling loading of gain map from CCDB"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalGainMap); + mCalibObjects.mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalGainMap); } if (mConfParam->dEdxDisableResidualGainMap) { LOGP(info, "Disabling loading of residual gain map from CCDB"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalResidualGainMap); + mCalibObjects.mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalResidualGainMap); } if (mConfParam->dEdxDisableResidualGain) { LOGP(info, "Disabling loading of residual gain calibration from CCDB"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTimeGain); + mCalibObjects.mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTimeGain); } if (mConfParam->dEdxUseFullGainMap) { LOGP(info, "Using the full gain map for correcting the cluster charge during calculation of the dE/dx"); - mdEdxCalibContainer->setUsageOfFullGainMap(true); + mCalibObjects.mdEdxCalibContainer->setUsageOfFullGainMap(true); } if (mConfParam->gainCalibDisableCCDB) { @@ -148,54 +148,54 @@ void GPURecoWorkflowSpec::initFunctionTPCCalib(InitContext& ic) if (!mConfParam->dEdxPolTopologyCorrFile.empty() || !mConfParam->dEdxCorrFile.empty() || !mConfParam->dEdxSplineTopologyCorrFile.empty()) { if (!mConfParam->dEdxPolTopologyCorrFile.empty()) { LOGP(info, "Loading dE/dx polynomial track topology correction from file: {}", mConfParam->dEdxPolTopologyCorrFile); - mdEdxCalibContainer->loadPolTopologyCorrectionFromFile(mConfParam->dEdxPolTopologyCorrFile); + mCalibObjects.mdEdxCalibContainer->loadPolTopologyCorrectionFromFile(mConfParam->dEdxPolTopologyCorrFile); LOGP(info, "Disabling loading of track topology correction using polynomials from CCDB as it was already loaded from input file"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol); + mCalibObjects.mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol); if (std::filesystem::exists(mConfParam->thresholdCalibFile)) { LOG(info) << "Loading tpc zero supression map from file " << mConfParam->thresholdCalibFile; const auto* thresholdMap = o2::tpc::utils::readCalPads(mConfParam->thresholdCalibFile, "ThresholdMap")[0]; - mdEdxCalibContainer->setZeroSupresssionThreshold(*thresholdMap); + mCalibObjects.mdEdxCalibContainer->setZeroSupresssionThreshold(*thresholdMap); LOGP(info, "Disabling loading of threshold map from CCDB as it was already loaded from input file"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalThresholdMap); + mCalibObjects.mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalThresholdMap); } else { if (not mConfParam->thresholdCalibFile.empty()) { LOG(warn) << "Couldn't find tpc zero supression file " << mConfParam->thresholdCalibFile << ". Not setting any zero supression."; } LOG(info) << "Setting default zero supression map"; - mdEdxCalibContainer->setDefaultZeroSupresssionThreshold(); + mCalibObjects.mdEdxCalibContainer->setDefaultZeroSupresssionThreshold(); } } else if (!mConfParam->dEdxSplineTopologyCorrFile.empty()) { LOGP(info, "Loading dE/dx spline track topology correction from file: {}", mConfParam->dEdxSplineTopologyCorrFile); - mdEdxCalibContainer->loadSplineTopologyCorrectionFromFile(mConfParam->dEdxSplineTopologyCorrFile); + mCalibObjects.mdEdxCalibContainer->loadSplineTopologyCorrectionFromFile(mConfParam->dEdxSplineTopologyCorrFile); LOGP(info, "Disabling loading of track topology correction using polynomials from CCDB as splines were loaded from input file"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol); + mCalibObjects.mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTopologyPol); } if (!mConfParam->dEdxCorrFile.empty()) { LOGP(info, "Loading dEdx correction from file: {}", mConfParam->dEdxCorrFile); - mdEdxCalibContainer->loadResidualCorrectionFromFile(mConfParam->dEdxCorrFile); + mCalibObjects.mdEdxCalibContainer->loadResidualCorrectionFromFile(mConfParam->dEdxCorrFile); LOGP(info, "Disabling loading of residual gain calibration from CCDB as it was already loaded from input file"); - mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTimeGain); + mCalibObjects.mdEdxCalibContainer->disableCorrectionCCDB(o2::tpc::CalibsdEdx::CalTimeGain); } } if (mConfParam->dEdxPolTopologyCorrFile.empty() && mConfParam->dEdxSplineTopologyCorrFile.empty()) { // setting default topology correction to allocate enough memory LOG(info) << "Setting default dE/dx polynomial track topology correction to allocate enough memory"; - mdEdxCalibContainer->setDefaultPolTopologyCorrection(); + mCalibObjects.mdEdxCalibContainer->setDefaultPolTopologyCorrection(); } GPUO2InterfaceConfiguration& config = *mConfig.get(); - mConfig->configCalib.dEdxCalibContainer = mdEdxCalibContainer.get(); + mConfig->configCalib.dEdxCalibContainer = mCalibObjects.mdEdxCalibContainer.get(); if (std::filesystem::exists(mConfParam->gainCalibFile)) { LOG(info) << "Loading tpc gain correction from file " << mConfParam->gainCalibFile; const auto* gainMap = o2::tpc::utils::readCalPads(mConfParam->gainCalibFile, "GainMap")[0]; - mTPCPadGainCalib = GPUO2Interface::getPadGainCalib(*gainMap); + mCalibObjects.mTPCPadGainCalib = GPUO2Interface::getPadGainCalib(*gainMap); LOGP(info, "Disabling loading the TPC gain correction map from the CCDB as it was already loaded from input file"); mUpdateGainMapCCDB = false; @@ -203,10 +203,10 @@ void GPURecoWorkflowSpec::initFunctionTPCCalib(InitContext& ic) if (not mConfParam->gainCalibFile.empty()) { LOG(warn) << "Couldn't find tpc gain correction file " << mConfParam->gainCalibFile << ". Not applying any gain correction."; } - mTPCPadGainCalib = GPUO2Interface::getPadGainCalibDefault(); - mTPCPadGainCalib->getGainCorrection(30, 5, 5); + mCalibObjects.mTPCPadGainCalib = GPUO2Interface::getPadGainCalibDefault(); + mCalibObjects.mTPCPadGainCalib->getGainCorrection(30, 5, 5); } - mConfig->configCalib.tpcPadGain = mTPCPadGainCalib.get(); + mConfig->configCalib.tpcPadGain = mCalibObjects.mTPCPadGainCalib.get(); mTPCZSLinkMapping.reset(new TPCZSLinkMapping{tpc::Mapper::instance()}); mConfig->configCalib.tpcZSLinkMapping = mTPCZSLinkMapping.get(); @@ -214,7 +214,7 @@ void GPURecoWorkflowSpec::initFunctionTPCCalib(InitContext& ic) void GPURecoWorkflowSpec::finaliseCCDBTPC(ConcreteDataMatcher& matcher, void* obj) { - const o2::tpc::CalibdEdxContainer* dEdxCalibContainer = mdEdxCalibContainer.get(); + const o2::tpc::CalibdEdxContainer* dEdxCalibContainer = mCalibObjects.mdEdxCalibContainer.get(); auto copyCalibsToBuffer = [this, dEdxCalibContainer]() { if (!(mdEdxCalibContainerBufferNew)) { @@ -263,17 +263,17 @@ void GPURecoWorkflowSpec::finaliseCCDBTPC(ConcreteDataMatcher& matcher, void* ob const auto* residualCorr = static_cast(obj); mdEdxCalibContainerBufferNew->setResidualCorrection(*residualCorr); } else if (mTPCVDriftHelper->accountCCDBInputs(matcher, obj)) { - } else if (mFastTransformHelper->accountCCDBInputs(matcher, obj)) { + } else if (mCalibObjects.mFastTransformHelper->accountCCDBInputs(matcher, obj)) { } } template <> -bool GPURecoWorkflowSpec::fetchCalibsCCDBTPC(ProcessingContext& pc, GPUCalibObjectsConst& newCalibObjects) +bool GPURecoWorkflowSpec::fetchCalibsCCDBTPC(ProcessingContext& pc, GPUCalibObjectsConst& newCalibObjects, calibObjectStruct& oldCalibObjects) { // update calibrations for clustering and tracking - mMustUpdateFastTransform = false; + bool mustUpdate = false; if ((mSpecConfig.outputTracks || mSpecConfig.caClusterer) && !mConfParam->disableCalibUpdates) { - const o2::tpc::CalibdEdxContainer* dEdxCalibContainer = mdEdxCalibContainer.get(); + const o2::tpc::CalibdEdxContainer* dEdxCalibContainer = mCalibObjects.mdEdxCalibContainer.get(); // this calibration is defined for clustering and tracking if (dEdxCalibContainer->isCorrectionCCDB(o2::tpc::CalibsdEdx::CalGainMap) || mUpdateGainMapCCDB) { @@ -301,75 +301,66 @@ bool GPURecoWorkflowSpec::fetchCalibsCCDBTPC(ProcessingCon if (mSpecConfig.outputTracks) { mTPCVDriftHelper->extractCCDBInputs(pc); - mFastTransformHelper->extractCCDBInputs(pc); + mCalibObjects.mFastTransformHelper->extractCCDBInputs(pc); } - if (mTPCVDriftHelper->isUpdated() || mFastTransformHelper->isUpdated()) { + if (mTPCVDriftHelper->isUpdated() || mCalibObjects.mFastTransformHelper->isUpdated()) { const auto& vd = mTPCVDriftHelper->getVDriftObject(); LOGP(info, "Updating{}TPC fast transform map and/or VDrift factor of {} wrt reference {} and TDrift offset {} wrt reference {} from source {}", - mFastTransformHelper->isUpdated() ? " new " : " old ", + mCalibObjects.mFastTransformHelper->isUpdated() ? " new " : " old ", vd.corrFact, vd.refVDrift, vd.timeOffsetCorr, vd.refTimeOffset, mTPCVDriftHelper->getSourceName()); - if (mTPCVDriftHelper->isUpdated() || mFastTransformHelper->isUpdatedMap()) { - mFastTransformNew.reset(new TPCFastTransform); - mFastTransformNew->cloneFromObject(*mFastTransformHelper->getCorrMap(), nullptr); - o2::tpc::TPCFastTransformHelperO2::instance()->updateCalibration(*mFastTransformNew, 0, vd.corrFact, vd.refVDrift, vd.getTimeOffset()); - newCalibObjects.fastTransform = mFastTransformNew.get(); + bool mustUpdateHelper = false; + if (mTPCVDriftHelper->isUpdated() || mCalibObjects.mFastTransformHelper->isUpdatedMap()) { + oldCalibObjects.mFastTransform = std::move(mCalibObjects.mFastTransform); + mCalibObjects.mFastTransform.reset(new TPCFastTransform); + mCalibObjects.mFastTransform->cloneFromObject(*mCalibObjects.mFastTransformHelper->getCorrMap(), nullptr); + o2::tpc::TPCFastTransformHelperO2::instance()->updateCalibration(*mCalibObjects.mFastTransform, 0, vd.corrFact, vd.refVDrift, vd.getTimeOffset()); + newCalibObjects.fastTransform = mCalibObjects.mFastTransform.get(); + mustUpdateHelper = true; } - if (mTPCVDriftHelper->isUpdated() || mFastTransformHelper->isUpdatedMapRef()) { - mFastTransformRefNew.reset(new TPCFastTransform); - mFastTransformRefNew->cloneFromObject(*mFastTransformHelper->getCorrMapRef(), nullptr); - o2::tpc::TPCFastTransformHelperO2::instance()->updateCalibration(*mFastTransformRefNew, 0, vd.corrFact, vd.refVDrift, vd.getTimeOffset()); - newCalibObjects.fastTransformRef = mFastTransformRefNew.get(); + if (mTPCVDriftHelper->isUpdated() || mCalibObjects.mFastTransformHelper->isUpdatedMapRef()) { + oldCalibObjects.mFastTransformRef = std::move(mCalibObjects.mFastTransformRef); + mCalibObjects.mFastTransformRef.reset(new TPCFastTransform); + mCalibObjects.mFastTransformRef->cloneFromObject(*mCalibObjects.mFastTransformHelper->getCorrMapRef(), nullptr); + o2::tpc::TPCFastTransformHelperO2::instance()->updateCalibration(*mCalibObjects.mFastTransformRef, 0, vd.corrFact, vd.refVDrift, vd.getTimeOffset()); + newCalibObjects.fastTransformRef = mCalibObjects.mFastTransformRef.get(); + mustUpdateHelper = true; } - if (mFastTransformNew || mFastTransformRefNew || mFastTransformHelper->isUpdatedLumi()) { - mFastTransformHelperNew.reset(new o2::tpc::CorrectionMapsLoader); - mFastTransformHelperNew->setInstLumi(mFastTransformHelper->getInstLumi(), false); - mFastTransformHelperNew->setMeanLumi(mFastTransformHelper->getMeanLumi(), false); - mFastTransformHelperNew->setUseCTPLumi(mFastTransformHelper->getUseCTPLumi()); - mFastTransformHelperNew->setMeanLumiOverride(mFastTransformHelper->getMeanLumiOverride()); - mFastTransformHelperNew->setInstLumiOverride(mFastTransformHelper->getInstLumiOverride()); - mFastTransformHelperNew->setLumiScaleMode(mFastTransformHelper->getLumiScaleMode()); - mFastTransformHelperNew->setCorrMap(mFastTransformNew ? mFastTransformNew.get() : mFastTransform.get()); - mFastTransformHelperNew->setCorrMapRef(mFastTransformRefNew ? mFastTransformRefNew.get() : mFastTransformRef.get()); - mFastTransformHelperNew->acknowledgeUpdate(); - newCalibObjects.fastTransformHelper = mFastTransformHelperNew.get(); + if (mustUpdateHelper || mCalibObjects.mFastTransformHelper->isUpdatedLumi()) { + oldCalibObjects.mFastTransformHelper = std::move(mCalibObjects.mFastTransformHelper); + mCalibObjects.mFastTransformHelper.reset(new o2::tpc::CorrectionMapsLoader); + mCalibObjects.mFastTransformHelper->setInstLumi(oldCalibObjects.mFastTransformHelper->getInstLumi(), false); + mCalibObjects.mFastTransformHelper->setMeanLumi(oldCalibObjects.mFastTransformHelper->getMeanLumi(), false); + mCalibObjects.mFastTransformHelper->setUseCTPLumi(oldCalibObjects.mFastTransformHelper->getUseCTPLumi()); + mCalibObjects.mFastTransformHelper->setMeanLumiOverride(oldCalibObjects.mFastTransformHelper->getMeanLumiOverride()); + mCalibObjects.mFastTransformHelper->setInstLumiOverride(oldCalibObjects.mFastTransformHelper->getInstLumiOverride()); + mCalibObjects.mFastTransformHelper->setLumiScaleMode(oldCalibObjects.mFastTransformHelper->getLumiScaleMode()); + mCalibObjects.mFastTransformHelper->setCorrMap(mCalibObjects.mFastTransform.get()); + mCalibObjects.mFastTransformHelper->setCorrMapRef(mCalibObjects.mFastTransformRef.get()); + mCalibObjects.mFastTransformHelper->acknowledgeUpdate(); + newCalibObjects.fastTransformHelper = mCalibObjects.mFastTransformHelper.get(); } - mMustUpdateFastTransform = true; + mustUpdate = true; mTPCVDriftHelper->acknowledgeUpdate(); - mFastTransformHelper->acknowledgeUpdate(); + mCalibObjects.mFastTransformHelper->acknowledgeUpdate(); } } if (mdEdxCalibContainerBufferNew) { - newCalibObjects.dEdxCalibContainer = mdEdxCalibContainerBufferNew.get(); + oldCalibObjects.mdEdxCalibContainer = std::move(mCalibObjects.mdEdxCalibContainer); + mCalibObjects.mdEdxCalibContainer = std::move(mdEdxCalibContainerBufferNew); + newCalibObjects.dEdxCalibContainer = mCalibObjects.mdEdxCalibContainer.get(); + mustUpdate = true; } if (mTPCPadGainCalibBufferNew) { - newCalibObjects.tpcPadGain = mTPCPadGainCalibBufferNew.get(); + oldCalibObjects.mTPCPadGainCalib = std::move(mCalibObjects.mTPCPadGainCalib); + mCalibObjects.mTPCPadGainCalib = std::move(mTPCPadGainCalibBufferNew); + newCalibObjects.tpcPadGain = mCalibObjects.mTPCPadGainCalib.get(); + mustUpdate = true; } - - return mdEdxCalibContainerBufferNew || mTPCPadGainCalibBufferNew || mMustUpdateFastTransform; - } - return false; -} - -void GPURecoWorkflowSpec::cleanOldCalibsTPCPtrs() -{ - if (mdEdxCalibContainerBufferNew) { - mdEdxCalibContainer = std::move(mdEdxCalibContainerBufferNew); - } - if (mTPCPadGainCalibBufferNew) { - mTPCPadGainCalib = std::move(mTPCPadGainCalibBufferNew); - } - if (mFastTransformNew) { - mFastTransform = std::move(mFastTransformNew); - } - if (mFastTransformRefNew) { - mFastTransformRef = std::move(mFastTransformRefNew); - } - if (mFastTransformHelperNew) { - mFastTransformHelper = std::move(mFastTransformHelperNew); } + return mustUpdate; } void GPURecoWorkflowSpec::doTrackTuneTPC(GPUTrackingInOutPointers& ptrs, char* buffout) From 24d5c9c5963242cad2827ffcfb7b88ad3a6c9127 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sat, 30 Sep 2023 16:05:37 +0200 Subject: [PATCH 183/324] GPU: Fix merging of calib updates --- GPU/GPUTracking/Global/GPUChainTracking.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 0ea5603c2efb2..fb7324f3b055c 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -979,7 +979,7 @@ void GPUChainTracking::SetUpdateCalibObjects(const GPUCalibObjectsConst& obj, co { std::lock_guard lk(mMutexUpdateCalib); if (mNewCalibObjects) { - void* const* pSrc = (void* const*)&vals; + void* const* pSrc = (void* const*)&obj; void** pDst = (void**)mNewCalibObjects.get(); for (unsigned int i = 0; i < sizeof(*mNewCalibObjects) / sizeof(void*); i++) { if (pSrc[i]) { From a29a880af4623986f7a0220f2ecb2bbd53916a57 Mon Sep 17 00:00:00 2001 From: mfasel Date: Fri, 29 Sep 2023 16:18:53 +0200 Subject: [PATCH 184/324] [EMCAL-1046] Swap HG and LG at overflow cut The reconstruction swap HG and LG at 950 ADC counts in order to avoid saturation of the HG (i.e. due to pedestals). The compression instead used the 10 bit ADC range (1024). In the encoding LG cells in that energy range are encoded with negative values and therefore are out-of-range. In addition introduce a 200 MeV safety margin for the LG in order to not truncate for cells which are slightly below the saturation offset due to floating point imprecision. --- .../EMCAL/include/DataFormatsEMCAL/Cell.h | 9 +- DataFormats/Detectors/EMCAL/src/Cell.cxx | 91 +++++++++++++++++++ .../include/EMCALReconstruction/CTFCoder.h | 2 + .../EMCAL/reconstruction/src/CTFCoder.cxx | 2 +- 4 files changed, 101 insertions(+), 3 deletions(-) diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Cell.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Cell.h index 202615f318a7b..cf29f1d79381c 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Cell.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/Cell.h @@ -60,7 +60,8 @@ class Cell public: enum class EncoderVersion { EncodingV0, - EncodingV1 + EncodingV1, + EncodingV2 }; /// \brief Default constructor Cell() = default; @@ -202,7 +203,7 @@ class Cell /// the limits is provided the energy is /// set to the limits (0 in case of negative /// energy, 250. in case of energies > 250 GeV) - uint16_t getEnergyEncoded(EncoderVersion version = EncoderVersion::EncodingV1) const; + uint16_t getEnergyEncoded(EncoderVersion version = EncoderVersion::EncodingV2) const; /// \brief Get encoded bit representation of cell type (for CTF) /// \return Encoded bit representation @@ -218,10 +219,14 @@ class Cell static uint16_t encodeTime(float timestamp); static uint16_t encodeEnergyV0(float energy); static uint16_t encodeEnergyV1(float energy, ChannelType_t celltype); + static uint16_t encodeEnergyV2(float energy, ChannelType_t celltype); static uint16_t V0toV1(uint16_t energybits, ChannelType_t celltype); + static uint16_t V0toV2(uint16_t energybits, ChannelType_t celltype); + static uint16_t V1toV2(uint16_t energybits, ChannelType_t celltype); static float decodeTime(uint16_t timestampBits); static float decodeEnergyV0(uint16_t energybits); static float decodeEnergyV1(uint16_t energybits, ChannelType_t celltype); + static float decodeEnergyV2(uint16_t energybits, ChannelType_t celltype); private: /// \brief Set cell energy from encoded bit representation (from CTF) diff --git a/DataFormats/Detectors/EMCAL/src/Cell.cxx b/DataFormats/Detectors/EMCAL/src/Cell.cxx index 385c4e6fffece..261384d53ca2a 100644 --- a/DataFormats/Detectors/EMCAL/src/Cell.cxx +++ b/DataFormats/Detectors/EMCAL/src/Cell.cxx @@ -44,6 +44,21 @@ const float ENERGY_RESOLUTION_TRU = ENERGY_TRUNCATION / ENERGY_BITS, ENERGY_RESOLUTION_LEDMON = ENERGY_TRUNCATION / ENERGY_BITS; } + +namespace v2 +{ +const float + ENERGY_BITS = static_cast(0x3FFF), + SAFETYMARGIN = 0.2, + HGLGTRANSITION = o2::emcal::constants::OVERFLOWCUT * o2::emcal::constants::EMCAL_ADCENERGY, + OFFSET_LG = HGLGTRANSITION - SAFETYMARGIN, + ENERGY_TRUNCATION = 250., + ENERGY_RESOLUTION_LG = (ENERGY_TRUNCATION - OFFSET_LG) / ENERGY_BITS, + ENERGY_RESOLUTION_HG = HGLGTRANSITION / ENERGY_BITS, + ENERGY_RESOLUTION_TRU = ENERGY_TRUNCATION / ENERGY_BITS, + ENERGY_RESOLUTION_LEDMON = ENERGY_TRUNCATION / ENERGY_BITS; + +} } // namespace EnergyEncoding namespace DecodingV0 @@ -87,6 +102,10 @@ uint16_t Cell::getEnergyEncoded(EncoderVersion version) const case EncoderVersion::EncodingV1: energyBits = encodeEnergyV1(mEnergy, mChannelType); break; + + case EncoderVersion::EncodingV2: + energyBits = encodeEnergyV2(mEnergy, mChannelType); + break; } return energyBits; } @@ -105,6 +124,9 @@ void Cell::setEnergyEncoded(uint16_t energyBits, uint16_t channelTypeBits, Encod case EncoderVersion::EncodingV1: mEnergy = decodeEnergyV1(energyBits, static_cast(channelTypeBits)); break; + case EncoderVersion::EncodingV2: + mEnergy = decodeEnergyV2(energyBits, static_cast(channelTypeBits)); + break; } } @@ -214,12 +236,55 @@ uint16_t Cell::encodeEnergyV1(float energy, ChannelType_t celltype) return static_cast(std::round((truncatedEnergy - energyOffset) / resolutionApplied)); }; +uint16_t Cell::encodeEnergyV2(float energy, ChannelType_t celltype) +{ + double truncatedEnergy = energy; + if (truncatedEnergy < 0.) { + truncatedEnergy = 0.; + } else if (truncatedEnergy > EnergyEncoding::v2::ENERGY_TRUNCATION) { + truncatedEnergy = EnergyEncoding::v2::ENERGY_TRUNCATION; + } + float resolutionApplied = 0., energyOffset = 0.; + switch (celltype) { + case ChannelType_t::HIGH_GAIN: { + resolutionApplied = EnergyEncoding::v2::ENERGY_RESOLUTION_HG; + break; + } + case ChannelType_t::LOW_GAIN: { + resolutionApplied = EnergyEncoding::v2::ENERGY_RESOLUTION_LG; + energyOffset = EnergyEncoding::v2::OFFSET_LG; + break; + } + case ChannelType_t::TRU: { + resolutionApplied = EnergyEncoding::v2::ENERGY_RESOLUTION_TRU; + break; + } + case ChannelType_t::LEDMON: { + resolutionApplied = EnergyEncoding::v2::ENERGY_RESOLUTION_LEDMON; + break; + } + } + return static_cast(std::round((truncatedEnergy - energyOffset) / resolutionApplied)); +}; + uint16_t Cell::V0toV1(uint16_t energyBits, ChannelType_t celltype) { auto decodedEnergy = decodeEnergyV0(energyBits); return encodeEnergyV1(decodedEnergy, celltype); } +uint16_t Cell::V0toV2(uint16_t energyBits, ChannelType_t celltype) +{ + auto decodedEnergy = decodeEnergyV0(energyBits); + return encodeEnergyV2(decodedEnergy, celltype); +} + +uint16_t Cell::V1toV2(uint16_t energyBits, ChannelType_t celltype) +{ + auto decodedEnergy = decodeEnergyV1(energyBits, celltype); + return encodeEnergyV2(decodedEnergy, celltype); +} + float Cell::decodeTime(uint16_t timestampBits) { return (static_cast(timestampBits) * TimeEncoding::TIME_RESOLUTION) - TimeEncoding::TIME_SHIFT; @@ -256,6 +321,32 @@ float Cell::decodeEnergyV1(uint16_t energyBits, ChannelType_t celltype) return (static_cast(energyBits) * resolutionApplied) + energyOffset; } +float Cell::decodeEnergyV2(uint16_t energyBits, ChannelType_t celltype) +{ + float resolutionApplied = 0., + energyOffset = 0.; + switch (celltype) { + case ChannelType_t::HIGH_GAIN: { + resolutionApplied = EnergyEncoding::v2::ENERGY_RESOLUTION_HG; + break; + } + case ChannelType_t::LOW_GAIN: { + resolutionApplied = EnergyEncoding::v2::ENERGY_RESOLUTION_LG; + energyOffset = EnergyEncoding::v2::OFFSET_LG; + break; + } + case ChannelType_t::TRU: { + resolutionApplied = EnergyEncoding::v2::ENERGY_RESOLUTION_TRU; + break; + } + case ChannelType_t::LEDMON: { + resolutionApplied = EnergyEncoding::v2::ENERGY_RESOLUTION_LEDMON; + break; + } + } + return (static_cast(energyBits) * resolutionApplied) + energyOffset; +} + void Cell::PrintStream(std::ostream& stream) const { stream << "EMCAL Cell: Type " << getType() << ", Energy " << getEnergy() << ", Time " << getTimeStamp() << ", Tower " << getTower(); diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h index 9bef0b9184117..1617a9f1a7d54 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h @@ -169,6 +169,8 @@ o2::ctf::CTFIOSize CTFCoder::decode(const CTF::base& ec, VTRG& trigVec, VCELL& c Cell::EncoderVersion encodingversion = o2::emcal::Cell::EncoderVersion::EncodingV0; if (header.majorVersion == 1 && header.minorVersion == 1) { encodingversion = o2::emcal::Cell::EncoderVersion::EncodingV1; + } else if (header.majorVersion == 1 && header.minorVersion == 2) { + encodingversion = o2::emcal::Cell::EncoderVersion::EncodingV2; } uint32_t firstEntry = 0, cellCount = 0; diff --git a/Detectors/EMCAL/reconstruction/src/CTFCoder.cxx b/Detectors/EMCAL/reconstruction/src/CTFCoder.cxx index 22cad97dd7e76..5f3b04f600192 100644 --- a/Detectors/EMCAL/reconstruction/src/CTFCoder.cxx +++ b/Detectors/EMCAL/reconstruction/src/CTFCoder.cxx @@ -66,6 +66,6 @@ void CTFCoder::assignDictVersion(o2::ctf::CTFDictHeader& h) const h = mExtHeader; } else { h.majorVersion = 1; - h.minorVersion = 1; + h.minorVersion = 2; } } \ No newline at end of file From 51bc3fab76d5403885b5c862e2b17b5db7552a34 Mon Sep 17 00:00:00 2001 From: shahoian Date: Sun, 1 Oct 2023 17:46:55 +0200 Subject: [PATCH 185/324] Check if FileFetcher is done for early stop on empty queue (fix for PR11985) --- Detectors/CTF/workflow/src/CTFReaderSpec.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx index 13f78afd57ff9..9eddb2e9b32c9 100644 --- a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx @@ -228,7 +228,7 @@ void CTFReaderSpec::run(ProcessingContext& pc) if (mCTFCounter >= mInput.maxTFs || (!mInput.ctfIDs.empty() && mSelIDEntry >= mInput.ctfIDs.size())) { // done LOG(info) << "All CTFs from selected range were injected, stopping"; mRunning = false; - } else if (mRunning && !mCTFTree && mFileFetcher->getNextFileInQueue().empty()) { // previous tree was done, can we read more? + } else if (mRunning && !mCTFTree && mFileFetcher->getNextFileInQueue().empty() && !mFileFetcher->isRunning()) { // previous tree was done, can we read more? mRunning = false; } From 3eaa11b9b90a23442a41bf8b849dd838d103fcc2 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 1 Oct 2023 12:48:08 +0200 Subject: [PATCH 186/324] dpl-workflow: make GPU double-pipeline the default for EPN and FST --- prodtests/full-system-test/dpl-workflow.sh | 2 +- prodtests/full-system-test/start_tmux.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index e5590a6497ccd..8934a5b7924ef 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -290,7 +290,7 @@ if has_detector_calib PHS && workflow_has_parameter CALIB; then PHS_CONFIG+=" --fullclu-output" fi -[[ ${O2_GPU_DOUBLE_PIPELINE:-0} == 1 ]] && GPU_CONFIG+=" --enableDoublePipeline" +[[ ${O2_GPU_DOUBLE_PIPELINE:-$EPNSYNCMODE} == 1 ]] && GPU_CONFIG+=" --enableDoublePipeline" ( workflow_has_parameter AOD || [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output o2-emcal-cell-writer-workflow ) && has_detector EMC && RAW_EMC_SUBSPEC=" --subspecification 1 " has_detector_reco MID && has_detector_matching MCHMID && MFTMCHConf="FwdMatching.useMIDMatch=true;" || MFTMCHConf="FwdMatching.useMIDMatch=false;" diff --git a/prodtests/full-system-test/start_tmux.sh b/prodtests/full-system-test/start_tmux.sh index e6451d7940a2a..c4564f4863421 100755 --- a/prodtests/full-system-test/start_tmux.sh +++ b/prodtests/full-system-test/start_tmux.sh @@ -36,6 +36,7 @@ if [[ "0$FST_TMUX_NO_EPN" != "01" ]]; then [[ -z $GPUMEMSIZE ]] && export GPUMEMSIZE=$(( 24 << 30 )) [[ -z $NUMAGPUIDS ]] && export NUMAGPUIDS=1 [[ -z $EPNPIPELINES ]] && export EPNPIPELINES=1 + [[ -z $O2_GPU_DOUBLE_PIPELINE ]] && export O2_GPU_DOUBLE_PIPELINE=1 [[ -z $DPL_CONDITION_BACKEND ]] && export DPL_CONDITION_BACKEND="http://localhost:8084" export ALL_EXTRA_CONFIG="$ALL_EXTRA_CONFIG;NameConf.mCCDBServer=${DPL_CONDITION_BACKEND};" export GEN_TOPO_QC_OVERRIDE_CCDB_SERVER="${DPL_CONDITION_BACKEND}" From c6269789b86403d4bcbdff51da7a84ab34e55af3 Mon Sep 17 00:00:00 2001 From: Fabrizio Date: Mon, 2 Oct 2023 10:08:01 +0200 Subject: [PATCH 187/324] [ITS3] Improve transformation of coordinates and digitisation (#11965) * [ITS3] Improve transformation of coordinates and digitisation * Please consider the following formatting changes --------- Co-authored-by: ALICE Action Bot --- .../ITS3Base/SegmentationSuperAlpide.h | 38 +++++++++---------- .../ITS3/simulation/src/Digitizer.cxx | 10 ++--- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/Detectors/Upgrades/ITS3/base/include/ITS3Base/SegmentationSuperAlpide.h b/Detectors/Upgrades/ITS3/base/include/ITS3Base/SegmentationSuperAlpide.h index 810fa19e882fa..fb888feb359ea 100644 --- a/Detectors/Upgrades/ITS3/base/include/ITS3Base/SegmentationSuperAlpide.h +++ b/Detectors/Upgrades/ITS3/base/include/ITS3Base/SegmentationSuperAlpide.h @@ -40,20 +40,20 @@ class SegmentationSuperAlpide } SegmentationSuperAlpide(int layer = 0) : SegmentationSuperAlpide(layer, SuperAlpideParams::Instance().mPitchCol, SuperAlpideParams::Instance().mPitchRow, SuperAlpideParams::Instance().mDetectorThickness, DescriptorInnerBarrelITS3Param::Instance().mLength, DescriptorInnerBarrelITS3Param::Instance().mRadii) {} - double mRadii[4] = {1.8f, 2.4f, 3.0f, 6.0f}; ///< radii for different layers - const double mLength; ///< chip length - const int mLayer; ///< chip layer - const float mPitchCol; ///< pixel column size - const float mPitchRow; ///< pixel row size - const float mDetectorLayerThickness; ///< detector thickness - const int mNCols{static_cast(std::ceil(mLength / mPitchCol))}; ///< number of columns - const int mNRows{static_cast(std::ceil(double(mRadii[mLayer] + mDetectorLayerThickness - mSensorLayerThickness / 2.) * double(constants::math::PI) / double(mPitchRow) * (mLayer == 3 ? 0.5 : 1.)))}; ///< number of rows - const int mNPixels{mNRows * mNCols}; ///< total number of pixels - static constexpr float mPassiveEdgeReadOut = 0.; ///< width of the readout edge (Passive bottom) - static constexpr float mPassiveEdgeTop = 0.; ///< Passive area on top - static constexpr float mPassiveEdgeSide = 0.; ///< width of Passive area on left/right of the sensor - const float mActiveMatrixSizeCols{mPitchCol * mNCols}; ///< Active size along columns - const float mActiveMatrixSizeRows{mPitchRow * mNRows}; ///< Active size along rows + double mRadii[4] = {1.8f, 2.4f, 3.0f, 6.0f}; ///< radii for different layers + const double mLength; ///< chip length + const int mLayer; ///< chip layer + const float mPitchCol; ///< pixel column size at the external surface + const float mPitchRow; ///< pixel row size at the external surface + const float mDetectorLayerThickness; ///< detector thickness + const int mNCols{static_cast(std::floor(mLength / mPitchCol / 2) * 2)}; ///< number of columns (we force to have an even number) + const int mNRows{static_cast(std::floor(double(mRadii[mLayer] + mDetectorLayerThickness - mSensorLayerThicknessEff / 2.) * double(constants::math::PI) / double(mPitchRow) / 2 * (mLayer == 3 ? 0.5 : 1.)) * 2)}; ///< number of rows (we force to have an even number) + const int mNPixels{mNRows * mNCols}; ///< total number of pixels + static constexpr float mPassiveEdgeReadOut = 0.; ///< width of the readout edge (Passive bottom) + static constexpr float mPassiveEdgeTop = 0.; ///< Passive area on top + static constexpr float mPassiveEdgeSide = 0.; ///< width of Passive area on left/right of the sensor + const float mActiveMatrixSizeCols{mPitchCol * mNCols}; ///< Active size along columns + const float mActiveMatrixSizeRows{mPitchRow * mNRows}; ///< Active size along rows // effective thickness of sensitive layer, accounting for charge collection non-uniformity, https://alice.its.cern.ch/jira/browse/AOC-46 static constexpr float mSensorLayerThicknessEff = 28.e-4; ///< effective thickness of sensitive part @@ -140,7 +140,7 @@ inline void SegmentationSuperAlpide::curvedToFlat(float xCurved, float yCurved, float dist = std::sqrt(xCurved * xCurved + yCurved * yCurved); yFlat = dist - (mRadii[mLayer] + mDetectorLayerThickness - mSensorLayerThickness / 2.); float phi = (double)constants::math::PI / 2 - std::atan2((double)yCurved, (double)xCurved); - xFlat = dist * phi; + xFlat = (mRadii[mLayer] + mDetectorLayerThickness - mSensorLayerThickness / 2.) * phi; // we bring everything to the upper surface to avoid effects due to the different length of upper and lower surfaces } inline void SegmentationSuperAlpide::flatToCurved(float xFlat, float yFlat, float& xCurved, float& yCurved) @@ -157,8 +157,8 @@ inline void SegmentationSuperAlpide::localToDetectorUnchecked(float xRow, float // convert to row/col w/o over/underflow check xRow = 0.5 * (mActiveMatrixSizeRows - mPassiveEdgeTop + mPassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix zCol += 0.5 * mActiveMatrixSizeCols; // coordinate wrt left edge of Active matrix - iRow = int(xRow / mPitchRow); - iCol = int(zCol / mPitchCol); + iRow = std::floor(xRow / mPitchRow); + iCol = std::floor(zCol / mPitchCol); if (xRow < 0) { iRow -= 1; } @@ -176,8 +176,8 @@ inline bool SegmentationSuperAlpide::localToDetector(float xRow, float zCol, int iRow = iCol = -1; return false; } - iRow = int(xRow / mPitchRow); - iCol = int(zCol / mPitchCol); + iRow = std::floor(xRow / mPitchRow); + iCol = std::floor(zCol / mPitchCol); return true; } diff --git a/Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx index d508458d92e54..cbad587f7cf7f 100644 --- a/Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx @@ -231,7 +231,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID float nStepsInv = mParams.getNSimStepsInv(); int nSteps = mParams.getNSimSteps(); short detID{hit.GetDetectorID()}; - const auto& matrix = mGeometry->getMatrixL2G(detID); // <<<< ????? + const auto& matrix = mGeometry->getMatrixL2G(detID); bool innerBarrel{detID < mSuperSegmentations.size()}; math_utils::Vector3D xyzLocS, xyzLocE; xyzLocS = matrix ^ (hit.GetPosStart()); @@ -331,12 +331,8 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID // take into account that the AlpideSimResponse depth defintion has different min/max boundaries // although the max should coincide with the surface of the epitaxial layer, which in the chip // local coordinates has Y = +SensorLayerThickness/2 - float thickness = innerBarrel ? mSuperSegmentations[detID].mDetectorLayerThickness : Segmentation::SensorLayerThickness; - if (!innerBarrel) { - xyzLocS.SetY(xyzLocS.Y() + resp->getDepthMax() - Segmentation::SensorLayerThickness / 2.); - } else { - xyzLocS.SetY(xyzLocS.Y() * (mSuperSegmentations[detID].mSensorLayerThicknessEff / 2. / mSuperSegmentations[detID].mDetectorLayerThickness)); // to avoid holes in clusters // FIXME - } + float thickness = innerBarrel ? mSuperSegmentations[detID].mSensorLayerThicknessEff : Segmentation::SensorLayerThickness; + xyzLocS.SetY(xyzLocS.Y() + resp->getDepthMax() - thickness / 2.); // collect charge in evey pixel which might be affected by the hit for (int iStep = nSteps; iStep--;) { From 6d3ffd0f91d3509c35bca9ff6384196b1e59d988 Mon Sep 17 00:00:00 2001 From: shahoian Date: Mon, 2 Oct 2023 15:59:17 +0200 Subject: [PATCH 188/324] Fix: CTPinputs from prev BC were filled for BCs w/o CTP input --- Detectors/AOD/src/AODProducerWorkflowSpec.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index f9dcccd0029fb..6984ed3841e63 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -2124,10 +2124,10 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) } // filling BC table - std::pair masks{0, 0}; bcCursor.reserve(bcsMap.size()); for (auto& item : bcsMap) { uint64_t bc = item.first; + std::pair masks{0, 0}; if (mInputSources[GID::CTP]) { auto bcClassPair = bcToClassMask.find(bc); if (bcClassPair != bcToClassMask.end()) { From de977ead3445c3eff534866532cef103d288d8bf Mon Sep 17 00:00:00 2001 From: lietava Date: Mon, 2 Oct 2023 21:31:23 +0200 Subject: [PATCH 189/324] ctpinputs-decoding-ctf to ignore-ctpinputs-decoding-ctf --- Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx b/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx index 0e71d05af5815..8f3da5f439f80 100644 --- a/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx @@ -44,7 +44,7 @@ void EntropyDecoderSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matche void EntropyDecoderSpec::init(o2::framework::InitContext& ic) { mCTFCoder.init(ic); - bool decodeinps = ic.options().get("ctpinputs-decoding-ctf"); + bool decodeinps = !ic.options().get("ignore-ctpinputs-decoding-ctf"); mCTFCoder.setDecodeInps(decodeinps); LOG(info) << "Decode inputs:" << decodeinps; } @@ -95,7 +95,7 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) outputs, AlgorithmSpec{adaptFromTask(verbosity)}, Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ctpinputs-decoding-ctf", VariantType::Bool, false, {"Inputs alignment: true - CTF decoder - has to be compatible with reco: allowed options: 10,01,00"}}, + {"ignore-ctpinputs-decoding-ctf", VariantType::Bool, false, {"Inputs alignment: false - CTF decoder - has to be compatible with reco: allowed options: 10,01,00"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } From 6e6c10e5119dde0fb8c7e17e1f479f5a055f8160 Mon Sep 17 00:00:00 2001 From: shahoian Date: Tue, 3 Oct 2023 00:31:07 +0200 Subject: [PATCH 190/324] Transfer all lumi scaling settings between alternating CorrectionMapsLoaders --- .../include/TPCCalibration/CorrectionMapsLoader.h | 2 ++ .../TPC/calibration/src/CorrectionMapsLoader.cxx | 14 ++++++++++++++ GPU/Workflow/src/GPUWorkflowTPC.cxx | 7 +------ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h b/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h index 043ed05e33d70..3f832e35557fb 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h @@ -48,6 +48,8 @@ class CorrectionMapsLoader : public o2::gpu::CorrectionMapsHelper void extractCCDBInputs(o2::framework::ProcessingContext& pc); void updateVDrift(float vdriftCorr, float vdrifRef, float driftTimeOffset = 0); void init(o2::framework::InitContext& ic); + void copySettings(const CorrectionMapsLoader& src); + static void requestCCDBInputs(std::vector& inputs, std::vector& options, bool requestCTPLumi = false, int lumiScaleMode = 0); static void addOptions(std::vector& options); diff --git a/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx b/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx index 48426044bec87..92432162872a9 100644 --- a/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx +++ b/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx @@ -149,4 +149,18 @@ void CorrectionMapsLoader::init(o2::framework::InitContext& ic) LOGP(info, "CTP Lumi request for TPC corr.map scaling={}, override values: lumiMean={} lumiInst={} lumiScaleMode={}, LumiInst scale={}, CTP Lumi source={}", getUseCTPLumi() ? "ON" : "OFF", mMeanLumiOverride, mInstLumiOverride, mLumiScaleMode, mInstLumiFactor, mCTPLumiSource); } + +//________________________________________________________ +void CorrectionMapsLoader::copySettings(const CorrectionMapsLoader& src) +{ + setInstLumi(src.getInstLumi(), false); + setMeanLumi(src.getMeanLumi(), false); + setUseCTPLumi(src.getUseCTPLumi()); + setMeanLumiOverride(src.getMeanLumiOverride()); + setInstLumiOverride(src.getInstLumiOverride()); + setLumiScaleMode(src.getLumiScaleMode()); + mInstLumiFactor = src.mInstLumiFactor; + mCTPLumiSource = src.mCTPLumiSource; +} + #endif // #ifndef GPUCA_GPUCODE_DEVICE diff --git a/GPU/Workflow/src/GPUWorkflowTPC.cxx b/GPU/Workflow/src/GPUWorkflowTPC.cxx index d522c16b6e07c..3bc36716f8607 100644 --- a/GPU/Workflow/src/GPUWorkflowTPC.cxx +++ b/GPU/Workflow/src/GPUWorkflowTPC.cxx @@ -329,12 +329,7 @@ bool GPURecoWorkflowSpec::fetchCalibsCCDBTPC(ProcessingCon if (mustUpdateHelper || mCalibObjects.mFastTransformHelper->isUpdatedLumi()) { oldCalibObjects.mFastTransformHelper = std::move(mCalibObjects.mFastTransformHelper); mCalibObjects.mFastTransformHelper.reset(new o2::tpc::CorrectionMapsLoader); - mCalibObjects.mFastTransformHelper->setInstLumi(oldCalibObjects.mFastTransformHelper->getInstLumi(), false); - mCalibObjects.mFastTransformHelper->setMeanLumi(oldCalibObjects.mFastTransformHelper->getMeanLumi(), false); - mCalibObjects.mFastTransformHelper->setUseCTPLumi(oldCalibObjects.mFastTransformHelper->getUseCTPLumi()); - mCalibObjects.mFastTransformHelper->setMeanLumiOverride(oldCalibObjects.mFastTransformHelper->getMeanLumiOverride()); - mCalibObjects.mFastTransformHelper->setInstLumiOverride(oldCalibObjects.mFastTransformHelper->getInstLumiOverride()); - mCalibObjects.mFastTransformHelper->setLumiScaleMode(oldCalibObjects.mFastTransformHelper->getLumiScaleMode()); + mCalibObjects.mFastTransformHelper->copySettings(*oldCalibObjects.mFastTransformHelper); mCalibObjects.mFastTransformHelper->setCorrMap(mCalibObjects.mFastTransform.get()); mCalibObjects.mFastTransformHelper->setCorrMapRef(mCalibObjects.mFastTransformRef.get()); mCalibObjects.mFastTransformHelper->acknowledgeUpdate(); From 0f7aec11f00a38178e0b500a520f958dc67cc786 Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Mon, 2 Oct 2023 23:12:58 +0200 Subject: [PATCH 191/324] Make TRD raw reader more fault tolerant, allow fixing n time bins --- .../Detectors/TRD/include/DataFormatsTRD/Digit.h | 1 + .../include/TRDReconstruction/CruRawReader.h | 9 +++++++++ Detectors/TRD/reconstruction/src/CruRawReader.cxx | 15 ++++++++++++--- Detectors/TRD/reconstruction/src/DataReader.cxx | 1 + .../TRD/reconstruction/src/DataReaderTask.cxx | 5 +++++ 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Digit.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Digit.h index 9b0d3a25f91a6..03602d96e85da 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Digit.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Digit.h @@ -91,6 +91,7 @@ class Digit ADC_t getADCsum() const { return std::accumulate(mADC.begin(), mADC.end(), (ADC_t)0); } // returns the max ADC value and sets idx to the time bin with the largest ADC value ADC_t getADCmax(int& idx) const; + ADC_t getADCval(int tb) const { return mADC[tb]; } bool operator==(const Digit& o) const { diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/CruRawReader.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/CruRawReader.h index 23b9d809eecfd..871160f3dfd7e 100644 --- a/Detectors/TRD/reconstruction/include/TRDReconstruction/CruRawReader.h +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/CruRawReader.h @@ -63,6 +63,14 @@ class CruRawReader // configure the raw reader, done once at the init() stage void configure(int tracklethcheader, int halfchamberwords, int halfchambermajor, std::bitset<16> options); + // set number of time bins to fixed value instead of reading from DigitHCHeader + // (but still complain if DigitHCHeader is not consistent) + void setNumberOfTimeBins(int tb) + { + mTimeBins = tb; + mTimeBinsFixed = true; + } + // settings in order to avoid InfoLogger flooding void setMaxErrWarnPrinted(int nerr, int nwar) { @@ -165,6 +173,7 @@ class CruRawReader bool mPreviousHalfCRUHeaderSet; // flag, whether we can use mPreviousHalfCRUHeader for additional sanity checks DigitHCHeader mDigitHCHeader; // Digit HalfChamber header we are currently on. uint16_t mTimeBins{constants::TIMEBINS}; // the number of time bins to be read out (default 30, can be overwritten from digit HC header) + bool mTimeBinsFixed{false}; // flag, whether number of time bins different from default was configured bool mHaveSeenDigitHCHeader3{false}; // flag, whether we can compare an incoming DigitHCHeader3 with a header we have seen before uint32_t mPreviousDigitHCHeadersvnver; // svn ver in the digithalfchamber header, used for validity checks uint32_t mPreviousDigitHCHeadersvnrver; // svn release ver also used for validity checks diff --git a/Detectors/TRD/reconstruction/src/CruRawReader.cxx b/Detectors/TRD/reconstruction/src/CruRawReader.cxx index beb0b92869147..eff2597b481a8 100644 --- a/Detectors/TRD/reconstruction/src/CruRawReader.cxx +++ b/Detectors/TRD/reconstruction/src/CruRawReader.cxx @@ -303,7 +303,7 @@ bool CruRawReader::parseDigitHCHeaders(int hcid) mPreTriggerPhase = header1.ptrigphase; headersfound.set(0); - if ((header1.numtimebins > TIMEBINS) || (header1.numtimebins < 3)) { + if ((header1.numtimebins > TIMEBINS) || (header1.numtimebins < 3) || mTimeBinsFixed && header1.numtimebins != mTimeBins) { if (mOptions[TRDVerboseErrorsBit]) { LOGF(warn, "According to Digit HC Header 1 there are %i time bins configured", (int)header1.numtimebins); printDigitHCHeader(mDigitHCHeader, headers.data()); @@ -760,10 +760,10 @@ int CruRawReader::parseDigitLinkData(int maxWords32, int hcid, int& wordsRejecte } else if (state == StateDigitMCMData) { - std::array adcValues; bool exitChannelLoop = false; state = StateDigitMCMHeader; // after we are done reading the ADC data, by default we expect another MCM header for (int iChannel = 0; iChannel < NADCMCM; ++iChannel) { + std::array adcValues{}; if (!(mDigitHCHeader.major & 0x20) || adcMask.adcmask & (1UL << iChannel)) { // either ZS is OFF, or the adcMask has iChannel flagged as active DigitMCMData data; @@ -887,7 +887,10 @@ int CruRawReader::parseTrackletLinkData(int linkSize32, int& hcid, int& wordsRej mcmHeader.word = currWord; if (!sanityCheckTrackletMCMHeader(mcmHeader)) { incrementErrors(TrackletMCMHeaderSanityCheckFailure, hcid, fmt::format("Invalid word {:#010x} for the expected TrackletMCMHeader", currWord)); - state = StateMoveToEndMarker; // invalid MCM header, no chance to interpret the following MCM data + // invalid MCM header, but we can try to find another valid MCM header before the end markers. + // If there are no end markers we can anyhow not parse digits if they were there. + // Other invalid MCM headers can be caught by the check on their ordering (row/column) + // state = StateMoveToEndMarker; ++wordsRead; ++wordsRejected; continue; @@ -896,8 +899,14 @@ int CruRawReader::parseTrackletLinkData(int linkSize32, int& hcid, int& wordsRej if (previousColumn >= 0) { if (mcmHeader.padrow < previousRow || (mcmHeader.padrow == previousRow && mcmHeader.col < previousColumn)) { incrementErrors(TrackletDataWrongOrdering, hcid, fmt::format("Current padrow/column = {}/{}, previous padrow/column = {}/{}", (int)mcmHeader.padrow, (int)mcmHeader.col, previousRow, previousColumn)); + ++wordsRead; + ++wordsRejected; + continue; } else if (mcmHeader.padrow == previousRow && mcmHeader.col == previousColumn) { incrementErrors(TrackletDataDuplicateMCM, hcid, fmt::format("Second MCM header {:#010x} for padrow/column = {}/{}", currWord, previousRow, previousColumn)); + ++wordsRead; + ++wordsRejected; + continue; } } else { previousColumn = mcmHeader.col; diff --git a/Detectors/TRD/reconstruction/src/DataReader.cxx b/Detectors/TRD/reconstruction/src/DataReader.cxx index 3e24fe0440153..4a5d74523c530 100644 --- a/Detectors/TRD/reconstruction/src/DataReader.cxx +++ b/Detectors/TRD/reconstruction/src/DataReader.cxx @@ -105,6 +105,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) algoSpec, Options{{"log-max-errors", VariantType::Int, 20, {"maximum number of errors to log"}}, {"log-max-warnings", VariantType::Int, 20, {"maximum number of warnings to log"}}, + {"number-of-TBs", VariantType::Int, -1, {"set to >=0 in order to overwrite number of time bins"}}, {"every-nth-tf", VariantType::Int, 1, {"process only every n-th TF"}}}}); if (!cfgc.options().get("disable-root-output")) { diff --git a/Detectors/TRD/reconstruction/src/DataReaderTask.cxx b/Detectors/TRD/reconstruction/src/DataReaderTask.cxx index 7bba5d2b085d4..2e1232e15aa4e 100644 --- a/Detectors/TRD/reconstruction/src/DataReaderTask.cxx +++ b/Detectors/TRD/reconstruction/src/DataReaderTask.cxx @@ -32,6 +32,11 @@ namespace o2::trd void DataReaderTask::init(InitContext& ic) { mReader.setMaxErrWarnPrinted(ic.options().get("log-max-errors"), ic.options().get("log-max-warnings")); + int nTimeBins = ic.options().get("number-of-TBs"); + if (nTimeBins >= 0) { + LOGP(info, "Number of time bins set to {} externally", nTimeBins); + mReader.setNumberOfTimeBins(nTimeBins); + } mReader.configure(mTrackletHCHeaderState, mHalfChamberWords, mHalfChamberMajor, mOptions); mProcessEveryNthTF = ic.options().get("every-nth-tf"); } From e1229ac2c37c0ea6c04efe5d882cd6e1ffb9c059 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 3 Oct 2023 11:15:10 +0200 Subject: [PATCH 192/324] Avoid injecting data unexpectedly (#11995) This protects the case of multiple pipelines. --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index bd9767fe0661e..94aadf7f76950 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -281,6 +281,10 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve firstDH = dh; } for (size_t pi = 0; pi < present.size(); ++pi) { + // Consider uninvolved pipelines as present. + if (routes[pi].timeslice == (dph->startTime % routes[pi].maxTimeslices)) { + present[pi] = true; + } if (present[pi]) { continue; } From 81a4232e5aaa145c42a6e8f59583407c1a955dba Mon Sep 17 00:00:00 2001 From: noferini Date: Tue, 3 Oct 2023 09:32:43 +0200 Subject: [PATCH 193/324] check fill scheme to clean FT0 BC in TOF calibs --- .../include/GlobalTracking/MatchTOF.h | 3 +++ Detectors/GlobalTracking/src/MatchTOF.cxx | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h index fbaef9a8a0c1f..0e19b15d9a401 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h @@ -223,6 +223,9 @@ class MatchTOF void updateTimeDependentParams(); + static bool mHasFillScheme; + static bool mFillScheme[o2::constants::lhc::LHCMaxBunches]; + //================================================================ // Data members diff --git a/Detectors/GlobalTracking/src/MatchTOF.cxx b/Detectors/GlobalTracking/src/MatchTOF.cxx index 81492a6fd7ae5..2fed841134117 100644 --- a/Detectors/GlobalTracking/src/MatchTOF.cxx +++ b/Detectors/GlobalTracking/src/MatchTOF.cxx @@ -53,6 +53,9 @@ using Cluster = o2::tof::Cluster; using GTrackID = o2::dataformats::GlobalTrackID; using timeEst = o2::dataformats::TimeStampWithError; +bool MatchTOF::mHasFillScheme = false; +bool MatchTOF::mFillScheme[o2::constants::lhc::LHCMaxBunches] = {0}; + ClassImp(MatchTOF); //______________________________________________ @@ -1187,19 +1190,30 @@ void MatchTOF::doMatchingForTPC(int sec) //______________________________________________ int MatchTOF::findFITIndex(int bc, const gsl::span& FITRecPoints, unsigned long firstOrbit) { + if ((!mHasFillScheme) && o2::tof::Utils::hasFillScheme()) { + mHasFillScheme = true; + for (int ibc = 0; ibc < o2::tof::Utils::getNinteractionBC(); ibc++) { + mFillScheme[o2::tof::Utils::getInteractionBC(ibc)] = true; + } + } + if (FITRecPoints.size() == 0) { return -1; } int index = -1; - int distMax = 7; // require bc distance below 5 + int distMax = 0; + const int distThr = 8; for (unsigned int i = 0; i < FITRecPoints.size(); i++) { const o2::InteractionRecord ir = FITRecPoints[i].getInteractionRecord(); + if (mHasFillScheme && !mFillScheme[ir.bc]) { + continue; + } int bct0 = (ir.orbit - firstOrbit) * o2::constants::lhc::LHCMaxBunches + ir.bc; int dist = bc - bct0; - if (dist < 0 || dist > distMax) { + if (dist < 0 || dist > distThr || dist < distMax) { continue; } From c3355cda90a6e012554a144de09cdb597399d987 Mon Sep 17 00:00:00 2001 From: swenzel Date: Thu, 14 Sep 2023 16:46:40 +0200 Subject: [PATCH 194/324] MCTrack: Generalize hit bit property So far, every possible sensitive detector for ALICE Run3 had a dedicated bit assigned inside MCTracks. The number of such bit was fixed to be 22 maximally. In this way we could store information if a particular Monte Carlo track caused energy deposits in detectors. Since more and more detectors are being added to the code (ALICE3, ITS3, R&D), we'll soon have more than 22 DetIDs in our code which will conflict with the space available in MCTrack. Since enlarging the MCTrack class in memory is to be avoided, this commit proposes a solution based on an intermediate lookup table which dynamically maps the detector ID to a particular bit. The lookup table is setup during geometry construction and stored in MCEventHeaders for offline use. This solution should scale much further than before. The limit is now 22 simultaneous sensitive detectors in the geometry and not 22 total sensitive detectors in the code. --- .../SimulationDataFormat/MCEventHeader.h | 6 +- .../include/SimulationDataFormat/MCTrack.h | 36 ++++++++--- DataFormats/simulation/test/MCTrack.cxx | 15 +++-- .../Base/include/DetectorsBase/Detector.h | 6 ++ Detectors/Base/src/Detector.cxx | 1 + Detectors/Base/src/Stack.cxx | 11 +++- Steer/src/O2MCApplication.cxx | 1 + macro/build_geometry.C | 55 ++++++++++------ run/SimExamples/Inspect_Hits/left_trace.macro | 62 +++++++++---------- .../Inspect_Hits/primary_and_hits.macro | 6 +- .../Inspect_Hits/secondary_and_hits.macro | 8 ++- run/checkStack.cxx | 9 ++- 12 files changed, 145 insertions(+), 71 deletions(-) diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h index cf323e197392d..1532973778eed 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h @@ -86,6 +86,9 @@ class MCEventHeader : public FairMCEventHeader MCEventStats& getMCEventStats() { return mEventStats; } + void setDetId2HitBitLUT(std::vector const& v) { mDetId2HitBitIndex = v; } + std::vector const& getDetId2HitBitLUT() const { return mDetId2HitBitIndex; } + /// create a standalone ROOT file/tree with only the MCHeader branch static void extractFileFromKinematics(std::string_view kinefilename, std::string_view targetfilename); @@ -96,9 +99,10 @@ class MCEventHeader : public FairMCEventHeader // store a few global properties that this event // had in the current simulation (which can be used quick filtering/searching) MCEventStats mEventStats{}; + std::vector mDetId2HitBitIndex; o2::utils::RootSerializableKeyValueStore mEventInfo; - ClassDefOverride(MCEventHeader, 3); + ClassDefOverride(MCEventHeader, 4); }; /** class MCEventHeader **/ diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h b/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h index fd9b794e59d91..4ebf5fe0c579c 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h @@ -46,6 +46,8 @@ template class MCTrackT { public: + static constexpr int NHITBITS = 22; // do not modify this + /// Default constructor MCTrackT(); @@ -159,24 +161,40 @@ class MCTrackT void SetSecondMotherTrackId(Int_t id) { mSecondMotherTrackId = id; } void SetFirstDaughterTrackId(Int_t id) { mFirstDaughterTrackId = id; } void SetLastDaughterTrackId(Int_t id) { mLastDaughterTrackId = id; } + // set bit indicating that this track - // left a hit in detector with id iDet - void setHit(Int_t iDet) + // left a hit in detector that corresponds to bit iDetBit. This bit is found in + // a lookup table. + void setHit(Int_t iDetBit) { - assert(0 <= iDet && iDet < o2::detectors::DetID::nDetectors); + assert(0 <= iDetBit && iDetBit < o2::detectors::DetID::nDetectors); auto prop = ((PropEncoding)mProp); - prop.hitmask |= 1 << iDet; + prop.hitmask |= 1 << iDetBit; mProp = prop.i; } - // did detector iDet see this track? - bool leftTrace(Int_t iDet) const { return (((PropEncoding)mProp).hitmask & (1 << iDet)) > 0; } + bool leftTraceGivenBitField(int bit) const + { + return (((PropEncoding)mProp).hitmask & (1 << bit)) > 0; + } + + /// Returns of detector with DetID iDet has seen this track. + /// Needs lookup table detIDToBit mapping detectorIDs to bitfields (which is persistified in MCEventHeaders). + bool leftTrace(Int_t iDet, std::vector const& detIDtoBit) const + { + auto bit = detIDtoBit[iDet]; + if (bit != -1) { + return leftTraceGivenBitField(bit); + } + return false; + } + // determine how many detectors "saw" this track int getNumDet() const { int count = 0; - for (auto i = o2::detectors::DetID::First; i < o2::detectors::DetID::nDetectors; ++i) { - if (leftTrace(i)) { + for (auto i = 0; i < NHITBITS; ++i) { + if (leftTraceGivenBitField(i)) { count++; } } @@ -261,7 +279,7 @@ class MCTrackT struct { int storage : 1; // encoding whether to store this track to the output unsigned int process : 6; // encoding process that created this track (enough to store TMCProcess from ROOT) - int hitmask : 22; // encoding hits per detector + int hitmask : NHITBITS; // encoding hits per detector static_assert(o2::detectors::DetID::nDetectors <= 22); // ensure that all known detectors can be encoded here by a bit int reserved1 : 1; // bit reserved for possible future purposes int inhibited : 1; // whether tracking of this was inhibited diff --git a/DataFormats/simulation/test/MCTrack.cxx b/DataFormats/simulation/test/MCTrack.cxx index 699adc89abb8c..e857e2b88da41 100644 --- a/DataFormats/simulation/test/MCTrack.cxx +++ b/DataFormats/simulation/test/MCTrack.cxx @@ -24,10 +24,17 @@ using namespace o2; BOOST_AUTO_TEST_CASE(MCTrack_test) { MCTrack track; + + // auxiliary lookup table needed to fetch and set hit properties + std::vector hitLUT(o2::detectors::DetID::nDetectors, -1); + // in this test we have a single fictional detector 1, which we map to + // the first bit + hitLUT[1] = 0; + // check properties on default constructed object BOOST_CHECK(track.getStore() == false); for (auto i = o2::detectors::DetID::First; i < o2::detectors::DetID::nDetectors; ++i) { - BOOST_CHECK(track.leftTrace(i) == false); + BOOST_CHECK(track.leftTrace(i, hitLUT) == false); } BOOST_CHECK(track.getNumDet() == 0); BOOST_CHECK(track.hasHits() == false); @@ -41,10 +48,10 @@ BOOST_AUTO_TEST_CASE(MCTrack_test) BOOST_CHECK(track.getStore() == true); // set hit for first detector - BOOST_CHECK(track.leftTrace(1) == false); - track.setHit(1); + BOOST_CHECK(track.leftTrace(1, hitLUT) == false); + track.setHit(hitLUT[1]); BOOST_CHECK(track.hasHits() == true); - BOOST_CHECK(track.leftTrace(1) == true); + BOOST_CHECK(track.leftTrace(1, hitLUT) == true); BOOST_CHECK(track.getNumDet() == 1); // check process encoding diff --git a/Detectors/Base/include/DetectorsBase/Detector.h b/Detectors/Base/include/DetectorsBase/Detector.h index 73764e8b7021b..6acfa4f5cc46c 100644 --- a/Detectors/Base/include/DetectorsBase/Detector.h +++ b/Detectors/Base/include/DetectorsBase/Detector.h @@ -216,6 +216,10 @@ class Detector : public FairDetector // which is required for media creation static void initFieldTrackingParams(int& mode, float& maxfield); + /// set the DetID to HitBitIndex mapping. Succeeds if not already set. + static void setDetId2HitBitIndex(std::vector const& v) { Detector::sDetId2HitBitIndex = v; } + static std::vector const& getDetId2HitBitIndex() { return Detector::sDetId2HitBitIndex; } + protected: Detector(const Detector& origin); @@ -233,6 +237,7 @@ class Detector : public FairDetector static Float_t mDensityFactor; //! factor that is multiplied to all material densities (ONLY for // systematic studies) + static std::vector sDetId2HitBitIndex; //! global lookup table keeping mapping of DetID to index in hit bit field (used in MCTrack) ClassDefOverride(Detector, 1); // Base class for ALICE Modules }; @@ -738,6 +743,7 @@ class DetImpl : public o2::base::Detector int mInitialized = false; char* mHitCollectorBufferPtr = nullptr; //! pointer to hit (collector) buffer location (strictly internal) + ClassDefOverride(DetImpl, 0); }; } // namespace base diff --git a/Detectors/Base/src/Detector.cxx b/Detectors/Base/src/Detector.cxx index e93295f1fc3f6..3168e0e84e1f2 100644 --- a/Detectors/Base/src/Detector.cxx +++ b/Detectors/Base/src/Detector.cxx @@ -30,6 +30,7 @@ using namespace o2::base; using namespace o2::detectors; Float_t Detector::mDensityFactor = 1.0; +std::vector o2::base::Detector::sDetId2HitBitIndex{}; // initialize empty vector Detector::Detector() : FairDetector(), mMapMaterial(), mMapMedium() {} Detector::Detector(const char* name, Bool_t Active) diff --git a/Detectors/Base/src/Stack.cxx b/Detectors/Base/src/Stack.cxx index b5873165a0e46..64daf2eccefc5 100644 --- a/Detectors/Base/src/Stack.cxx +++ b/Detectors/Base/src/Stack.cxx @@ -638,14 +638,17 @@ void Stack::Print(Option_t* option) const void Stack::addHit(int iDet) { + // translate detector ID to bit id + const auto bitID = o2::base::Detector::getDetId2HitBitIndex()[iDet]; + if (mIndexOfCurrentTrack < mNumberOfPrimaryParticles) { auto& part = mTracks->at(mIndexOfCurrentTrack); - part.setHit(iDet); + part.setHit(bitID); } else { Int_t iTrack = mTrackIDtoParticlesEntry[mIndexOfCurrentTrack]; auto& part = mParticles[iTrack]; - part.setHit(iDet); + part.setHit(bitID); } mCurrentParticle.SetBit(ParticleStatus::kHasHits, 1); mHitCounter++; @@ -654,7 +657,9 @@ void Stack::addHit(int iDet, Int_t iTrack) { mHitCounter++; auto& part = mParticles[iTrack]; - part.setHit(iDet); + // fetch the bit encoding for hits + const auto bitID = o2::base::Detector::getDetId2HitBitIndex()[iDet]; + part.setHit(bitID); mCurrentParticle.SetBit(ParticleStatus::kHasHits, 1); } diff --git a/Steer/src/O2MCApplication.cxx b/Steer/src/O2MCApplication.cxx index ea4faab1c415f..64fe2281ed1b5 100644 --- a/Steer/src/O2MCApplication.cxx +++ b/Steer/src/O2MCApplication.cxx @@ -197,6 +197,7 @@ void O2MCApplicationBase::finishEventCommon() auto header = static_cast(fMCEventHeader); header->getMCEventStats().setNSteps(mStepCounter); + header->setDetId2HitBitLUT(o2::base::Detector::getDetId2HitBitIndex()); static_cast(GetStack())->updateEventStats(); } diff --git a/macro/build_geometry.C b/macro/build_geometry.C index 3caf94abd5323..de8e3ea98b6b8 100644 --- a/macro/build_geometry.C +++ b/macro/build_geometry.C @@ -179,103 +179,120 @@ void build_geometry(FairRunSim* run = nullptr) run->AddModule(new o2::passive::FrameStructure("FRAME", "Frame")); } + std::vector detId2RunningId = std::vector(o2::detectors::DetID::nDetectors, -1); // a mapping of detectorId to a dense runtime index + // used for instance to set bits in the hit structure of MCTracks; -1 means that there is no bit associated + + auto addReadoutDetector = [&detId2RunningId, &run](o2::base::Detector* detector) { + static int runningid = 0; // this is static for constant lambda interfaces --> use fixed type and not auto in the lambda! + run->AddModule(detector); + if (detector->IsActive()) { + auto detID = detector->GetDetId(); + detId2RunningId[detID] = runningid; + LOG(info) << " DETID " << detID << " vs " << detector->GetDetId() << " mapped to hit bit index " << runningid; + runningid++; + } + }; + if (isActivated("TOF")) { // TOF - run->AddModule(new o2::tof::Detector(isReadout("TOF"))); + addReadoutDetector(new o2::tof::Detector(isReadout("TOF"))); } if (isActivated("TRD")) { // TRD - run->AddModule(new o2::trd::Detector(isReadout("TRD"))); + addReadoutDetector(new o2::trd::Detector(isReadout("TRD"))); } if (isActivated("TPC")) { // tpc - run->AddModule(new o2::tpc::Detector(isReadout("TPC"))); + addReadoutDetector(new o2::tpc::Detector(isReadout("TPC"))); } #ifdef ENABLE_UPGRADES if (isActivated("IT3")) { // IT3 - run->AddModule(new o2::its::Detector(isReadout("IT3"), "IT3")); + addReadoutDetector(new o2::its::Detector(isReadout("IT3"), "IT3")); } if (isActivated("TRK")) { // ALICE 3 TRK - run->AddModule(new o2::trk::Detector(isReadout("TRK"))); + addReadoutDetector(new o2::trk::Detector(isReadout("TRK"))); } if (isActivated("FT3")) { // ALICE 3 FT3 - run->AddModule(new o2::ft3::Detector(isReadout("FT3"))); + addReadoutDetector(new o2::ft3::Detector(isReadout("FT3"))); } if (isActivated("FCT")) { // ALICE 3 FCT - run->AddModule(new o2::fct::Detector(isReadout("FCT"))); + addReadoutDetector(new o2::fct::Detector(isReadout("FCT"))); } #endif if (isActivated("ITS")) { // its - run->AddModule(new o2::its::Detector(isReadout("ITS"))); + addReadoutDetector(new o2::its::Detector(isReadout("ITS"))); } if (isActivated("MFT")) { // mft - run->AddModule(new o2::mft::Detector(isReadout("MFT"))); + addReadoutDetector(new o2::mft::Detector(isReadout("MFT"))); } if (isActivated("MCH")) { // mch - run->AddModule(new o2::mch::Detector(isReadout("MCH"))); + addReadoutDetector(new o2::mch::Detector(isReadout("MCH"))); } if (isActivated("MID")) { // mid - run->AddModule(new o2::mid::Detector(isReadout("MID"))); + addReadoutDetector(new o2::mid::Detector(isReadout("MID"))); } if (isActivated("EMC")) { // emcal - run->AddModule(new o2::emcal::Detector(isReadout("EMC"))); + addReadoutDetector(new o2::emcal::Detector(isReadout("EMC"))); } if (isActivated("PHS")) { // phos - run->AddModule(new o2::phos::Detector(isReadout("PHS"))); + addReadoutDetector(new o2::phos::Detector(isReadout("PHS"))); } if (isActivated("CPV")) { // cpv - run->AddModule(new o2::cpv::Detector(isReadout("CPV"))); + addReadoutDetector(new o2::cpv::Detector(isReadout("CPV"))); } if (isActivated("FT0")) { // FIT-T0 - run->AddModule(new o2::ft0::Detector(isReadout("FT0"))); + addReadoutDetector(new o2::ft0::Detector(isReadout("FT0"))); } if (isActivated("FV0")) { // FIT-V0 - run->AddModule(new o2::fv0::Detector(isReadout("FV0"))); + addReadoutDetector(new o2::fv0::Detector(isReadout("FV0"))); } if (isActivated("FDD")) { // FIT-FDD - run->AddModule(new o2::fdd::Detector(isReadout("FDD"))); + addReadoutDetector(new o2::fdd::Detector(isReadout("FDD"))); } if (isActivated("HMP")) { // HMP - run->AddModule(new o2::hmpid::Detector(isReadout("HMP"))); + addReadoutDetector(new o2::hmpid::Detector(isReadout("HMP"))); } if (isActivated("ZDC")) { // ZDC - run->AddModule(new o2::zdc::Detector(isReadout("ZDC"))); + addReadoutDetector(new o2::zdc::Detector(isReadout("ZDC"))); } if (geomonly) { run->Init(); } + + // register the DetId2HitIndex lookup with the detector class by copying the vector + o2::base::Detector::setDetId2HitBitIndex(detId2RunningId); } diff --git a/run/SimExamples/Inspect_Hits/left_trace.macro b/run/SimExamples/Inspect_Hits/left_trace.macro index 3c3adb6bd033f..88bc4e592edda 100644 --- a/run/SimExamples/Inspect_Hits/left_trace.macro +++ b/run/SimExamples/Inspect_Hits/left_trace.macro @@ -1,54 +1,54 @@ bool -leftTrace_golden(o2::MCTrack& t) +leftTrace_golden(o2::MCTrack& t, std::vector const& bitLUT) { bool trace = false; - trace |= t.leftTrace(o2::detectors::DetID::ITS); - trace |= t.leftTrace(o2::detectors::DetID::TPC); - trace |= t.leftTrace(o2::detectors::DetID::TRD); - trace |= t.leftTrace(o2::detectors::DetID::TOF); + trace |= t.leftTrace(o2::detectors::DetID::ITS, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::TPC, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::TRD, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::TOF, bitLUT); return trace; } bool -leftTrace_barrel(o2::MCTrack& t) +leftTrace_barrel(o2::MCTrack& t, std::vector const& bitLUT) { bool trace = false; - trace |= t.leftTrace(o2::detectors::DetID::ITS); - trace |= t.leftTrace(o2::detectors::DetID::TPC); - trace |= t.leftTrace(o2::detectors::DetID::TRD); - trace |= t.leftTrace(o2::detectors::DetID::TOF); - trace |= t.leftTrace(o2::detectors::DetID::HMP); - trace |= t.leftTrace(o2::detectors::DetID::EMC); - trace |= t.leftTrace(o2::detectors::DetID::PHS); - trace |= t.leftTrace(o2::detectors::DetID::FV0); - trace |= t.leftTrace(o2::detectors::DetID::FT0); - return trace; + trace |= t.leftTrace(o2::detectors::DetID::ITS, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::TPC, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::TRD, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::TOF, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::HMP, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::EMC, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::PHS, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::FV0, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::FT0, bitLUT); + return trace; } bool -leftTrace_muon(o2::MCTrack& t) +leftTrace_muon(o2::MCTrack& t, std::vector const& bitLUT) { bool trace = false; - trace |= t.leftTrace(o2::detectors::DetID::ITS); - trace |= t.leftTrace(o2::detectors::DetID::FV0); - trace |= t.leftTrace(o2::detectors::DetID::FT0); - trace |= t.leftTrace(o2::detectors::DetID::MFT); - trace |= t.leftTrace(o2::detectors::DetID::MCH); - trace |= t.leftTrace(o2::detectors::DetID::MID); - return trace; + trace |= t.leftTrace(o2::detectors::DetID::ITS, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::FV0, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::FT0, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::MFT, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::MCH, bitLUT); + trace |= t.leftTrace(o2::detectors::DetID::MID, bitLUT); + return trace; } bool -leftTrace_any(o2::MCTrack& t) +leftTrace_any(o2::MCTrack& t, std::vector const& bitLUT) { - return leftTrace_barrel(t) || leftTrace_muon(t); + return leftTrace_barrel(t, bitLUT) || leftTrace_muon(t, bitLUT); } -std::function leftTrace_selected = leftTrace_barrel; +std::function const&)> leftTrace_selected = leftTrace_barrel; /* -std::map leftTrace = { +std::map const&)> leftTrace = { {"golden", leftTrace_golden}, {"barrel", leftTrace_barrel}, {"muon" , leftTrace_muon} , @@ -57,8 +57,8 @@ std::map leftTrace = { */ bool -leftTrace(o2::MCTrack& t, vector* tracks) { - if (leftTrace_selected(t)) return true; // this track has left trace in requested detectors +leftTrace(o2::MCTrack& t, vector* tracks, std::vector const& bitLUT) { + if (leftTrace_selected(t, bitLUT)) return true; // this track has left trace in requested detectors // if (leftTrace_barrel(t)) return true; // this track has left trace in requested detectors // check if any of the daughters left trace auto id1 = t.getFirstDaughterTrackId(); @@ -67,7 +67,7 @@ leftTrace(o2::MCTrack& t, vector* tracks) { bool trace = false; for (int id = id1; id <= id2; ++id) { auto d = tracks->at(id); - trace |= leftTrace(d, tracks); // at least one daughter has left trace + trace |= leftTrace(d, tracks, bitLUT); // at least one daughter has left trace } return trace; } diff --git a/run/SimExamples/Inspect_Hits/primary_and_hits.macro b/run/SimExamples/Inspect_Hits/primary_and_hits.macro index dd8ce743d58c0..94f941b31bfd1 100644 --- a/run/SimExamples/Inspect_Hits/primary_and_hits.macro +++ b/run/SimExamples/Inspect_Hits/primary_and_hits.macro @@ -15,6 +15,10 @@ primary_and_hits(const char *fname, std::string where = "barrel") tin->SetBranchAddress("MCTrack", &tracks); auto nev = tin->GetEntries(); + // get the LUT for detector ID to bit index for hits + o2::dataformats::MCEventHeader *m = nullptr; + tin->SetBranchAddress("MCEventHeader.", &m); + std::map hEtaPtGen, hEtaPtHit; for (int iev = 0; iev < nev; ++iev) { @@ -31,7 +35,7 @@ primary_and_hits(const char *fname, std::string where = "barrel") hEtaPtGen[pdg]->Fill(t.GetEta(), t.GetPt()); - if (!leftTrace(t, tracks)) continue; + if (!leftTrace(t, tracks, m->getDetId2HitBitLUT())) continue; hEtaPtHit[pdg]->Fill(t.GetEta(), t.GetPt()); diff --git a/run/SimExamples/Inspect_Hits/secondary_and_hits.macro b/run/SimExamples/Inspect_Hits/secondary_and_hits.macro index 9a21924e62b2d..8e34faaecb21a 100644 --- a/run/SimExamples/Inspect_Hits/secondary_and_hits.macro +++ b/run/SimExamples/Inspect_Hits/secondary_and_hits.macro @@ -15,6 +15,10 @@ secondary_and_hits(const char *fname, std::string where = "barrel") tin->SetBranchAddress("MCTrack", &tracks); auto nev = tin->GetEntries(); + // get the LUT for detector ID to bit index for hits + o2::dataformats::MCEventHeader *m = nullptr; + tin->SetBranchAddress("MCEventHeader.", &m); + std::map hZRGen, hZRHit; for (int iev = 0; iev < nev; ++iev) { @@ -32,7 +36,9 @@ secondary_and_hits(const char *fname, std::string where = "barrel") auto R = std::hypot(t.GetStartVertexCoordinatesX(), t.GetStartVertexCoordinatesY()); hZRGen[pdg]->Fill(z, R); - if (!leftTrace(t, tracks)) continue; + if (!leftTrace(t, tracks, m->getDetId2HitBitLUT())) { + continue; + } hZRHit[pdg]->Fill(z, R); diff --git a/run/checkStack.cxx b/run/checkStack.cxx index 4c7aa3516c402..4470ea463fd98 100644 --- a/run/checkStack.cxx +++ b/run/checkStack.cxx @@ -89,6 +89,9 @@ int main(int argc, char** argv) std::vector trackidsinTPC; std::vector trackidsinITS; + // fetch the encoding of DetIDs to bits for the hit properties (can be fetched from any MCEventHeader) + auto& mcEventHeader = mcreader.getMCEventHeader(0, 0); + int primaries = 0; int physicalprimaries = 0; int secondaries = 0; @@ -103,12 +106,14 @@ int main(int argc, char** argv) // for primaries, this may be different (for instance with Pythia8) assert(ti > t.getMotherTrackId()); } - if (t.leftTrace(o2::detectors::DetID::TPC)) { + + if (t.leftTrace(o2::detectors::DetID::TPC, mcEventHeader.getDetId2HitBitLUT())) { trackidsinTPC.emplace_back(ti); } - if (t.leftTrace(o2::detectors::DetID::ITS)) { + if (t.leftTrace(o2::detectors::DetID::ITS, mcEventHeader.getDetId2HitBitLUT())) { trackidsinITS.emplace_back(ti); } + bool physicalPrim = o2::mcutils::MCTrackNavigator::isPhysicalPrimary(t, *mctracks); LOG(debug) << " track " << ti << "\t" << t.getMotherTrackId() << " hits " << t.hasHits() << " isPhysicalPrimary " << physicalPrim; if (t.isPrimary()) { From 258f604b8d06bdbd346270157bc26e587d294b71 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 3 Oct 2023 16:42:57 +0200 Subject: [PATCH 195/324] Fix macro tests when using boost 1.82 / 1.83 (#12007) --- Common/Utils/include/CommonUtils/ShmManager.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Common/Utils/include/CommonUtils/ShmManager.h b/Common/Utils/include/CommonUtils/ShmManager.h index 9b2029df658fd..e7174b909b82c 100644 --- a/Common/Utils/include/CommonUtils/ShmManager.h +++ b/Common/Utils/include/CommonUtils/ShmManager.h @@ -23,8 +23,10 @@ #include #include +#if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) #include #include +#endif #if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) && !defined(__APPLE__) // this shared mem mode is meant for compiled stuff in o2-sim; not for ROOT sessions @@ -116,8 +118,10 @@ class ShmManager void* tryAttach(bool& success); size_t getPointerOffset(void* ptr) const { return (size_t)((char*)ptr - (char*)mBufferPtr); } +#if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) boost::interprocess::wmanaged_external_buffer* boostmanagedbuffer; boost::interprocess::allocator* boostallocator; +#endif }; } // namespace utils From a0699f10b92072fc25b969dfa5730a0ca57c917c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesus=20Eduardo=20Mu=C3=B1oz=20Mendez?= Date: Mon, 2 Oct 2023 11:47:18 +0200 Subject: [PATCH 196/324] Add Alice3 absorber --- Common/SimConfig/src/SimConfig.cxx | 3 +- .../Upgrades/ALICE3/Passive/CMakeLists.txt | 4 +- .../include/Alice3DetectorsPassive/Absorber.h | 42 +++++ .../Upgrades/ALICE3/Passive/src/Absorber.cxx | 164 ++++++++++++++++++ .../ALICE3/Passive/src/PassiveLinkDef.h | 3 +- macro/build_geometry.C | 7 + 6 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/Absorber.h create mode 100644 Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx diff --git a/Common/SimConfig/src/SimConfig.cxx b/Common/SimConfig/src/SimConfig.cxx index a35019648abb9..f80a64e62220d 100644 --- a/Common/SimConfig/src/SimConfig.cxx +++ b/Common/SimConfig/src/SimConfig.cxx @@ -93,11 +93,12 @@ void SimConfig::determineActiveModules(std::vector const& inputargs #ifdef ENABLE_UPGRADES if (mIsRun5) { for (int d = DetID::First; d <= DetID::Last; ++d) { - if (d == DetID::IT3 || d == DetID::TRK || d == DetID::FT3 || d == DetID::FCT) { + if (d == DetID::TRK || d == DetID::FT3 || d == DetID::FCT) { activeModules.emplace_back(DetID::getName(d)); } } activeModules.emplace_back("A3IP"); + activeModules.emplace_back("A3ABSO"); } else { #endif // add passive components manually (make a PassiveDetID for them!) diff --git a/Detectors/Upgrades/ALICE3/Passive/CMakeLists.txt b/Detectors/Upgrades/ALICE3/Passive/CMakeLists.txt index 7333d7584a7cc..6d2e9433418aa 100644 --- a/Detectors/Upgrades/ALICE3/Passive/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/Passive/CMakeLists.txt @@ -12,9 +12,11 @@ o2_add_library(Alice3DetectorsPassive SOURCES src/Pipe.cxx src/PassiveBase.cxx + src/Absorber.cxx PUBLIC_LINK_LIBRARIES O2::Field O2::DetectorsBase O2::SimConfig) o2_target_root_dictionary(Alice3DetectorsPassive HEADERS include/Alice3DetectorsPassive/Pipe.h include/Alice3DetectorsPassive/PassiveBase.h - LINKDEF src/PassiveLinkDef.h) \ No newline at end of file + include/Alice3DetectorsPassive/Absorber.h + LINKDEF src/PassiveLinkDef.h) diff --git a/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/Absorber.h b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/Absorber.h new file mode 100644 index 0000000000000..db8b7627ee79e --- /dev/null +++ b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/Absorber.h @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICE3_PASSIVE_ABSORBER_H +#define ALICE3_PASSIVE_ABSORBER_H + +#include "Alice3DetectorsPassive/PassiveBase.h" + +namespace o2 +{ +namespace passive +{ +class Alice3Absorber : public Alice3PassiveBase +{ + public: + Alice3Absorber(const char* name, const char* Title = "ALICE3 Absorber"); + Alice3Absorber(); + ~Alice3Absorber() override; + void ConstructGeometry() override; + void createMaterials(); + + /// Clone this object (used in MT mode only) + FairModule* CloneModule() const override; + + private: + Alice3Absorber(const Alice3Absorber& orig); + Alice3Absorber& operator=(const Alice3Absorber&); + + ClassDefOverride(o2::passive::Alice3Absorber, 1); +}; +} // namespace passive +} // namespace o2 + +#endif diff --git a/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx b/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx new file mode 100644 index 0000000000000..7cb0148c12dc9 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx @@ -0,0 +1,164 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include +#include // for TGeoTrap +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef NDEBUG +#undef NDEBUG +#endif +#include + +using namespace o2::passive; + +Alice3Absorber::~Alice3Absorber() = default; + +Alice3Absorber::Alice3Absorber() : Alice3PassiveBase("A3ABSO", "") {} +Alice3Absorber::Alice3Absorber(const char* name, const char* Title) : Alice3PassiveBase(name, Title) {} +Alice3Absorber::Alice3Absorber(const Alice3Absorber& rhs) = default; + +Alice3Absorber& Alice3Absorber::operator=(const Alice3Absorber& rhs) +{ + // self assignment + if (this == &rhs) { + return *this; + } + + // base class assignment + FairModule::operator=(rhs); + + return *this; +} + +void Alice3Absorber::createMaterials() +{ + + auto& matmgr = o2::base::MaterialManager::Instance(); + // Define materials for muon absorber + // + Int_t isxfld = 2.; + Float_t sxmgmx = 10.; + o2::base::Detector::initFieldTrackingParams(isxfld, sxmgmx); + + // + // Steel + // + Float_t asteel[4] = {55.847, 51.9961, 58.6934, 28.0855}; + Float_t zsteel[4] = {26., 24., 28., 14.}; + Float_t wsteel[4] = {.715, .18, .1, .005}; + // + // Air + // + float aAir[4] = {12.0107, 14.0067, 15.9994, 39.948}; + float zAir[4] = {6., 7., 8., 18.}; + float wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827}; + float dAir = 1.20479E-3; + float dAir1 = 1.20479E-11; + + // **************** + // Defines tracking media parameters. + // + Float_t epsil, stmin, tmaxfd, deemax, stemax; + epsil = .001; // Tracking precision, + stemax = -0.01; // Maximum displacement for multiple scat + tmaxfd = -20.; // Maximum angle due to field deflection + deemax = -.3; // Maximum fractional energy loss, DLS + stmin = -.8; + // *************** + // + + matmgr.Mixture("ALICE3ABSO", 16, "VACUUM0$", aAir, zAir, dAir1, 4, wAir); + matmgr.Medium("ALICE3ABSO", 16, "VA_C0", 16, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); + + // + // Steel + matmgr.Mixture("ALICE3ABSO", 19, "STAINLESS STEEL0$", asteel, zsteel, 7.88, 4, wsteel); + matmgr.Mixture("ALICE3ABSO", 39, "STAINLESS STEEL1$", asteel, zsteel, 7.88, 4, wsteel); + matmgr.Mixture("ALICE3ABSO", 59, "STAINLESS STEEL2$", asteel, zsteel, 7.88, 4, wsteel); + matmgr.Medium("ALICE3ABSO", 19, "ST_C0", 19, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); + matmgr.Medium("ALICE3ABSO", 39, "ST_C1", 39, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); + matmgr.Medium("ALICE3ABSO", 59, "ST_C3", 59, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); +} + +void Alice3Absorber::ConstructGeometry() +{ + createMaterials(); + + // + // Build muon shield geometry + // + // + + auto& matmgr = o2::base::MaterialManager::Instance(); + + // + // Media + // + + auto kMedVac = matmgr.getTGeoMedium("ALICE3ABSO_VA_C0"); + auto kMedSteel = matmgr.getTGeoMedium("ALICE3ABSO_ST_C0"); + auto kMedSteelSh = matmgr.getTGeoMedium("ALICE3ABSO_ST_C3"); + + // The top volume + TGeoVolume* top = gGeoManager->GetVolume("cave"); + TGeoVolume* barrel = gGeoManager->GetVolume("barrel"); + if (!barrel) { + LOG(fatal) << "Could not find the top volume"; + } + + TGeoPcon* absorings = new TGeoPcon(0., 360., 18); + + absorings->DefineSection(0, 500, 236, 274); + absorings->DefineSection(1, 400, 236, 274); + absorings->DefineSection(2, 400, 232.5, 277.5); + absorings->DefineSection(3, 300, 232.5, 277.5); + absorings->DefineSection(4, 300, 227.5, 282.5); + absorings->DefineSection(5, 200, 227.5, 282.5); + absorings->DefineSection(6, 200, 222.5, 287.5); + absorings->DefineSection(7, 100, 222.5, 287.5); + absorings->DefineSection(8, 100, 220, 290); + absorings->DefineSection(9, -100, 220, 290); + absorings->DefineSection(10, -100, 222.5, 287.5); + absorings->DefineSection(11, -200, 222.5, 287.5); + absorings->DefineSection(12, -200, 227.5, 282.5); + absorings->DefineSection(13, -300, 227.5, 282.5); + absorings->DefineSection(14, -300, 232.5, 277.5); + absorings->DefineSection(15, -400, 232.5, 277.5); + absorings->DefineSection(16, -400, 236, 274); + absorings->DefineSection(17, -500, 236, 274); + + // Insert + absorings->SetName("absorings"); + + TGeoVolume* abso = new TGeoVolume("Absorber", absorings, kMedSteel); + + abso->SetVisibility(1); + abso->SetTransparency(50); + abso->SetLineColor(kGray); + + // + // Adding volumes to mother volume + // + + barrel->AddNode(abso, 1, new TGeoTranslation(0, 30.f, 0)); +} + +FairModule* Alice3Absorber::CloneModule() const { return new Alice3Absorber(*this); } +ClassImp(o2::passive::Alice3Absorber); diff --git a/Detectors/Upgrades/ALICE3/Passive/src/PassiveLinkDef.h b/Detectors/Upgrades/ALICE3/Passive/src/PassiveLinkDef.h index bab082778a4c2..7974620fec1c6 100644 --- a/Detectors/Upgrades/ALICE3/Passive/src/PassiveLinkDef.h +++ b/Detectors/Upgrades/ALICE3/Passive/src/PassiveLinkDef.h @@ -17,5 +17,6 @@ #pragma link C++ class o2::passive::Alice3PassiveBase + ; #pragma link C++ class o2::passive::Alice3Pipe + ; +#pragma link C++ class o2::passive::Alice3Absorber + ; -#endif \ No newline at end of file +#endif diff --git a/macro/build_geometry.C b/macro/build_geometry.C index de8e3ea98b6b8..85a3ae30481b1 100644 --- a/macro/build_geometry.C +++ b/macro/build_geometry.C @@ -54,6 +54,7 @@ #include #include #include +#include #endif void finalize_geometry(FairRunSim* run); @@ -161,6 +162,12 @@ void build_geometry(FairRunSim* run = nullptr) if (isActivated("A3IP")) { run->AddModule(new o2::passive::Alice3Pipe("A3IP", "Alice 3 beam pipe", !isActivated("TRK"), 0.48f, 0.025f, 1000.f, 3.7f, 0.08f, 1000.f)); } + + // the absorber + if (isActivated("A3ABSO")) { + run->AddModule(new o2::passive::Alice3Absorber("A3ABSO", "ALICE3 Absorber")); + } + #endif // the absorber From 4d396f1862301ce129de9cb0a6f5b8fa5f9ee66c Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 4 Oct 2023 06:51:32 +0200 Subject: [PATCH 197/324] Fix deprecation warning (#12006) --- Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx index 466c892350162..b45614d64c268 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx @@ -1585,7 +1585,7 @@ void ITSThresholdCalibrator::addDatabaseEntry( this->mp.expandChipInfoHW(chipID, lay, sta, ssta, mod, chipInMod); char stave[6]; - sprintf(stave, "L%d_%02d", lay, sta); + snprintf(stave, 6, "L%d_%02d", lay, sta); if (isQC) { o2::dcs::addConfigItem(this->mChipDoneQc, "O2ChipID", std::to_string(chipID)); From d6fa38b108e12fa0f0a782650b84a6dcf54b7426 Mon Sep 17 00:00:00 2001 From: shahoian Date: Wed, 4 Oct 2023 00:14:04 +0200 Subject: [PATCH 198/324] Decrease max error count, err->warn for *Wrong order/duplication* --- .../ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx b/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx index c3fe5b4971032..980b673e802ef 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx @@ -375,10 +375,10 @@ ChipPixelData* RawPixelDecoder::getNextChipData(std::vector= chipData.getChipID()) { if (!mROFRampUpStage) { - const int MaxErrLog = 5; + const int MaxErrLog = 2; static int errLocCount = 0; if (errLocCount < MaxErrLog) { - LOGP(error, "Wrong order/duplication: encountered chip {} after processing chip {}, skippin. Inform PDP (message {} of max {} allowed)", + LOGP(warn, "Wrong order/duplication: encountered chip {} after processing chip {}, skipping.", chipData.getChipID(), mLastReadChipID, ++errLocCount, MaxErrLog); } } From 0d766df7ec168df6818715e3ee556c3084aec528 Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Tue, 3 Oct 2023 10:02:14 +0200 Subject: [PATCH 199/324] TRD PH calib send dummy message even if STOP requested --- .../TRD/workflow/include/TRDWorkflow/TRDPulseHeightSpec.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDPulseHeightSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDPulseHeightSpec.h index 01688842333b4..6ba185ee28ccb 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDPulseHeightSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/TRDPulseHeightSpec.h @@ -22,6 +22,7 @@ #include "DetectorsBase/GRPGeomHelper.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "TRDCalibration/PulseHeight.h" +#include "DataFormatsTRD/PHData.h" using namespace o2::framework; using GID = o2::dataformats::GlobalTrackID; @@ -50,6 +51,8 @@ class PuseHeightDevice : public o2::framework::Task mRunStopRequested = false; } if (mRunStopRequested) { + std::vector mPHValues{}; // the calibration expects data at every TF, so inject dummy + pc.outputs().snapshot(Output{"TRD", "PULSEHEIGHT", 0, Lifetime::Timeframe}, mPHValues); return; } RecoContainer recoData; From db84bf6084c317d1e8ae334376e2d5d8be617dc8 Mon Sep 17 00:00:00 2001 From: Michael Lettrich Date: Mon, 2 Oct 2023 21:12:47 +0200 Subject: [PATCH 200/324] [rANS] Enforce Consistent Histograms --- .../DetectorsCommonDataFormats/EncodedBlocks.h | 18 +++++++++++++++++- .../rANS/internal/containers/DenseHistogram.h | 11 ++++++++++- .../include/rANS/internal/transform/renorm.h | 2 +- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index 13cd7d2b122d5..6afc171a79d7c 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -339,7 +339,10 @@ class EncodedBlocks using dictionaryType = std::variant, rans::RenormedDenseHistogram>; #endif - void setHeader(const H& h) { mHeader = h; } + void setHeader(const H& h) + { + mHeader = h; + } const H& getHeader() const { return mHeader; } H& getHeader() { return mHeader; } std::shared_ptr cloneHeader() const { return std::shared_ptr(new H(mHeader)); } // for dictionary creation @@ -371,6 +374,19 @@ class EncodedBlocks assert(static_cast(std::numeric_limits::min()) <= static_cast(metadata.max)); assert(static_cast(std::numeric_limits::max()) >= static_cast(metadata.min)); + // check consistency of metadata and type + [&]() { + const int64_t sourceMin = std::numeric_limits::min(); + const int64_t sourceMax = std::numeric_limits::max(); + + const int64_t mdMin = metadata.min; + const int64_t mdMax = metadata.max; + + if ((mdMin < sourceMin) || (mdMax > sourceMax)) { + throw std::runtime_error(fmt::format("value range of dictionary and target datatype are incompatible: target type [{},{}] vs dictionary [{},{}]", sourceMin, sourceMax, mdMin, mdMax)); + } + }(); + if (ansVersion == ANSVersionCompat) { rans::DenseHistogram histogram{block.getDict(), block.getDict() + block.getNDict(), metadata.min}; return rans::compat::renorm(std::move(histogram), metadata.probabilityBits); diff --git a/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h b/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h index 354ee96b84f48..844e0c9695a32 100644 --- a/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h +++ b/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h @@ -586,7 +586,16 @@ auto DenseHistogram>::addFrequ addedHistogramView = trim(addedHistogramView); if constexpr (std::is_unsigned_v) { - LOG_IF(warning, addedHistogramView.getMin() < 0) << fmt::format("trying to add frequencies for a signed symbol to a DenseHistogram of an unsiged type."); + LOG_IF(warning, addedHistogramView.getMin() < 0) << fmt::format("trying to add frequencies of a signed symbol type to a DenseHistogram of an unsiged type."); + } + if constexpr (std::is_signed_v) { + const std::ptrdiff_t sourceTypeMax = std::numeric_limits::max(); + const bool isMinOutOfRange = addedHistogramView.getMin() > sourceTypeMax; + const bool isMaxOutOfRange = addedHistogramView.getMax() > sourceTypeMax; + + if (isMaxOutOfRange || isMinOutOfRange) { + LOGP(warning, "trying to add frequencies of an unsigned symbol type to a DenseHistogram of a signed type"); + } } const auto thisHistogramView = makeHistogramView(this->mContainer); diff --git a/Utilities/rANS/include/rANS/internal/transform/renorm.h b/Utilities/rANS/include/rANS/internal/transform/renorm.h index 5e3d7d551a665..5d55b3553ceca 100644 --- a/Utilities/rANS/include/rANS/internal/transform/renorm.h +++ b/Utilities/rANS/include/rANS/internal/transform/renorm.h @@ -143,7 +143,7 @@ decltype(auto) renorm(histogram_T histogram, Metrics Date: Tue, 3 Oct 2023 22:29:54 +0200 Subject: [PATCH 201/324] [rANS] Fix Compiler Warnings --- .../DetectorsCommonDataFormats/EncodedBlocks.h | 4 +--- .../internal/ExternalEntropyCoder.h | 2 +- .../internal/InplaceEntropyCoder.h | 1 - .../Detectors/Common/test/testCTFEntropyCoder.cxx | 4 ++-- Utilities/rANS/benchmarks/bench_ransHistogram.cxx | 4 ++-- .../rANS/internal/containers/DenseHistogram.h | 4 +--- .../internal/containers/ReverseSymbolLookupTable.h | 4 ++-- .../rANS/include/rANS/internal/containers/Symbol.h | 7 ++----- .../rANS/include/rANS/internal/encode/Encoder.h | 4 ++++ .../rANS/internal/encode/EncoderSymbolMapper.h | 4 ---- .../rANS/internal/encode/SingleStreamEncoderImpl.h | 2 -- .../rANS/internal/pack/DictionaryStreamReader.h | 2 +- .../include/rANS/internal/transform/algorithmImpl.h | 2 +- .../rANS/include/rANS/internal/transform/renorm.h | 1 - Utilities/rANS/run/bin-encode-decode.cxx | 2 +- Utilities/rANS/test/test_ransHistograms.cxx | 3 --- Utilities/rANS/test/test_ransMetrics.cxx | 1 - Utilities/rANS/test/test_ransPack.cxx | 3 +-- Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx | 12 +++++++----- Utilities/rANS/test/test_ransSparseVector.cxx | 2 -- Utilities/rANS/test/test_ransSymbolTables.cxx | 2 +- 21 files changed, 27 insertions(+), 43 deletions(-) diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index 6afc171a79d7c..3deae46f00913 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -835,7 +835,7 @@ auto EncodedBlocks::getImage(const void* newHead) // we don't modify newHead, but still need to remove constness for relocation interface relocate(image.mRegistry.head, const_cast(reinterpret_cast(newHead)), reinterpret_cast(&image)); - return std::move(image); + return image; } ///_____________________________________________________________________________ @@ -945,7 +945,6 @@ CTFIOSize EncodedBlocks::decodeCompatImpl(dst_IT dstBegin, int slot, co { // get references to the right data - const auto& ansVersion = getANSHeader(); const auto& block = mBlocks[slot]; const auto& md = mMetadata[slot]; @@ -984,7 +983,6 @@ CTFIOSize EncodedBlocks::decodeRansV1Impl(dst_IT dstBegin, int slot, co { // get references to the right data - const auto& ansVersion = getANSHeader(); const auto& block = mBlocks[slot]; const auto& md = mMetadata[slot]; diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h index 6a8be509c021c..5335514278e26 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h @@ -79,7 +79,7 @@ template constexpr size_t Overhead = 10 * rans::utils::pow2(10); // 10KB overhead safety margin const double_t RelativeSafetyFactor = 2.0 * safetyFactor; const size_t messageSizeB = nElements * sizeof(source_type); - return rans::utils::nBytesTo(std::ceil(safetyFactor * messageSizeB) + Overhead); + return rans::utils::nBytesTo(std::ceil(RelativeSafetyFactor * messageSizeB) + Overhead); } template diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h index 54302d51d2666..8601469b34142 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h @@ -166,7 +166,6 @@ void InplaceEntropyCoder::makeEncoder() } const size_t rangeBits = rans::utils::getRangeBits(*mMetrics.getCoderProperties().min, *mMetrics.getCoderProperties().max); - const size_t nSamples = mMetrics.getDatasetProperties().numSamples; const size_t nUsedAlphabetSymbols = mMetrics.getDatasetProperties().nUsedAlphabetSymbols; if (rangeBits <= 18) { diff --git a/DataFormats/Detectors/Common/test/testCTFEntropyCoder.cxx b/DataFormats/Detectors/Common/test/testCTFEntropyCoder.cxx index 3471a6c9e4dff..6b688fcebc7f7 100644 --- a/DataFormats/Detectors/Common/test/testCTFEntropyCoder.cxx +++ b/DataFormats/Detectors/Common/test/testCTFEntropyCoder.cxx @@ -126,7 +126,7 @@ void encodeInplace(source_IT begin, source_IT end) std::vector dictBuffer(sizeEstimate.getCompressedDictionarySize(), 0); auto encoderEnd = entropyCoder.encode(begin, end, encodeBuffer.data(), encodeBuffer.data() + encodeBuffer.size()); - auto literalsEnd = entropyCoder.writeIncompressible(literalSymbolsBuffer.data(), literalSymbolsBuffer.data() + literalSymbolsBuffer.size()); + [[maybe_unused]] auto literalsEnd = entropyCoder.writeIncompressible(literalSymbolsBuffer.data(), literalSymbolsBuffer.data() + literalSymbolsBuffer.size()); auto dictEnd = entropyCoder.writeDictionary(dictBuffer.data(), dictBuffer.data() + dictBuffer.size()); // decode const auto& coderProperties = metrics.getCoderProperties(); @@ -303,7 +303,7 @@ void encodeExternal(source_IT begin, source_IT end) auto encoderEnd = entropyCoder.encode(begin, end, encodeBuffer.data(), encodeBuffer.data() + encodeBuffer.size()); std::vector literalSymbolsBuffer(entropyCoder.template computePackedIncompressibleSize(), 0); - auto literalsEnd = entropyCoder.writeIncompressible(literalSymbolsBuffer.data(), literalSymbolsBuffer.data() + literalSymbolsBuffer.size()); + [[maybe_unused]] auto literalsEnd = entropyCoder.writeIncompressible(literalSymbolsBuffer.data(), literalSymbolsBuffer.data() + literalSymbolsBuffer.size()); // decode auto decoder = ExternalEncoders.getDecoder(); diff --git a/Utilities/rANS/benchmarks/bench_ransHistogram.cxx b/Utilities/rANS/benchmarks/bench_ransHistogram.cxx index 9c32117ba914b..084d4b8fca1bc 100644 --- a/Utilities/rANS/benchmarks/bench_ransHistogram.cxx +++ b/Utilities/rANS/benchmarks/bench_ransHistogram.cxx @@ -137,7 +137,7 @@ void ransMakeHistogramBenchmark(benchmark::State& st, Args&&... args) histogram_type hist{}; hist.addSamples(gsl::span(inputData)); - for (std::ptrdiff_t symbol = histogram.getOffset(); symbol != histogram.getOffset() + histogram.size(); ++symbol) { + for (std::ptrdiff_t symbol = histogram.getOffset(); symbol != histogram.getOffset() + static_cast(histogram.size()); ++symbol) { if (histogram[symbol] > 0) { LOG_IF(info, histogram[symbol] != hist[symbol]) << fmt::format("[{}]: {} != {}", symbol, hist[symbol], histogram[symbol]); isSame = isSame && (histogram[symbol] == hist[symbol]); @@ -190,7 +190,7 @@ void ransAccessHistogramBenchmark(benchmark::State& st, Args&&... args) #endif bool isSame = true; - for (std::ptrdiff_t symbol = histogram.getOffset(); symbol != histogram.getOffset() + histogram.size(); ++symbol) { + for (std::ptrdiff_t symbol = histogram.getOffset(); symbol != histogram.getOffset() + static_cast(histogram.size()); ++symbol) { if (histogram[symbol] > 0) { LOG_IF(info, histogram[symbol] != hist[symbol]) << fmt::format("[{}]: {} != {}", symbol, hist[symbol], histogram[symbol]); isSame = isSame && (histogram[symbol] == hist[symbol]); diff --git a/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h b/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h index 844e0c9695a32..177245ef7bec6 100644 --- a/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h +++ b/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h @@ -184,7 +184,7 @@ inline bool DenseHistogram>::i ret = false; } } - if (max - min > this->MaxSize) { + if (max - min > static_cast(this->MaxSize)) { LOGP(warning, "DenseHistogram exceeds {} elements threshold", this->MaxSize); ret = false; } @@ -233,8 +233,6 @@ inline auto DenseHistogram>::a constexpr size_t nUnroll = 4 * ElemsPerQWord; auto iter = begin; - const source_type offset = this->getOffset(); - if (getRangeBits(min, max) <= 17) { container_type histogram{this->mContainer.size(), this->mContainer.getOffset()}; diff --git a/Utilities/rANS/include/rANS/internal/containers/ReverseSymbolLookupTable.h b/Utilities/rANS/include/rANS/internal/containers/ReverseSymbolLookupTable.h index 506aaaf53fa40..3a79619b2338d 100644 --- a/Utilities/rANS/include/rANS/internal/containers/ReverseSymbolLookupTable.h +++ b/Utilities/rANS/include/rANS/internal/containers/ReverseSymbolLookupTable.h @@ -71,8 +71,8 @@ class ReverseSymbolLookupTable return mLut[cumul]; }; - inline const iterator_type begin() const noexcept { return mLut.data(); }; - inline const iterator_type end() const noexcept { return mLut.data() + size(); }; + inline iterator_type begin() const noexcept { return mLut.data(); }; + inline iterator_type end() const noexcept { return mLut.data() + size(); }; container_type mLut{}; }; diff --git a/Utilities/rANS/include/rANS/internal/containers/Symbol.h b/Utilities/rANS/include/rANS/internal/containers/Symbol.h index 0c00c46e1a627..5269447e22344 100644 --- a/Utilities/rANS/include/rANS/internal/containers/Symbol.h +++ b/Utilities/rANS/include/rANS/internal/containers/Symbol.h @@ -37,11 +37,8 @@ class Symbol // TODO(milettri): fix once ROOT cling respects the standard http://wg21.link/p1286r2 constexpr Symbol() noexcept {}; // NOLINT - constexpr Symbol(value_type frequency, value_type cumulative, size_t symbolTablePrecision = 0) - : mSymbol{frequency, cumulative} - { - (void)symbolTablePrecision; // silence compiler warnings - }; + constexpr Symbol(value_type frequency, value_type cumulative, [[maybe_unused]] size_t symbolTablePrecision = 0) + : mSymbol{frequency, cumulative} {}; [[nodiscard]] inline constexpr value_type getFrequency() const noexcept { return mSymbol[0]; }; [[nodiscard]] inline constexpr value_type getCumulative() const noexcept { return mSymbol[1]; }; [[nodiscard]] inline constexpr const value_type* data() const noexcept { return mSymbol.data(); }; diff --git a/Utilities/rANS/include/rANS/internal/encode/Encoder.h b/Utilities/rANS/include/rANS/internal/encode/Encoder.h index ef097992ac9cd..fb6015b7aa021 100644 --- a/Utilities/rANS/include/rANS/internal/encode/Encoder.h +++ b/Utilities/rANS/include/rANS/internal/encode/Encoder.h @@ -143,7 +143,11 @@ decltype(auto) Encoder::process(source_IT EncoderSymbolMapper symbolMapper{this->mSymbolTable, literalsBegin}; typename coder_type::symbol_type encoderSymbols[2]{}; + // one past the end. Will not be dereferenced, thus safe. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" coder_type* codersREnd = advanceIter(coders.data(), -1); +#pragma GCC diagnostic pop coder_type* activeCoder = codersREnd + nPartialCoderIterations; // we are encoding backwards! diff --git a/Utilities/rANS/include/rANS/internal/encode/EncoderSymbolMapper.h b/Utilities/rANS/include/rANS/internal/encode/EncoderSymbolMapper.h index 083dad90f81c6..8925dfb6b34cf 100644 --- a/Utilities/rANS/include/rANS/internal/encode/EncoderSymbolMapper.h +++ b/Utilities/rANS/include/rANS/internal/encode/EncoderSymbolMapper.h @@ -254,8 +254,6 @@ class EncoderSymbolMapper frequencies; @@ -330,8 +328,6 @@ class EncoderSymbolMapper frequencies; diff --git a/Utilities/rANS/include/rANS/internal/encode/SingleStreamEncoderImpl.h b/Utilities/rANS/include/rANS/internal/encode/SingleStreamEncoderImpl.h index 580df53fc64bd..ff7d6535365e0 100644 --- a/Utilities/rANS/include/rANS/internal/encode/SingleStreamEncoderImpl.h +++ b/Utilities/rANS/include/rANS/internal/encode/SingleStreamEncoderImpl.h @@ -145,8 +145,6 @@ class SingleStreamEncoderImpl : public SingleStreamEncoderImplBasegetFrequency() != 0); - const state_type old = this->mState; - const auto [newState, streamPosition] = this->renorm(this->mState, outputIter, symbol->getFrequency()); // coding function state_type quotient = static_cast((static_cast(newState) * symbol->getReciprocalFrequency()) >> 64); diff --git a/Utilities/rANS/include/rANS/internal/pack/DictionaryStreamReader.h b/Utilities/rANS/include/rANS/internal/pack/DictionaryStreamReader.h index f84eaebf25fb9..0109abe102fc3 100644 --- a/Utilities/rANS/include/rANS/internal/pack/DictionaryStreamReader.h +++ b/Utilities/rANS/include/rANS/internal/pack/DictionaryStreamReader.h @@ -84,7 +84,7 @@ class DictionaryStreamParser template template -DictionaryStreamParser::DictionaryStreamParser(buffer_IT begin, buffer_IT end, source_type max) : mEnd{begin}, mPos{end}, mIndex(max) +DictionaryStreamParser::DictionaryStreamParser(buffer_IT begin, buffer_IT end, source_type max) : mPos{end}, mEnd{begin}, mIndex(max) { static_assert(std::is_pointer_v, "can only deserialize from raw pointers"); diff --git a/Utilities/rANS/include/rANS/internal/transform/algorithmImpl.h b/Utilities/rANS/include/rANS/internal/transform/algorithmImpl.h index 84dff9609a574..382f116d5ca04 100644 --- a/Utilities/rANS/include/rANS/internal/transform/algorithmImpl.h +++ b/Utilities/rANS/include/rANS/internal/transform/algorithmImpl.h @@ -161,7 +161,7 @@ inline void forEachIndexValue(container_T&& container, IT begin, IT end, F funct using container_type = removeCVRef_t; typename container_type::source_type index = container.getOffset() + std::distance(container.begin(), begin); - for (size_t i = 0; i < std::distance(begin, end); ++i) { + for (std::ptrdiff_t i = 0; i < std::distance(begin, end); ++i) { functor(index++, begin[i]); } } diff --git a/Utilities/rANS/include/rANS/internal/transform/renorm.h b/Utilities/rANS/include/rANS/internal/transform/renorm.h index 5d55b3553ceca..8d8ab238aaa91 100644 --- a/Utilities/rANS/include/rANS/internal/transform/renorm.h +++ b/Utilities/rANS/include/rANS/internal/transform/renorm.h @@ -74,7 +74,6 @@ decltype(auto) renorm(histogram_T histogram, Metrics(5), 5}, }; - const size_t fixedSizeOffset = std::numeric_limits::min(); - histogram_T histogram{}; histogram.addFrequencies(frequencies.begin(), frequencies.end(), 0); @@ -389,7 +387,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_addFrequenciesSignChange, histogram_T, histog const std::ptrdiff_t offset = utils::pow2(utils::toBits() - 1); if constexpr (std::is_same_v>) { - const std::ptrdiff_t largeOffset = utils::toBits() - 1; BOOST_CHECK_THROW(histogram.addFrequencies(frequencies2.begin(), frequencies2.end(), offset), HistogramError); BOOST_CHECK_THROW(histogram2.addFrequencies(gsl::make_span(frequencies2), offset), HistogramError); } else { diff --git a/Utilities/rANS/test/test_ransMetrics.cxx b/Utilities/rANS/test/test_ransMetrics.cxx index 42dcf7519f664..4370194306f1d 100644 --- a/Utilities/rANS/test/test_ransMetrics.cxx +++ b/Utilities/rANS/test/test_ransMetrics.cxx @@ -238,7 +238,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_singleElementMetrics, histogram_T, histogram_ std::vector frequencies{5}; histogram_T histogram{frequencies.begin(), frequencies.end(), 2}; const auto [min, max] = getMinMax(histogram); - const float eps = 1e-2; const size_t nUsedAlphabetSymbols = countNUsedAlphabetSymbols(histogram); const Metrics metrics{histogram}; diff --git a/Utilities/rANS/test/test_ransPack.cxx b/Utilities/rANS/test/test_ransPack.cxx index bc63ad04cdf96..e6aaaffa79ebf 100644 --- a/Utilities/rANS/test/test_ransPack.cxx +++ b/Utilities/rANS/test/test_ransPack.cxx @@ -56,7 +56,6 @@ using source_types = boost::mp11::mp_list BOOST_AUTO_TEST_CASE_TEMPLATE(test_computePackingBufferSize, buffer_T, buffer_types) { - size_t nElems{}; size_t packingWidth = utils::toBits() - 3; BOOST_CHECK_EQUAL(0, (computePackingBufferSize(0, packingWidth))); @@ -132,7 +131,7 @@ BOOST_AUTO_TEST_CASE(test_packUnpackStream) source_type min = *std::min_element(source.begin(), source.end()); - auto packingBufferEnd = pack(source.data(), source.size(), packingBuffer.data(), packingWidth, min); + [[maybe_unused]] auto packingBufferEnd = pack(source.data(), source.size(), packingBuffer.data(), packingWidth, min); std::vector unpackBuffer(source.size(), 0); unpack(packingBuffer.data(), source.size(), unpackBuffer.data(), packingWidth, min); diff --git a/Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx b/Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx index 12f65a6c610b6..ea099fd2238f7 100644 --- a/Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx +++ b/Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx @@ -120,7 +120,9 @@ struct AosToSoaFixture { uint32_t counter = 0; for (size_t i = 0; i < nElems; ++i) { - Symbol symbol{counter++, counter++, 0}; + const auto freq = counter++; + const auto cumul = counter++; + Symbol symbol{freq, cumul, 0}; mFrequencies(i) = symbol.getFrequency(); mCumulative(i) = symbol.getCumulative(); @@ -228,10 +230,10 @@ struct SSERenormFixture { statesVec[0] = load(states[0]); statesVec[1] = load(states[1]); - stream_iterator newstreamOutIter = ransRenorm(statesVec, - frequenciesVec, - SymbolTablePrecisionBits, - streamOutBuffer.begin(), newStatesVec); + [[maybe_unused]] stream_iterator newstreamOutIter = ransRenorm(statesVec, + frequenciesVec, + SymbolTablePrecisionBits, + streamOutBuffer.begin(), newStatesVec); epi64_t newStates(0); store(newStatesVec[0], newStates[0]); diff --git a/Utilities/rANS/test/test_ransSparseVector.cxx b/Utilities/rANS/test/test_ransSparseVector.cxx index fab69aa5750ad..fc1a2980e3226 100644 --- a/Utilities/rANS/test/test_ransSparseVector.cxx +++ b/Utilities/rANS/test/test_ransSparseVector.cxx @@ -47,8 +47,6 @@ BOOST_AUTO_TEST_CASE(test_write) { sparseVector_type vec{}; - const size_t fixedSizeOffset = std::numeric_limits::min(); - std::vector samples{-5, -2, 1, 3, 5, 8, -5, 5, 1, 1, 1, 14, 8, 8, 8, 8, 8, 8, 8, 8, utils::pow2(18) + 1}; std::unordered_map results{{-5, 2}, {-2, 1}, {-1, 0}, {0, 0}, {1, 4}, {2, 0}, {3, 1}, {4, 0}, {5, 2}, {8, 9}, {14, 1}, {utils::pow2(18) + 1, 1}}; diff --git a/Utilities/rANS/test/test_ransSymbolTables.cxx b/Utilities/rANS/test/test_ransSymbolTables.cxx index 5384607b2b0c4..bbadb8c8c46a0 100644 --- a/Utilities/rANS/test/test_ransSymbolTables.cxx +++ b/Utilities/rANS/test/test_ransSymbolTables.cxx @@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_symbolTable, histogram_T, histogram_t) BOOST_CHECK_EQUAL(symbolTable.getPrecision(), scaleBits); - for (source_type index = 0; index < rescaledFrequencies.size(); ++index) { + for (source_type index = 0; index < static_cast(rescaledFrequencies.size()); ++index) { auto symbol = symbolTable[index + 6]; BOOST_CHECK_EQUAL(symbol.getFrequency(), rescaledFrequencies[index]); BOOST_CHECK_EQUAL(symbol.getCumulative(), cumulativeFrequencies[index]); From c83bd66be97ad7b3c2b50cec5a66a3c71989f91b Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 4 Oct 2023 10:50:42 +0200 Subject: [PATCH 202/324] MID: Downscale InfoLogger errors temporarily --- Detectors/MUON/MID/Raw/src/ELinkManager.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Detectors/MUON/MID/Raw/src/ELinkManager.cxx b/Detectors/MUON/MID/Raw/src/ELinkManager.cxx index 1b9067addcf9b..d998db8856d7c 100644 --- a/Detectors/MUON/MID/Raw/src/ELinkManager.cxx +++ b/Detectors/MUON/MID/Raw/src/ELinkManager.cxx @@ -78,7 +78,8 @@ void ELinkManager::onDone(const ELinkDecoder& decoder, uint8_t crateId, uint8_t // To avoid flooding the logs, we warn only the first time we see it. auto& err = mErrors[uniqueId]; ++err; - if (err == 1) { + static unsigned int nTotalErr = 0; + if (err == 1 && nTotalErr++ < 3) { // This is the first time we see this faulty board, so we report it. ROBoard board{decoder.getStatusWord(), decoder.getTriggerWord(), raw::makeUniqueLocID(crateId, locId), decoder.getInputs()}; for (int ich = 0; ich < 4; ++ich) { From cbb534bc9dcfa227b1409303ebfeaa1ae3044cfb Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 4 Oct 2023 13:50:53 +0200 Subject: [PATCH 203/324] DPL: Fix typo, should be != (#12017) --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 94aadf7f76950..cfc464a87016e 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -281,11 +281,12 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve firstDH = dh; } for (size_t pi = 0; pi < present.size(); ++pi) { + if (present[pi]) { + continue; + } // Consider uninvolved pipelines as present. - if (routes[pi].timeslice == (dph->startTime % routes[pi].maxTimeslices)) { + if (routes[pi].timeslice != (dph->startTime % routes[pi].maxTimeslices)) { present[pi] = true; - } - if (present[pi]) { continue; } allFound = false; From 77d2c79e90ae2b1f540fedc52706157854f92621 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:15:29 +0200 Subject: [PATCH 204/324] DPL: improve message for missing data --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index cfc464a87016e..4de5c7aa28aa9 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -247,14 +247,19 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve bool hassih = false; // Do not check anything which has DISTSUBTIMEFRAME in it. + size_t expectedDataSpecs = 0; for (size_t pi = 0; pi < present.size(); ++pi) { auto& spec = routes[pi].matcher; if (DataSpecUtils::asConcreteDataTypeMatcher(spec).description == header::DataDescription("DISTSUBTIMEFRAME")) { present[pi] = true; continue; } + if (routes[pi].timeslice == 0) { + ++expectedDataSpecs; + } } + size_t foundDataSpecs = 0; for (int msgidx = 0; msgidx < parts.Size(); msgidx += 2) { const auto dh = o2::header::get(parts.At(msgidx)->GetData()); auto const sih = o2::header::get(parts.At(msgidx)->GetData()); @@ -294,6 +299,7 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve OutputSpec query{dh->dataOrigin, dh->dataDescription, dh->subSpecification}; if (DataSpecUtils::match(spec, query)) { present[pi] = true; + ++foundDataSpecs; break; } } @@ -357,7 +363,7 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve static int maxWarn = 10; // Correct would be o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef, but Framework does not depend on CommonUtils..., but not so critical since receives will send correct number of DEADBEEF messages static int contDeadBeef = 0; if (++contDeadBeef <= maxWarn) { - LOGP(alarm, "Found {}/{} data specs, missing data specs: {}, injecting 0xDEADBEEF", present.size() - unmatchedDescriptions.size(), present.size(), missing); + LOGP(alarm, "Found {}/{} data specs, missing data specs: {}, injecting 0xDEADBEEF", foundDataSpecs, expectedDataSpecs, missing); } } } From 9e281930092168a56d9c8128254c38d89031755d Mon Sep 17 00:00:00 2001 From: jmyrcha Date: Wed, 4 Oct 2023 14:02:47 +0200 Subject: [PATCH 205/324] o2-eve: HMPID display, fix in display configuration file read (#11997) * o2-eve: HMPID display, fix in display configuration file read o2-eve-workflow: storing HMPID in *.root/*.json file * clang * LOG->LOGF * clang * geometry for HMP --------- Co-authored-by: Julian Myrcha --- .../ConfigurationManager.h | 2 +- .../Base/src/ConfigurationManager.cxx | 10 ++-- .../Base/src/DataSourceOnline.cxx | 2 +- .../Base/src/DirectoryLoader.cxx | 4 +- EventVisualisation/Base/src/FileWatcher.cxx | 14 ++--- .../Base/src/GeometryManager.cxx | 8 +-- .../VisualisationCalo.h | 5 +- .../VisualisationCluster.h | 11 +++- .../VisualisationConstants.h | 7 ++- .../VisualisationEvent.h | 5 ++ .../VisualisationEventJSONSerializer.h | 6 +- .../DataConverter/src/VisualisationEvent.cxx | 3 + .../src/VisualisationEventJSONSerializer.cxx | 6 +- .../src/VisualisationEventROOTSerializer.cxx | 2 +- .../DataConverter/src/converter.cxx | 12 ++-- .../Geometry/simple_geom_HMP.root | Bin 0 -> 2611 bytes .../Geometry/simple_geom_ITS.root | Bin EventVisualisation/View/src/EventManager.cxx | 23 +++---- .../View/src/EventManagerFrame.cxx | 7 +-- EventVisualisation/View/src/Initializer.cxx | 4 +- EventVisualisation/View/src/MultiView.cxx | 2 +- EventVisualisation/View/src/Options.cxx | 3 +- EventVisualisation/View/src/Screenshot.cxx | 1 - EventVisualisation/View/src/main.cxx | 12 ++-- .../include/EveWorkflow/EveWorkflowHelper.h | 2 + .../include/EveWorkflow/O2DPLDisplay.h | 4 +- .../Workflow/src/AO2DConverter.cxx | 2 +- .../Workflow/src/EveWorkflowHelper.cxx | 56 +++++++++++++++--- .../Workflow/src/O2DPLDisplay.cxx | 26 ++++---- 29 files changed, 147 insertions(+), 92 deletions(-) create mode 100644 EventVisualisation/Geometry/simple_geom_HMP.root mode change 100755 => 100644 EventVisualisation/Geometry/simple_geom_ITS.root diff --git a/EventVisualisation/Base/include/EventVisualisationBase/ConfigurationManager.h b/EventVisualisation/Base/include/EventVisualisationBase/ConfigurationManager.h index 74783252dff2a..f9abc00774298 100644 --- a/EventVisualisation/Base/include/EventVisualisationBase/ConfigurationManager.h +++ b/EventVisualisation/Base/include/EventVisualisationBase/ConfigurationManager.h @@ -25,7 +25,7 @@ namespace o2 namespace event_visualisation { /// Version of the software -const static std::string o2_eve_version = "1.60"; +const static std::string o2_eve_version = "1.70"; /// Configuration Manager allows an easy access to the config file. /// diff --git a/EventVisualisation/Base/src/ConfigurationManager.cxx b/EventVisualisation/Base/src/ConfigurationManager.cxx index c6e2f5400f4ab..6205f3c2ab67e 100644 --- a/EventVisualisation/Base/src/ConfigurationManager.cxx +++ b/EventVisualisation/Base/src/ConfigurationManager.cxx @@ -38,21 +38,21 @@ void ConfigurationManager::getConfig(TEnv& settings) const return; // precise located options file name read succesfully } if (settings.ReadFile(fileName = ".o2eve_config", kEnvUser) < 0) { - LOG(warn) << "could not find .o2eve_config in working directory! Trying .o2eve_config in home directory"; + LOGF(warn, "could not find .o2eve_config in working directory! Trying .o2eve_config in home directory"); if (settings.ReadFile(fileName = Form("%s/.o2eve_config", gSystem->Getenv("HOME")), kEnvUser) < 0) { - LOG(warn) << "could not find .o2eve_config in home directory! Trying o2eve_config in home directory"; + LOGF(warn, "could not find .o2eve_config in home directory! Trying o2eve_config in home directory"); if (settings.ReadFile(fileName = Form("%s/o2eve_config", gSystem->Getenv("HOME")), kEnvUser) < 0) { - LOG(warn) << "could not find o2eve_config in home directory! Trying o2eve_config in O2/EventVisualisation"; + LOGF(warn, "could not find o2eve_config in home directory! Trying o2eve_config in O2/EventVisualisation"); if (settings.ReadFile(fileName = Form("%s/EventVisualisation/o2eve_config", gSystem->Getenv("ALICEO2_INSTALL_PATH")), kEnvUser) < 0) { - LOG(fatal) << "could not find .o2eve_config or o2eve_config file!."; + LOGF(fatal, "could not find .o2eve_config or o2eve_config file!."); exit(0); } } } } - LOG(info) << Form("using %s config settings", fileName.Data()); + LOGF(info, Form("using %s config settings", fileName.Data())); } const ConfigurationManager* ConfigurationManager::loadSettings() diff --git a/EventVisualisation/Base/src/DataSourceOnline.cxx b/EventVisualisation/Base/src/DataSourceOnline.cxx index 35d6b8c8b7f0e..d6ed7c9adcb72 100644 --- a/EventVisualisation/Base/src/DataSourceOnline.cxx +++ b/EventVisualisation/Base/src/DataSourceOnline.cxx @@ -83,7 +83,7 @@ std::vector> } auto stop = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(stop - start); - LOG(info) << "getVisualisationList: " << duration.count(); + LOGF(info, "getVisualisationList: ", duration.count()); return res; } diff --git a/EventVisualisation/Base/src/DirectoryLoader.cxx b/EventVisualisation/Base/src/DirectoryLoader.cxx index fd4186bf6bde7..6bfe6f50d4b0a 100644 --- a/EventVisualisation/Base/src/DirectoryLoader.cxx +++ b/EventVisualisation/Base/src/DirectoryLoader.cxx @@ -104,10 +104,10 @@ std::string DirectoryLoader::getLatestFile(std::string& path, std::vector& ext, int remaining) +void DirectoryLoader::removeOldestFiles(std::string& path, std::vector& ext, const int remaining) { while (getNumberOfFiles(path, ext) > remaining) { - LOG(info) << "removing oldest file in folder: " << path << " : " << getLatestFile(path, ext); + LOGF(info, "removing oldest file in folder: ", path, " : ", getLatestFile(path, ext)); filesystem::remove(path + "/" + getLatestFile(path, ext)); } } diff --git a/EventVisualisation/Base/src/FileWatcher.cxx b/EventVisualisation/Base/src/FileWatcher.cxx index 7cc04d79d4130..99b27c706a793 100644 --- a/EventVisualisation/Base/src/FileWatcher.cxx +++ b/EventVisualisation/Base/src/FileWatcher.cxx @@ -143,8 +143,8 @@ int FileWatcher::getPos() const bool FileWatcher::refresh() { string previous = this->currentItem(); - LOG(info) << "previous:" << previous; - LOG(info) << "currentFile:" << this->mCurrentFile; + LOGF(info, "previous:", previous); + LOGF(info, "currentFile:", this->mCurrentFile); this->mFiles = DirectoryLoader::load(this->mDataFolders, "_", this->mExt); // already sorted according part staring with marker if (this->mCurrentFile != mEndGuard) { @@ -165,17 +165,17 @@ bool FileWatcher::refresh() this->mFiles.push_front(mLowGuard); this->mFiles.push_back(mEndGuard); - LOG(info) << "this->mFiles.size() = " << this->mFiles.size(); - LOG(info) << "this->mCurrentFile = " << this->mCurrentFile; - LOG(info) << "current:" << this->currentItem(); + LOGF(info, "this->mFiles.size() = ", this->mFiles.size()); + LOGF(info, "this->mCurrentFile = ", this->mCurrentFile); + LOGF(info, "current:", this->currentItem()); return previous != this->currentItem(); } void FileWatcher::setCurrentItem(int no) { this->mCurrentFile = this->mFiles[no]; - LOG(info) << "this->setCurrentItem(" << no << ")"; - LOG(info) << "this->mCurrentFile = " << this->mCurrentFile; + LOGF(info, "this->setCurrentItem(", no, ")"); + LOGF(info, "this->mCurrentFile = ", this->mCurrentFile); } std::string FileWatcher::currentFilePath() const diff --git a/EventVisualisation/Base/src/GeometryManager.cxx b/EventVisualisation/Base/src/GeometryManager.cxx index d41733c017de0..59f91ce097974 100644 --- a/EventVisualisation/Base/src/GeometryManager.cxx +++ b/EventVisualisation/Base/src/GeometryManager.cxx @@ -47,13 +47,13 @@ TEveGeoShape* GeometryManager::getGeometryForDetector(string detectorName) // load ROOT file with geometry TFile* f = TFile::Open(Form("%s/simple_geom_%s.root", geomPath.c_str(), detectorName.c_str())); if (!f) { - LOG(error) << "GeometryManager::GetSimpleGeom -- no file with geometry found for: " << detectorName << "!"; + LOGF(error, "GeometryManager::GetSimpleGeom -- no file with geometry found for: ", detectorName, "!"); return nullptr; } - LOG(info) << "GeometryManager::GetSimpleGeom for: " << detectorName << " from " - << Form("%s/simple_geom_%s.root", geomPath.c_str(), detectorName.c_str()); + LOGF(info, "GeometryManager::GetSimpleGeom for: ", detectorName, " from ", + Form("%s/simple_geom_%s.root", geomPath.c_str(), detectorName.c_str())); - TEveGeoShapeExtract* geomShapreExtract = static_cast(f->Get(detectorName.c_str())); + auto geomShapreExtract = dynamic_cast(f->Get(detectorName.c_str())); TEveGeoShape* geomShape = TEveGeoShape::ImportShapeExtract(geomShapreExtract); f->Close(); diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationCalo.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationCalo.h index 1d79897e57942..e7c00064a909b 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationCalo.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationCalo.h @@ -46,8 +46,9 @@ class VisualisationCalo std::string gid = ""; o2::dataformats::GlobalTrackID::Source source; }; + // Constructor with properties initialisation - VisualisationCalo(const VisualisationCaloVO& vo); + explicit VisualisationCalo(const VisualisationCaloVO& vo); VisualisationCalo(const VisualisationCalo& src); @@ -103,8 +104,6 @@ class VisualisationCalo int mPID; /// PDG code of the particle std::string mGID; /// String representation of gid - float mStartCoordinates[3]; /// Vector of track's start coordinates - float mEta; /// An angle from Z-axis to the radius vector pointing to the particle float mPhi; /// An angle from X-axis to the radius vector pointing to the particle diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationCluster.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationCluster.h index f70dc8cefd0b1..da07dcf39ce68 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationCluster.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationCluster.h @@ -19,6 +19,7 @@ #include "ReconstructionDataFormats/GlobalTrackID.h" #include "rapidjson/document.h" +#include #include #include @@ -42,6 +43,14 @@ class VisualisationCluster public: // Default constructor VisualisationCluster(float XYZ[], float time); + VisualisationCluster(TVector3 xyz) + { + mTime = 0; + mCoordinates[0] = xyz[0]; + mCoordinates[1] = xyz[1]; + mCoordinates[2] = xyz[2]; + mSource = o2::dataformats::GlobalTrackID::HMP; + } float X() const { return mCoordinates[0]; } float Y() const { return mCoordinates[1]; } @@ -59,4 +68,4 @@ class VisualisationCluster }; } // namespace event_visualisation } // namespace o2 -#endif // ALICE_O2_DATACONVERTER_VISUALISATIONCLUSTER_H \ No newline at end of file +#endif // ALICE_O2_DATACONVERTER_VISUALISATIONCLUSTER_H diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationConstants.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationConstants.h index 3b9d0750b89d6..b118c19f00621 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationConstants.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationConstants.h @@ -36,6 +36,7 @@ enum EVisualisationGroup { EMC, PHS, CPV, + HMP, NvisualisationGroups }; @@ -49,7 +50,8 @@ const std::string gVisualisationGroupName[NvisualisationGroups] = { "MID", "EMC", "PHS", - "CPV"}; + "CPV", + "HMP"}; const bool R3Visualisation[NvisualisationGroups] = { true, //"ITS", @@ -61,7 +63,8 @@ const bool R3Visualisation[NvisualisationGroups] = { true, //"MID", true, //"EMC", true, //"PHS", - true, // "CPV" + true, //"CPV" + true, //"HMP" }; enum EVisualisationDataType { diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEvent.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEvent.h index 85e0c1a7a3c47..5e01e665a0f93 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEvent.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEvent.h @@ -89,6 +89,11 @@ class VisualisationEvent return mTracks.back().addCluster(pos); } + VisualisationCluster& addGlobalCluster(const TVector3& xyz) + { + return mClusters.emplace_back(xyz); + } + VisualisationCalo* addCalo(VisualisationCalo::VisualisationCaloVO vo) { mCalo.emplace_back(vo); diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventJSONSerializer.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventJSONSerializer.h index 6b26a0d615789..233d43651db67 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventJSONSerializer.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventJSONSerializer.h @@ -28,10 +28,12 @@ namespace event_visualisation class VisualisationEventJSONSerializer : public VisualisationEventSerializer { + public: static int getIntOrDefault(rapidjson::Value& tree, const char* key, int defaultValue = 0); - float getFloatOrDefault(rapidjson::Value& tree, const char* key, float defaultValue = 0.0f); - std::string getStringOrDefault(rapidjson::Value& tree, const char* key, const char* defaultValue = ""); + static float getFloatOrDefault(rapidjson::Value& tree, const char* key, float defaultValue = 0.0f); + static std::string getStringOrDefault(rapidjson::Value& tree, const char* key, const char* defaultValue = ""); + private: std::string toJson(const VisualisationEvent& event) const; void fromJson(VisualisationEvent& event, std::string json); diff --git a/EventVisualisation/DataConverter/src/VisualisationEvent.cxx b/EventVisualisation/DataConverter/src/VisualisationEvent.cxx index 188c087e715b5..24448ae5e88dd 100644 --- a/EventVisualisation/DataConverter/src/VisualisationEvent.cxx +++ b/EventVisualisation/DataConverter/src/VisualisationEvent.cxx @@ -86,6 +86,9 @@ VisualisationEvent::GIDVisualisation VisualisationEvent::mVis = [] { if (filter == o2::event_visualisation::EVisualisationGroup::PHS) { res.contains[o2::dataformats::GlobalTrackID::PHS][filter] = true; } + if (filter == o2::event_visualisation::EVisualisationGroup::HMP) { + res.contains[o2::dataformats::GlobalTrackID::HMP][filter] = true; + } } return res; }(); diff --git a/EventVisualisation/DataConverter/src/VisualisationEventJSONSerializer.cxx b/EventVisualisation/DataConverter/src/VisualisationEventJSONSerializer.cxx index c3663bf141f7f..e9de16551303d 100644 --- a/EventVisualisation/DataConverter/src/VisualisationEventJSONSerializer.cxx +++ b/EventVisualisation/DataConverter/src/VisualisationEventJSONSerializer.cxx @@ -18,10 +18,8 @@ #include #include #include -#include #include "rapidjson/document.h" -#include "rapidjson/writer.h" #include "rapidjson/prettywriter.h" #include "rapidjson/stringbuffer.h" @@ -40,7 +38,7 @@ void VisualisationEventJSONSerializer::toFile(const VisualisationEvent& event, s bool VisualisationEventJSONSerializer::fromFile(VisualisationEvent& event, std::string fileName) { - LOG(info) << "VisualisationEventJSONSerializer <- " << fileName; + LOGF(info, "VisualisationEventJSONSerializer <- ", fileName); if (FILE* file = fopen(fileName.c_str(), "r")) { fclose(file); // file exists } else { @@ -195,7 +193,7 @@ VisualisationCluster VisualisationEventJSONSerializer::clusterFromJSON(rapidjson XYZ[2] = jsonZ.GetDouble(); VisualisationCluster cluster(XYZ, 0); - cluster.mSource = o2::dataformats::GlobalTrackID::TPC; // temporary + cluster.mSource = o2::dataformats::GlobalTrackID::HMP; return cluster; } diff --git a/EventVisualisation/DataConverter/src/VisualisationEventROOTSerializer.cxx b/EventVisualisation/DataConverter/src/VisualisationEventROOTSerializer.cxx index 38da87d8bed51..fd9e70aa02153 100644 --- a/EventVisualisation/DataConverter/src/VisualisationEventROOTSerializer.cxx +++ b/EventVisualisation/DataConverter/src/VisualisationEventROOTSerializer.cxx @@ -188,7 +188,7 @@ void VisualisationEventROOTSerializer::toFile(const VisualisationEvent& event, s bool VisualisationEventROOTSerializer::fromFile(VisualisationEvent& event, std::string fileName) { - LOG(info) << "VisualisationEventROOTSerializer <- " << fileName; + LOGF(info, "VisualisationEventROOTSerializer <- ", fileName); event.mTracks.clear(); event.mClusters.clear(); event.mCalo.clear(); diff --git a/EventVisualisation/DataConverter/src/converter.cxx b/EventVisualisation/DataConverter/src/converter.cxx index 3ba11be3c3b9c..f33638f686d5c 100644 --- a/EventVisualisation/DataConverter/src/converter.cxx +++ b/EventVisualisation/DataConverter/src/converter.cxx @@ -26,9 +26,9 @@ int main(int argc, char** argv) { - LOG(info) << "Welcome in O2 event conversion tool"; + LOGF(info, "Welcome in O2 event conversion tool"); if (argc != 3) { - LOG(error) << "two filename required, second should point to not existent file"; + LOGF(error, "two filename required, second should point to not existent file"); exit(-1); } @@ -45,13 +45,13 @@ int main(int argc, char** argv) srcSerializer->fromFile(vEvent, src); endTime = std::chrono::high_resolution_clock::now(); - LOG(info) << "read took " - << std::chrono::duration_cast(endTime - currentTime).count() * 1e-6; + LOGF(info, "read took ", + std::chrono::duration_cast(endTime - currentTime).count() * 1e-6); currentTime = std::chrono::high_resolution_clock::now(); dstSerializer->toFile(vEvent, dst); endTime = std::chrono::high_resolution_clock::now(); - LOG(info) << "write took " - << std::chrono::duration_cast(endTime - currentTime).count() * 1e-6; + LOGF(info, "write took ", + std::chrono::duration_cast(endTime - currentTime).count() * 1e-6); return 0; } diff --git a/EventVisualisation/Geometry/simple_geom_HMP.root b/EventVisualisation/Geometry/simple_geom_HMP.root new file mode 100644 index 0000000000000000000000000000000000000000..af37d833a4aa849561af29c6c203148c23bbe5e4 GIT binary patch literal 2611 zcmb7GX*kqfAO2ehWtl;EZDpq{Ph%^_42=kreHlxZF)|rO7zPR1hEVpUC^SMQOGQ2P z5H)0}EZGtn+rt>LRU~%b8Y0Nh*v8~!_Fs;>q-S0FZXJtMB=3+wfNT4Z1!$j%|ZITg@7 zKxVN40GGpA93CqYiVFxECeNq4Vmes<-IKTmbKo*1*s}8VO%9H<_ zK=!VjW2~k5jUqLMDg-W z7Dowj88?AM@A1fez>pu`RdH;)B^Co6qh5B(sGd*i?djF?4F4PrwfZHsU09WI_)45o zIb!hF8MAX&@&`Zqe=za}JH|fvjC?2==Z?8lw9SnaD3!428N;~FThQY^(J!7XzhtSO zGg@FSBS|i?OiUT9c5&Agf8N!Jyj3H06fUJ--%MCiqm|ik22MiX1ij+4; ze(O}1RIfj@gZ8H;rEY2KYM@hGp6<1`my_1#zzNG^lR61SP~ras+2A%&KH53AQj!2qmDr!Bx=Lf#h zfSGJhub_|bdWn5~YCap_81qvPVn9s&cKm^0i7%YW$vmZk6=7SW8#mQn-8CeCUmm&U z0-NqjgPb2pCbhBFpYAexpxu#Ri5b4G8+NLaJ8Z*y; zE0<)G3GaI<60rbD$|>KnR^{9MJwSCG@-R9^b>)L%vGbQCKCKZc!fv;hb=sGX>_(0G z4Z)qZ)1QcR=EgmJ?YySG*JAJBn$9|U8Z?jJk-z1j3p*-kJ(GqBu!x5I*Uw0{Ut2x& zE|q=G@llINYj{`0pOTQhr%3zaqhNpj;9s#!DfpKu5&Ndx|80OTmxC29H0-c_SP0fT z5F2tX$d3R)5{N$d$fI~%Pyp7KwS|VU9QuL_$QEQd^sTcS;S*BCXzA_zaPmNMu9Nz* zjbjznm2{WA%<0XT0+pSjivFJc_$Dc$6Ah{>8NHAl0-hIim}3)yyjWF6m>v~Df~Vu1 zCrMLcM;%HLt8dp7zn!gyhziNSO@|qUwwxL{HH;fkudzw()7H7mzu@rWr>1trkskwi z%h-V@hV6{|3`rP!$fQljXn;GXY0lMO%%n%7ZtO#DFCuDM^cg$zs3(N1?k)kEEVY)q zq{=?7x;Wn9L8wCqsVGXzC@UUpdxz~|BY1_IG9ff*Z=bwM;*x!^kQBc2a^(K{A=ps= zN6sU`XZa4jyg3*yCbG#tpmo7}p(1i2jWYX5x`Ow)>O@}?eo?qz<%iKG%I%Jw0uWZd zO}4nGLX<_71$rUK17qZc)ANJ)hgs>c-n>gUA#*Cx{P91} z^yUQ}#{o_jk<=vnGfq7q)P# zX|g9LNMDSBJOsw6_lDl{zU}=Q6ZtyL@yRQ%dqFAe$(M`ec;40vlSSVXApIJfRD|(V zDO}#k>pjeAYDU7M$bYnu7VvZz3`CJ^nTO3wP$1UnoG~16b zB|wP-A7#Q6yDO>9j7WhcyiS{|97@^MxAxC<7X#7ZMEP-ZR2!YMuD`LQQqzNu7K~d~ z8vULc?saE_p0jhdtr7a*R!E>H=~+)W1rt#tK3R^HaiwXP83|$+^D{Qku=O{Hm;*Z(s^#kZ6ZC^dEGPV z8Z!ytuN8!k+!@;axBF73@G*}H^@vSu$DjNvZTP@Exdu{%f18x88+qylqVoz}(mZ>c z?a6QN;-aAvS!_E))isWUJVtAbC)<0-f?%8s&RTNid~_P(ShI0`GCJELdIU{WhBhT0 zk{1r=L|dmNW4JFfFmOIZW0~~!Vnp8XqkN@Ps7@G|_MPTvN6>_N9qY`ct_7SKLH2~z z+GmD|wI8AVcvgp6$Kj6)LC-+tvd-|%BLL{F^dj@rNCPUWvriKL8|iIj#^?X|(8 zezpor_+LW3qpmJU`b^uIujM^4?WZJ+e1(?=bGPZN|2kMnhX+YfUsa zhSLGAX4mBEtZF)$F{-^Oddp9rP|T;y+1R=}e@KfOwcr-SX7tvPS0HzLsXs06 zO@Eq(!f&l9l&7Q@yUT1yfry4_X&j^_^X6kH5fI~{^)St!c=&_lN7;8p&$nsXvt!Cv z(|v4PFt!4I^{Yi1E*9Ghdx=&C>BM*eDxB|;OmKV^uLUIU3w4 z+7TuxrW&bvH}L0n+-?X&OBY89sNaB<;L@ksolrx(LH9k(eoHP^`9n5odH%Lwu7#r; z*-jK8RzAAaF=n#V>gJX8Ya5(r;@EQObU(&c%0zx*_*hUZ$78?P{TLN^kdXBLk&swv r=3of?`-H@LXAO)0JJYb*5C>#@|3tPQ`dAa^KajDg_@EIwxxn86M~;4B literal 0 HcmV?d00001 diff --git a/EventVisualisation/Geometry/simple_geom_ITS.root b/EventVisualisation/Geometry/simple_geom_ITS.root old mode 100755 new mode 100644 diff --git a/EventVisualisation/View/src/EventManager.cxx b/EventVisualisation/View/src/EventManager.cxx index 3f57d603cc4d4..0c0756583aa83 100644 --- a/EventVisualisation/View/src/EventManager.cxx +++ b/EventVisualisation/View/src/EventManager.cxx @@ -22,6 +22,7 @@ #include "EventVisualisationView/MultiView.h" #include "EventVisualisationView/Options.h" #include "EventVisualisationDataConverter/VisualisationEvent.h" +#include "EventVisualisationDataConverter/VisualisationEventJSONSerializer.h" #include #include "EventVisualisationBase/ConfigurationManager.h" #include "DataFormatsParameters/ECSDataAdapters.h" @@ -59,7 +60,7 @@ EventManager& EventManager::getInstance() EventManager::EventManager() : TEveEventManager("Event", "") { - LOG(info) << "Initializing TEveManager"; + LOGF(info, "Initializing TEveManager"); ConfigurationManager::getInstance().getConfig(settings); @@ -141,7 +142,6 @@ void EventManager::displayCurrentEvent() multiView->redraw3D(); auto stop = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(stop - start); - LOG(info) << "+++ displayCurrentEvent: " << duration.count(); } void EventManager::GotoEvent(Int_t no) @@ -221,7 +221,7 @@ void EventManager::displayVisualisationEvent(VisualisationEvent& event, const st { double eta = 0.1; size_t trackCount = event.getTrackCount(); - LOG(info) << "displayVisualisationEvent: " << trackCount << " detector: " << detectorName; + // tracks auto* list = new TEveTrackList(detectorName.c_str()); list->IncDenyDestroy(); @@ -266,7 +266,6 @@ void EventManager::displayVisualisationEvent(VisualisationEvent& event, const st if (trackCount != 0) { dataTypeLists[EVisualisationDataType::Tracks]->AddElement(list); if (detectorName != "MCH" && detectorName != "MFT" && detectorName != "MID") { - // LOG(info) << "phi: " << trackCount << " detector: " << detectorName; dataTypeListsPhi[EVisualisationDataType::Tracks]->AddElement(list); } } @@ -283,15 +282,14 @@ void EventManager::displayVisualisationEvent(VisualisationEvent& event, const st if (clusterCount != 0) { dataTypeLists[EVisualisationDataType::Clusters]->AddElement(point_list); if (detectorName != "MCH" && detectorName != "MFT" && detectorName != "MID") { - // LOG(info) << "phi: " << clusterCount << " detector: " << detectorName; dataTypeListsPhi[EVisualisationDataType::Clusters]->AddElement(point_list); } } - LOG(info) << "tracks: " << trackCount << " detector: " << detectorName << ":" - << dataTypeLists[EVisualisationDataType::Tracks]->NumChildren(); - LOG(info) << "clusters: " << clusterCount << " detector: " << detectorName << ":" - << dataTypeLists[EVisualisationDataType::Clusters]->NumChildren(); + LOGF(info, "tracks: ", trackCount, " detector: ", detectorName, ":", + dataTypeLists[EVisualisationDataType::Tracks]->NumChildren()); + LOGF(info, "clusters: ", clusterCount, " detector: ", detectorName, ":", + dataTypeLists[EVisualisationDataType::Clusters]->NumChildren()); } void EventManager::displayCalorimeters(VisualisationEvent& event, const std::string& detectorName) @@ -428,7 +426,7 @@ void EventManager::saveVisualisationSettings() return arr; }; - + d.AddMember("version", rapidjson::Value().SetString(o2_eve_version.c_str(), o2_eve_version.length()), allocator); d.AddMember("trackVisibility", jsonArray(vizSettings.trackVisibility, allocator), allocator); d.AddMember("trackColor", jsonArray(vizSettings.trackColor, allocator), allocator); d.AddMember("trackStyle", jsonArray(vizSettings.trackStyle, allocator), allocator); @@ -479,6 +477,11 @@ void EventManager::restoreVisualisationSettings() Document d; d.Parse(json.c_str()); + if (VisualisationEventJSONSerializer::getStringOrDefault(d, "version", "0.0") != o2_eve_version) { + LOGF(info, "visualisation settings has wrong version and was not restored"); + return; + } + auto updateArray = [](auto& array, const auto& document, const char* name, const auto& accessor) { for (size_t i = 0; i < elemof(array); ++i) { array[i] = accessor(document[name][i]); diff --git a/EventVisualisation/View/src/EventManagerFrame.cxx b/EventVisualisation/View/src/EventManagerFrame.cxx index d1ca190ab6475..ff5ee59047abb 100644 --- a/EventVisualisation/View/src/EventManagerFrame.cxx +++ b/EventVisualisation/View/src/EventManagerFrame.cxx @@ -382,10 +382,9 @@ void EventManagerFrame::checkMemory() if (success == 1) { // properly readed size = 4 * size / 1024; // in MB this->memoryUsedInfo = size; - LOG(info) << "Memory used: " << size << " memory allowed: " << memoryLimit; + LOGF(info, "Memory used: ", size, " memory allowed: ", memoryLimit); if (size > memoryLimit) { - LOG(error) << "Memory used: " << size << " exceeds memory allowed: " - << memoryLimit; + LOGF(error, "Memory used: ", size, " exceeds memory allowed: ", memoryLimit); exit(-1); } } @@ -412,7 +411,7 @@ void EventManagerFrame::createOutreachScreenshot() if (!std::filesystem::is_regular_file(fileName)) { std::vector ext = {".png"}; DirectoryLoader::removeOldestFiles(imageFolder, ext, (int)ConfigurationManager::getOutreachFilesMax()); - LOG(info) << "Outreach screenshot: " << fileName; + LOGF(info, "Outreach screenshot: ", fileName); Screenshot::perform("outreach", fileName, this->mEventManager->getDataSource()->getDetectorsMask(), this->mEventManager->getDataSource()->getRunNumber(), diff --git a/EventVisualisation/View/src/Initializer.cxx b/EventVisualisation/View/src/Initializer.cxx index f11d9bb22701a..e9572e24f991d 100644 --- a/EventVisualisation/View/src/Initializer.cxx +++ b/EventVisualisation/View/src/Initializer.cxx @@ -54,7 +54,7 @@ void Initializer::setup() false); // hide left and bottom tabs const string ocdbStorage = settings.GetValue("OCDB.default.path", o2::base::NameConf::getCCDBServer().c_str()); // default path to OCDB - LOG(info) << "Initializer -- OCDB path:" << ocdbStorage; + LOGF(info, "Initializer -- OCDB path:", ocdbStorage); auto& eventManager = EventManager::getInstance(); eventManager.setCdbPath(ocdbStorage); @@ -132,7 +132,7 @@ void Initializer::setupGeometry() } EVisualisationGroup det = static_cast(iDet); string detName = gVisualisationGroupName[det]; - LOG(info) << detName; + LOGF(info, detName); if (detName == "TPC" || detName == "MCH" || detName == "MID" || detName == "MFT") { // don't load MUON+MFT and AD and standard TPC to R-Phi view diff --git a/EventVisualisation/View/src/MultiView.cxx b/EventVisualisation/View/src/MultiView.cxx index a2f1beed99abf..e651a328dac2b 100644 --- a/EventVisualisation/View/src/MultiView.cxx +++ b/EventVisualisation/View/src/MultiView.cxx @@ -186,7 +186,7 @@ void MultiView::drawGeometryForDetector(string detectorName, bool threeD, bool r void MultiView::registerGeometry(TEveGeoShape* geom, bool threeD, bool rPhi, bool zy) { if (!geom) { - LOG(error) << "MultiView::registerGeometry -- geometry is NULL!"; + LOGF(error, "MultiView::registerGeometry -- geometry is NULL!"); exit(-1); } TEveProjectionManager* projection; diff --git a/EventVisualisation/View/src/Options.cxx b/EventVisualisation/View/src/Options.cxx index 56f44baa7e358..8fad13cc5686e 100644 --- a/EventVisualisation/View/src/Options.cxx +++ b/EventVisualisation/View/src/Options.cxx @@ -84,8 +84,7 @@ bool Options::processCommandLine(int argc, char* argv[]) } if (varmap.count("help")) { - LOG(info) << eveOptions << std::endl - << " default values are always taken from o2eve.json in current folder if present" << std::endl; + LOGF(info, printOptions()); return false; } diff --git a/EventVisualisation/View/src/Screenshot.cxx b/EventVisualisation/View/src/Screenshot.cxx index ed99463987f47..0391b52108f7e 100644 --- a/EventVisualisation/View/src/Screenshot.cxx +++ b/EventVisualisation/View/src/Screenshot.cxx @@ -252,7 +252,6 @@ std::string auto stop = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(stop - start); - LOG(info) << "++++++ Screenshot::perform: " << duration.count(); return fileName; // saved screenshod file name } diff --git a/EventVisualisation/View/src/main.cxx b/EventVisualisation/View/src/main.cxx index fd9ab254c93bb..7b13838446246 100644 --- a/EventVisualisation/View/src/main.cxx +++ b/EventVisualisation/View/src/main.cxx @@ -33,7 +33,7 @@ using namespace o2::event_visualisation; int main(int argc, char** argv) { - LOG(info) << "Welcome in O2 event visualisation tool (" << o2_eve_version << ")"; + LOGF(info, "Welcome in O2 event visualisation tool (", o2_eve_version, ")"); if (!Options::Instance()->processCommandLine(argc, argv)) { exit(-1); @@ -54,18 +54,16 @@ int main(int argc, char** argv) } // create ROOT application environment - TApplication* app = new TApplication("o2eve", &argc, argv); + auto app = new TApplication("o2eve", &argc, argv); gApplication = app; //app->Connect("TEveBrowser", "CloseWindow()", "TApplication", app, "Terminate()"); - LOG(info) << "Initializing TEveManager"; + LOGF(info, "Initializing TEveManager"); if (!TEveManager::Create(kTRUE, "FI")) { - LOG(fatal) << "Could not create TEveManager!!"; + LOGF(fatal, "Could not create TEveManager!!"); exit(0); } - //gEve->SpawnNewViewer("3D View", ""); exit(0); - // Initialize o2 Event Visualisation Initializer::setup(); @@ -76,6 +74,6 @@ int main(int argc, char** argv) TEveManager::Terminate(); app->Terminate(0); - LOG(info) << "O2 event visualisation tool terminated properly"; + LOGF(info, "O2 event visualisation tool terminated properly"); return 0; } diff --git a/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h b/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h index 1c3a50d6a7131..83b448568bbff 100644 --- a/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h +++ b/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h @@ -160,6 +160,7 @@ class EveWorkflowHelper void drawMCHMID(GID gid, float trackTime); void drawPHS(GID gid); void drawEMC(GID gid); + void drawHMP(GID gid); void drawAODBarrel(AODBarrelTrack const& track, float trackTime); void drawAODMFT(AODMFTTrack const& track, float trackTime); @@ -175,6 +176,7 @@ class EveWorkflowHelper void drawTRDClusters(const o2::trd::TrackTRD& trc, float trackTime); void drawTOFClusters(GID gid, float trackTime); void drawPoint(float x, float y, float z, float trackTime) { mEvent.addCluster(x, y, z, trackTime); } + void drawGlobalPoint(const TVector3& xyx) { mEvent.addGlobalCluster(xyx); } void prepareITSClusters(const o2::itsmft::TopologyDictionary* dict); // fills mITSClustersArray void prepareMFTClusters(const o2::itsmft::TopologyDictionary* dict); // fills mMFTClustersArray void clear() { mEvent.clear(); } diff --git a/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h b/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h index b6eb49d19750f..b3431951ed41f 100644 --- a/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h +++ b/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h @@ -47,8 +47,8 @@ class TPCFastTransform; class O2DPLDisplaySpec : public o2::framework::Task { public: - static constexpr auto allowedTracks = "ITS,TPC,MFT,MCH,MID,ITS-TPC,TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD,ITS-TPC-TRD-TOF,MCH-MID,MFT-MCH,MFT-MCH-MID,PHS,EMC"; - static constexpr auto allowedClusters = "ITS,TPC,TRD,TOF,MFT,MCH,MID,PHS,EMC"; + static constexpr auto allowedTracks = "ITS,TPC,MFT,MCH,MID,ITS-TPC,TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD,ITS-TPC-TRD-TOF,MCH-MID,MFT-MCH,MFT-MCH-MID,PHS,EMC,HMP"; + static constexpr auto allowedClusters = "ITS,TPC,TRD,TOF,MFT,MCH,MID,PHS,EMC,HMP"; O2DPLDisplaySpec(bool disableWrite, bool useMC, o2::dataformats::GlobalTrackID::mask_t trkMask, o2::dataformats::GlobalTrackID::mask_t clMask, diff --git a/EventVisualisation/Workflow/src/AO2DConverter.cxx b/EventVisualisation/Workflow/src/AO2DConverter.cxx index 488e0ce28034e..a1ae1b1c5623f 100644 --- a/EventVisualisation/Workflow/src/AO2DConverter.cxx +++ b/EventVisualisation/Workflow/src/AO2DConverter.cxx @@ -48,7 +48,7 @@ struct AO2DConverter { void init(o2::framework::InitContext& ic) { - LOG(info) << "------------------------ AO2DConverter::init version " << mWorkflowVersion << " ------------------------------------"; + LOGF(info, "------------------------ AO2DConverter::init version ", mWorkflowVersion, " ------------------------------------"); mData.init(); mHelper = std::make_shared(); diff --git a/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx b/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx index ad10ae9e9b6cb..3b1b40df9aba3 100644 --- a/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx +++ b/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx @@ -258,6 +258,7 @@ void EveWorkflowHelper::selectTowers() { const auto& allTriggersPHOS = mRecoCont->getPHOSTriggers(); const auto& allTriggersEMCAL = mRecoCont->getEMCALTriggers(); + const auto& allTriggersHMP = mRecoCont->getHMPClusterTriggers(); auto filterTrigger = [&](const auto& trig) { const auto time = bcDiffToTFTimeMUS(trig.getBCData()); @@ -281,14 +282,22 @@ void EveWorkflowHelper::selectTowers() for (std::size_t iv = 0; iv < totalPrimaryVertices; iv++) { const auto& vtref = vtxRefs[iv]; + // to be improved to recognize PV + for (std::size_t i = 0; i < allTriggersHMP.size(); i++) { + mTotalDataTypes[GID::HMP]++; + const auto& trig = allTriggersHMP[i]; + mPrimaryVertexTriggerGIDs[iv].emplace_back(GID{static_cast(i), GID::HMP}); + } + const auto triggersPHOS = gsl::span(trackIndex.data() + vtref.getFirstEntryOfSource(GID::PHS), vtref.getEntriesOfSource(GID::PHS)); for (const auto& tvid : triggersPHOS) { mTotalDataTypes[GID::PHS]++; - const auto& trig = allTriggersPHOS[tvid.getIndex()]; - - if (filterTrigger(trig)) { - mPrimaryVertexTriggerGIDs[iv].emplace_back(tvid); + if (tvid.getIndex() < allTriggersPHOS.size()) { + const auto& trig = allTriggersPHOS[tvid.getIndex()]; + if (filterTrigger(trig)) { + mPrimaryVertexTriggerGIDs[iv].emplace_back(tvid); + } } } @@ -296,14 +305,23 @@ void EveWorkflowHelper::selectTowers() for (const auto& tvid : triggersEMCAL) { mTotalDataTypes[GID::EMC]++; - const auto& trig = allTriggersEMCAL[tvid.getIndex()]; + if (tvid.getIndex() < allTriggersEMCAL.size()) { + const auto& trig = allTriggersEMCAL[tvid.getIndex()]; - if (filterTrigger(trig)) { - mPrimaryVertexTriggerGIDs[iv].emplace_back(tvid); + if (filterTrigger(trig)) { + mPrimaryVertexTriggerGIDs[iv].emplace_back(tvid); + } } } } } else { + + for (std::size_t i = 0; i < allTriggersHMP.size(); i++) { + mTotalDataTypes[GID::HMP]++; + const auto& trig = allTriggersHMP[i]; + mPrimaryVertexTriggerGIDs[0].emplace_back(GID{static_cast(i), GID::HMP}); + } + for (std::size_t i = 0; i < allTriggersPHOS.size(); i++) { mTotalDataTypes[GID::PHS]++; const auto& trig = allTriggersPHOS[i]; @@ -432,6 +450,9 @@ void EveWorkflowHelper::draw(std::size_t primaryVertexIdx, bool sortTracks) case GID::EMC: drawEMC(gid); break; + case GID::HMP: + drawHMP(gid); + break; default: LOGF(info, "Trigger type %s not handled", gid.getSourceName()); break; @@ -565,6 +586,27 @@ void EveWorkflowHelper::prepareMFTClusters(const o2::itsmft::TopologyDictionary* } } +void EveWorkflowHelper::drawHMP(GID gid) +{ + o2::hmpid::Param* pParam = o2::hmpid::Param::instance(); + const auto& trig = mRecoCont->getHMPClusterTriggers()[gid.getIndex()]; + const auto& clusters = mRecoCont->getHMPClusters(); + + auto bc = trig.getBc(); + auto orbit = trig.getOrbit(); + auto time = o2::InteractionTimeRecord::bc2ns(bc, orbit); // in ns absolute time + + for (int j = trig.getFirstEntry(); j <= trig.getLastEntry(); j++) { + auto cluster = clusters[j]; + auto module = cluster.ch(); + double x = cluster.x(); + double y = cluster.y(); + + TVector3 vec3 = pParam->lors2Mars(module, x, y); + drawGlobalPoint(vec3); + } +} + void EveWorkflowHelper::drawPHS(GID gid) { const auto& cells = mRecoCont->getPHOSCells(); diff --git a/EventVisualisation/Workflow/src/O2DPLDisplay.cxx b/EventVisualisation/Workflow/src/O2DPLDisplay.cxx index 653ba00941a1c..3885bbce959a8 100644 --- a/EventVisualisation/Workflow/src/O2DPLDisplay.cxx +++ b/EventVisualisation/Workflow/src/O2DPLDisplay.cxx @@ -90,7 +90,7 @@ void customize(std::vector& workflowOptions) #include "Framework/runDataProcessing.h" // main method must be included here (otherwise customize not used) void O2DPLDisplaySpec::init(InitContext& ic) { - LOG(info) << "------------------------ O2DPLDisplay::init version " << o2_eve_version << " ------------------------------------"; + LOGF(info, "------------------------ O2DPLDisplay::init version ", o2_eve_version, " ------------------------------------"); mData.mConfig.configProcessing.runMC = mUseMC; o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); } @@ -103,7 +103,7 @@ void O2DPLDisplaySpec::run(ProcessingContext& pc) if (this->mOnlyNthEvent && this->mEventCounter++ % this->mOnlyNthEvent != 0) { return; } - LOG(info) << "------------------------ O2DPLDisplay::run version " << o2_eve_version << " ------------------------------------"; + LOGF(info, "------------------------ O2DPLDisplay::run version ", o2_eve_version, " ------------------------------------"); // filtering out any run which occur before reaching next time interval auto currentTime = std::chrono::high_resolution_clock::now(); std::chrono::duration elapsed = currentTime - this->mTimeStamp; @@ -114,28 +114,23 @@ void O2DPLDisplaySpec::run(ProcessingContext& pc) o2::globaltracking::RecoContainer recoCont; recoCont.collectData(pc, *mDataRequest); updateTimeDependentParams(pc); // Make sure that this is called after the RecoContainer collect data, since some condition objects are fetched there - EveWorkflowHelper::FilterSet enabledFilters; enabledFilters.set(EveWorkflowHelper::Filter::ITSROF, this->mFilterITSROF); enabledFilters.set(EveWorkflowHelper::Filter::TimeBracket, this->mFilterTime); enabledFilters.set(EveWorkflowHelper::Filter::EtaBracket, this->mRemoveTPCEta); enabledFilters.set(EveWorkflowHelper::Filter::TotalNTracks, this->mNumberOfTracks != -1); - EveWorkflowHelper helper(enabledFilters, this->mNumberOfTracks, this->mTimeBracket, this->mEtaBracket, this->mPrimaryVertexMode); helper.setRecoContainer(&recoCont); - helper.setITSROFs(); helper.selectTracks(&(mData.mConfig.configCalib), mClMask, mTrkMask, mTrkMask); helper.selectTowers(); - helper.prepareITSClusters(mData.mITSDict); helper.prepareMFTClusters(mData.mMFTDict); const auto& tinfo = pc.services().get(); std::size_t filesSaved = 0; - auto processData = [&](const auto& dataMap) { for (const auto& keyVal : dataMap) { if (filesSaved >= mMaxPrimaryVertices) { @@ -185,7 +180,6 @@ void O2DPLDisplaySpec::run(ProcessingContext& pc) helper.clear(); } }; - if (mPrimaryVertexTriggers) { processData(helper.mPrimaryVertexTriggerGIDs); } else { @@ -247,12 +241,12 @@ void O2DPLDisplaySpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) return; } if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { - LOG(info) << "ITS cluster dictionary updated"; + LOGF(info, "ITS cluster dictionary updated"); mData.setITSDict((const o2::itsmft::TopologyDictionary*)obj); return; } if (matcher == ConcreteDataMatcher("MFT", "CLUSDICT", 0)) { - LOG(info) << "MFT cluster dictionary updated"; + LOGF(info, "MFT cluster dictionary updated"); mData.setMFTDict((const o2::itsmft::TopologyDictionary*)obj); return; } @@ -260,17 +254,17 @@ void O2DPLDisplaySpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - LOG(info) << "------------------------ defineDataProcessing " << o2_eve_version << " ------------------------------------"; + LOGF(info, "------------------------ defineDataProcessing ", o2_eve_version, " ------------------------------------"); WorkflowSpec specs; - std::string jsonFolder = cfgc.options().get("jsons-folder"); + auto jsonFolder = cfgc.options().get("jsons-folder"); std::string ext = ".root"; // root files are default format auto useJsonFormat = cfgc.options().get("use-json-format"); if (useJsonFormat) { ext = ".json"; } - std::string eveHostName = cfgc.options().get("eve-hostname"); + auto eveHostName = cfgc.options().get("eve-hostname"); o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); bool useMC = !cfgc.options().get("disable-mc"); bool disableWrite = cfgc.options().get("disable-write"); @@ -284,9 +278,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) char* colIdx = getenv("DDS_COLLECTION_INDEX"); int myIdx = colIdx ? atoi(colIdx) : -1; if (myIdx == eveDDSColIdx) { - LOG(important) << "Restricting DPL Display to collection index, my index " << myIdx << ", enabled " << int(myIdx == eveDDSColIdx); + LOGF(important, "Restricting DPL Display to collection index, my index ", myIdx, ", enabled ", int(myIdx == eveDDSColIdx)); } else { - LOG(info) << "Restricting DPL Display to collection index, my index " << myIdx << ", enabled " << int(myIdx == eveDDSColIdx); + LOGF(info, "Restricting DPL Display to collection index, my index ", myIdx, ", enabled ", int(myIdx == eveDDSColIdx)); } eveHostNameMatch &= myIdx == eveDDSColIdx; } @@ -310,7 +304,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) if (!srcTrk.any() && !srcCl.any()) { if (cfgc.options().get("skipOnEmptyInput")) { - LOG(info) << "No valid inputs for event display, disabling event display"; + LOGF(info, "No valid inputs for event display, disabling event display"); return std::move(specs); } throw std::runtime_error("No input configured"); From d87093b330a2cf66dc6b9f680c1dab51da6f9965 Mon Sep 17 00:00:00 2001 From: iravasen Date: Wed, 4 Oct 2023 14:52:30 +0200 Subject: [PATCH 206/324] ITS DCS parser: added configurable url to retrieve RCT headers (#11978) * added configurable url to retrieve RCT headers * default ccdb to o2 ccdb internal --- .../ITS/workflow/include/ITSWorkflow/DCSParserSpec.h | 3 +++ Detectors/ITSMFT/ITS/workflow/src/DCSParserSpec.cxx | 11 ++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/DCSParserSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/DCSParserSpec.h index 0f452dcd7e0d8..29cb5a660dab1 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/DCSParserSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/DCSParserSpec.h @@ -142,6 +142,9 @@ class ITSDCSParser : public Task // ITS Map o2::itsmft::ChipMappingITS mp; + + // CCDB url for RCT headers + std::string mCcdbUrlRct = "http://o2-ccdb.internal"; }; // Create a processor spec diff --git a/Detectors/ITSMFT/ITS/workflow/src/DCSParserSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/DCSParserSpec.cxx index 53618ae55851b..8cd631d0a719d 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/DCSParserSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/DCSParserSpec.cxx @@ -36,6 +36,8 @@ void ITSDCSParser::init(InitContext& ic) this->mCcdbUrl = ic.options().get("ccdb-url"); + this->mCcdbUrlRct = ic.options().get("ccdb-url-rct"); + this->mVerboseOutput = ic.options().get("verbose"); return; @@ -469,7 +471,7 @@ void ITSDCSParser::pushToCCDB(ProcessingContext& pc) long tstart = 0, tend = 0; // retireve run start/stop times from CCDB o2::ccdb::CcdbApi api; - api.init("http://alice-ccdb.cern.ch"); + api.init(mCcdbUrlRct); // Initialize empty metadata object for search std::map metadata; std::map headers = api.retrieveHeaders( @@ -582,7 +584,9 @@ void ITSDCSParser::appendDeadChipObj() unsigned short int globchipID = getGlobalChipID(hicPos, hS, chipInMod); this->mDeadMap.maskFullChip(globchipID); - LOG(info) << "Masking dead chip " << globchipID; + if (mVerboseOutput) { + LOG(info) << "Masking dead chip " << globchipID; + } } } @@ -660,7 +664,8 @@ DataProcessorSpec getITSDCSParserSpec() AlgorithmSpec{adaptFromTask()}, Options{ {"verbose", VariantType::Bool, false, {"Use verbose output mode"}}, - {"ccdb-url", VariantType::String, "", {"CCDB url, default is empty (i.e. send output to CCDB populator workflow)"}}}}; + {"ccdb-url", VariantType::String, "", {"CCDB url, default is empty (i.e. send output to CCDB populator workflow)"}}, + {"ccdb-url-rct", VariantType::String, "", {"CCDB url from where to get RCT object for headers, default is o2-ccdb.internal. Use http://alice-ccdb.cern.ch for local tests"}}}}; } } // namespace its } // namespace o2 From 9df4e93cd2ca1f28e2b34a3be323613ecd67be6b Mon Sep 17 00:00:00 2001 From: mfasel Date: Tue, 3 Oct 2023 20:03:12 +0200 Subject: [PATCH 207/324] [EMCAL-1048] Treat faulty memory size reported by RDH In case the memory size in the RDH reported is larger then the raw payload size forward the current positon to payload size or offsetToNext - whatever is smaller, before raising the error. In case the trailer is incomplete the page cannot be trusted, likely because it is overwritten in memory. The marker must be forwarded and an exception is thrown. --- .../EMCALReconstruction/RawReaderMemory.h | 9 ++-- .../reconstruction/src/RawReaderMemory.cxx | 43 ++++++++++++++++++- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawReaderMemory.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawReaderMemory.h index 463fe4981b7cf..f726d1307fb90 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawReaderMemory.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RawReaderMemory.h @@ -148,11 +148,10 @@ class RawReaderMemory /// Rewind stream to the first entry void init(); - /// \brief Check whether the current page is accepted - /// \param page Raw page to check - /// \return True if the page is accepted, false otherwise - bool acceptPage(const char* page) const; - + /// \brief Decode raw header words + /// \param headerwords Headerwords + /// \return Decoded RDH + /// \throw RawDecodingError with code HEADER_DECODING if the payload does not correspond to an expected header o2::header::RDHAny decodeRawHeader(const void* headerwords); private: diff --git a/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx b/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx index 7f247eee2fbba..977c55f7225d3 100644 --- a/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx +++ b/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx @@ -8,11 +8,13 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. - +#include #include #include #include "EMCALReconstruction/RawReaderMemory.h" #include "DetectorsRaw/RDHUtils.h" +#include "Headers/RAWDataHeader.h" +#include "Headers/DAQID.h" using namespace o2::emcal; @@ -35,6 +37,16 @@ o2::header::RDHAny RawReaderMemory::decodeRawHeader(const void* payloadwords) if (headerversion < RDHDecoder::getVersion() || headerversion > RDHDecoder::getVersion()) { throw RawDecodingError(RawDecodingError::ErrorType_t::HEADER_DECODING, mCurrentFEE); } + if (!RDHDecoder::checkRDH(payloadwords, false, true)) { + // Header size != to 64 and 0 in reserved words indicate that the header is a fake header + throw RawDecodingError(RawDecodingError::ErrorType_t::HEADER_DECODING, mCurrentFEE); + } + if (RDHDecoder::getVersion(payloadwords) >= 6) { + // If header version is >= 6 check that the source ID is EMCAL + if (RDHDecoder::getSourceID(payloadwords) != o2::header::DAQID::EMC) { + throw RawDecodingError(RawDecodingError::ErrorType_t::HEADER_DECODING, mCurrentFEE); + } + } return {*reinterpret_cast(payloadwords)}; } @@ -117,9 +129,31 @@ void RawReaderMemory::nextPage(bool doResetPayload) } if (mCurrentPosition + RDHDecoder::getMemorySize(mRawHeader) > mRawMemoryBuffer.size()) { // Payload incomplete + // Set to offset to next or buffer size, whatever is smaller + if (mCurrentPosition + RDHDecoder::getOffsetToNext(mRawHeader) < mRawMemoryBuffer.size()) { + mCurrentPosition += RDHDecoder::getOffsetToNext(mRawHeader); + if (mCurrentPosition + 64 < mRawMemoryBuffer.size()) { + // check if the page continues with a RDH + // if next page is not a header decodeRawHeader will throw a RawDecodingError + auto nextheader = decodeRawHeader(mRawMemoryBuffer.data() + mCurrentPosition); + if (RDHDecoder::getVersion(nextheader) != RDHDecoder::getVersion(mRawHeader)) { + // Next header has different header version - clear indication that it is a fake header + throw RawDecodingError(RawDecodingError::ErrorType_t::HEADER_DECODING, mCurrentFEE); + } + } + } else { + mCurrentPosition = mRawMemoryBuffer.size(); + } + // RDHDecoder::printRDH(mRawHeader); throw RawDecodingError(RawDecodingError::ErrorType_t::PAYLOAD_DECODING, mCurrentFEE); } else if (mCurrentPosition + RDHDecoder::getHeaderSize(mRawHeader) > mRawMemoryBuffer.size()) { // Start position of the payload is outside the payload range + // Set to offset to next or buffer size, whatever is smaller + if (mCurrentPosition + RDHDecoder::getOffsetToNext(mRawHeader) < mRawMemoryBuffer.size()) { + mCurrentPosition += RDHDecoder::getOffsetToNext(mRawHeader); + } else { + mCurrentPosition = mRawMemoryBuffer.size(); + } throw RawDecodingError(RawDecodingError::ErrorType_t::PAGE_START_INVALID, mCurrentFEE); } else { mRawBuffer.readFromMemoryBuffer(gsl::span(mRawMemoryBuffer.data() + mCurrentPosition + RDHDecoder::getHeaderSize(mRawHeader), RDHDecoder::getMemorySize(mRawHeader) - RDHDecoder::getHeaderSize(mRawHeader))); @@ -154,6 +188,13 @@ void RawReaderMemory::nextPage(bool doResetPayload) mMinorErrors.emplace_back(RawDecodingError::ErrorType_t::TRAILER_INCOMPLETE, mCurrentFEE); } } catch (RCUTrailer::Error& e) { + // We must forward the position in such cases in order to not end up in an infinity loop + if (mCurrentPosition + RDHDecoder::getOffsetToNext(mRawHeader) < mRawMemoryBuffer.size()) { + mCurrentPosition += RDHDecoder::getOffsetToNext(mRawHeader); + } else { + mCurrentPosition = mRawMemoryBuffer.size(); + } + // Page is not consistent - must be skipped throw RawDecodingError(RawDecodingError::ErrorType_t::TRAILER_DECODING, mCurrentFEE); } } else { From 8c5e0ec8df10f444a29769ad82f9c445c3a0a1bc Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 4 Oct 2023 19:36:52 +0200 Subject: [PATCH 208/324] DPL: drop ReadoutAdapter (#12016) Pre-DataDistribution prototype not needed at this point. --- Framework/Core/CMakeLists.txt | 1 - .../Core/include/Framework/ReadoutAdapter.h | 31 ------------- Framework/Core/src/ReadoutAdapter.cxx | 46 ------------------- 3 files changed, 78 deletions(-) delete mode 100644 Framework/Core/include/Framework/ReadoutAdapter.h delete mode 100644 Framework/Core/src/ReadoutAdapter.cxx diff --git a/Framework/Core/CMakeLists.txt b/Framework/Core/CMakeLists.txt index eabc3f7c30593..898fb3f6441fd 100644 --- a/Framework/Core/CMakeLists.txt +++ b/Framework/Core/CMakeLists.txt @@ -109,7 +109,6 @@ o2_add_library(Framework src/ProcessingContext.cxx src/Plugins.cxx src/RateLimiter.cxx - src/ReadoutAdapter.cxx src/ResourcesMonitoringHelper.cxx src/ResourcePolicy.cxx src/ResourcePolicyHelpers.cxx diff --git a/Framework/Core/include/Framework/ReadoutAdapter.h b/Framework/Core/include/Framework/ReadoutAdapter.h deleted file mode 100644 index 873ba9cf807d2..0000000000000 --- a/Framework/Core/include/Framework/ReadoutAdapter.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef o2_framework_ReadoutAdapter_H_DEFINED -#define o2_framework_ReadoutAdapter_H_DEFINED - -#include "ExternalFairMQDeviceProxy.h" - -namespace o2 -{ -namespace framework -{ - -/// An adapter function for data sent by Readout. It gets the raw pages as -/// provided by Readout and wraps them in a multipart message where the -/// DataHeader is specified by the OutputSpec, while the DataProcessing header -/// is an enumeration of the pages received. -InjectorFunction readoutAdapter(OutputSpec const& spec); - -} // namespace framework -} // namespace o2 - -#endif // o2_framework_ReadoutAdapter_H_DEFINED diff --git a/Framework/Core/src/ReadoutAdapter.cxx b/Framework/Core/src/ReadoutAdapter.cxx deleted file mode 100644 index 9b0c96fcad6ba..0000000000000 --- a/Framework/Core/src/ReadoutAdapter.cxx +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Framework/ReadoutAdapter.h" -#include "Framework/DataProcessingHeader.h" -#include "Framework/DataSpecUtils.h" -#include "Headers/DataHeader.h" - -namespace o2 -{ -namespace framework -{ - -using DataHeader = o2::header::DataHeader; - -InjectorFunction readoutAdapter(OutputSpec const& spec) -{ - return [spec](TimingInfo&, fair::mq::Device& device, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { - for (size_t i = 0; i < parts.Size(); ++i) { - DataHeader dh; - // FIXME: this will have to change and extract the actual subspec from - // the data. - ConcreteDataMatcher concrete = DataSpecUtils::asConcreteDataMatcher(spec); - dh.dataOrigin = concrete.origin; - dh.dataDescription = concrete.description; - dh.subSpecification = concrete.subSpec; - dh.payloadSize = parts.At(i)->GetSize(); - dh.payloadSerializationMethod = o2::header::gSerializationMethodNone; - - DataProcessingHeader dph{newTimesliceId, 0}; - o2::header::Stack headerStack{dh, dph}; - sendOnChannel(device, std::move(headerStack), std::move(parts.At(i)), spec, channelRetriever); - } - }; -} - -} // namespace framework -} // namespace o2 From 9bc3e88d7e40829607e740264291e899afcc1476 Mon Sep 17 00:00:00 2001 From: shahoian Date: Wed, 4 Oct 2023 20:12:23 +0200 Subject: [PATCH 209/324] Fill N nearest neighbours in T and Z for vtx study. --- .../PrimaryVertexExt.h | 8 +- .../Reconstruction/src/PrimaryVertexExt.cxx | 2 +- .../study/src/TrackingStudy.cxx | 114 +++++++++++++++--- 3 files changed, 105 insertions(+), 19 deletions(-) diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h index 9037066884da6..80a47c5ce6405 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h @@ -25,8 +25,10 @@ namespace dataformats struct PrimaryVertexExt : public PrimaryVertex { using PrimaryVertex::PrimaryVertex; std::array nSrc{}; // N contributors for each source type - float FT0Amp = 0; // amplitude of closest FT0 trigger - float FT0Time = 0.; // time of closest FT0 trigger + int VtxID = -1; // original vtx ID + float FT0Amp = -1; // amplitude of closest FT0 trigger + float FT0A = -1; // amplitude of the A side + float FT0Time = -1.; // time of closest FT0 trigger int getNSrc(int i) const { return nSrc[i]; } @@ -35,7 +37,7 @@ struct PrimaryVertexExt : public PrimaryVertex { std::string asString() const; #endif - ClassDefNV(PrimaryVertexExt, 1); + ClassDefNV(PrimaryVertexExt, 2); }; #ifndef GPUCA_ALIGPUCODE diff --git a/DataFormats/Reconstruction/src/PrimaryVertexExt.cxx b/DataFormats/Reconstruction/src/PrimaryVertexExt.cxx index 2f77c10f937a9..3d8ec6c5fa7c2 100644 --- a/DataFormats/Reconstruction/src/PrimaryVertexExt.cxx +++ b/DataFormats/Reconstruction/src/PrimaryVertexExt.cxx @@ -24,7 +24,7 @@ using GTrackID = o2::dataformats::GlobalTrackID; std::string PrimaryVertexExt::asString() const { - auto str = o2::utils::Str::concat_string(PrimaryVertex::asString(), fmt::format(" FT0Amp={} FT0T={}", FT0Amp, FT0Time)); + auto str = o2::utils::Str::concat_string(PrimaryVertex::asString(), fmt::format("VtxID={} FT0A/C={}/{} FT0T={}", VtxID, FT0A, FT0Amp - FT0A, FT0Time)); for (int i = 0; i < GTrackID::Source::NSources; i++) { if (getNSrc(i) > 0) { str += fmt::format(" {}={}", GTrackID::getSourceName(i), getNSrc(i)); diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx index daa3617c74dfc..cbd25f790686d 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx @@ -73,6 +73,8 @@ class TrackingStudySpec : public Task std::unique_ptr mDBGOut; std::unique_ptr mDBGOutVtx; float mITSROFrameLengthMUS = 0.; + int mMaxNeighbours = 3; + float mMaxVTTimeDiff = 25.; // \mus GTrackID::mask_t mTracksSrc{}; o2::steer::MCKinematicsReader mcReader; // reader of MC information }; @@ -82,6 +84,9 @@ void TrackingStudySpec::init(InitContext& ic) o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); mDBGOut = std::make_unique("trackStudy.root", "recreate"); mDBGOutVtx = std::make_unique("trackStudyVtx.root", "recreate"); + + mMaxVTTimeDiff = ic.options().get("max-vtx-timediff"); + mMaxNeighbours = ic.options().get("max-vtx-neighbours"); } void TrackingStudySpec::run(ProcessingContext& pc) @@ -116,6 +121,7 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) auto vtxRefs = recoData.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs auto prop = o2::base::Propagator::Instance(); auto FITInfo = recoData.getFT0RecPoints(); + static int TFCount = 0; int nv = vtxRefs.size() - 1; o2::dataformats::PrimaryVertexExt pveDummy; std::vector pveVec; @@ -128,7 +134,8 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) auto& pve = pveVec.emplace_back(); static_cast(pve) = pv; - float bestTimeDiff = 1000, bestTime = -999, bestAmp = -1; + float bestTimeDiff = 1000, bestTime = -999; + int bestFTID = -1; if (mTracksSrc[GTrackID::FT0]) { for (int ift0 = vtref.getFirstEntryOfSource(GTrackID::FT0); ift0 < vtref.getFirstEntryOfSource(GTrackID::FT0) + vtref.getEntriesOfSource(GTrackID::FT0); ift0++) { const auto& ft0 = FITInfo[trackIndex[ift0]]; @@ -136,20 +143,21 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) auto fitTime = ft0.getInteractionRecord().differenceInBCMUS(recoData.startIR); if (std::abs(fitTime - pv.getTimeStamp().getTimeStamp()) < bestTimeDiff) { bestTimeDiff = fitTime - pv.getTimeStamp().getTimeStamp(); - bestTime = fitTime; - bestAmp = ft0.getTrigger().getAmplA() + ft0.getTrigger().getAmplC(); + bestFTID = trackIndex[ift0]; } } } } else { LOGP(warn, "FT0 is not requested, cannot set complete vertex info"); } - pve.FT0Amp = bestAmp; - pve.FT0Time = bestTime; + if (bestFTID >= 0) { + pve.FT0A = FITInfo[bestFTID].getTrigger().getAmplA(); + pve.FT0Amp = pve.FT0A + FITInfo[bestFTID].getTrigger().getAmplC(); + pve.FT0Time = FITInfo[bestFTID].getInteractionRecord().differenceInBCMUS(recoData.startIR); + } + pve.VtxID = iv; for (int is = 0; is < GTrackID::NSources; is++) { - if (!GTrackID::getSourceDetectorsMask(is)[GTrackID::ITS] || !mTracksSrc[is] || !recoData.isTrackSourceLoaded(is)) { - continue; - } + bool skipTracks = (!GTrackID::getSourceDetectorsMask(is)[GTrackID::ITS] || !mTracksSrc[is] || !recoData.isTrackSourceLoaded(is)); int idMin = vtref.getFirstEntryOfSource(is), idMax = idMin + vtref.getEntriesOfSource(is); for (int i = idMin; i < idMax; i++) { auto vid = trackIndex[i]; @@ -157,6 +165,9 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) if (pvCont) { pve.nSrc[is]++; } + if (skipTracks) { + continue; + } bool ambig = vid.isAmbiguous(); auto trc = recoData.getTrackParam(vid); float xmin = trc.getX(); @@ -169,17 +180,87 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) } } } - - for (size_t cnt = 0; cnt < pveVec.size(); cnt++) { + int nvtot = mMaxNeighbours < 0 ? -1 : (int)pveVec.size(); + for (int cnt = 0; cnt < nvtot; cnt++) { const auto& pve = pveVec[cnt]; - const auto& pvePrev = cnt > 0 ? pveVec[cnt - 1] : pveDummy; - const auto& pveNext = cnt == pveVec.size() - 1 ? pveDummy : pveVec[cnt + 1]; + float tv = pve.getTimeStamp().getTimeStamp(); + std::vector pveT(mMaxNeighbours); // neighbours in time + std::vector pveZ(mMaxNeighbours); // neighbours in Z + std::vector idT(mMaxNeighbours), idZ(mMaxNeighbours); + std::vector dT(mMaxNeighbours), dZ(mMaxNeighbours); + for (int i = 0; i < mMaxNeighbours; i++) { + idT[i] = idZ[i] = -1; + dT[i] = mMaxVTTimeDiff; + dZ[i] = 1e9; + } + int cntM = cnt - 1, cntP = cnt + 1; + for (; cntM >= 0; cntM--) { // backward + const auto& vt = pveVec[cntM]; + auto dtime = std::abs(tv - vt.getTimeStamp().getTimeStamp()); + if (dtime > mMaxVTTimeDiff) { + continue; + } + for (int i = 0; i < mMaxNeighbours; i++) { + if (dT[i] > dtime) { + dT[i] = dtime; + idT[i] = cntM; + break; + } + } + auto dz = std::abs(pve.getZ() - vt.getZ()); + for (int i = 0; i < mMaxNeighbours; i++) { + if (dZ[i] > dz) { + dZ[i] = dz; + idZ[i] = cntM; + break; + } + } + } + for (; cntP < nvtot; cntP++) { // forward + const auto& vt = pveVec[cntP]; + auto dtime = std::abs(tv - vt.getTimeStamp().getTimeStamp()); + if (dtime > mMaxVTTimeDiff) { + continue; + } + for (int i = 0; i < mMaxNeighbours; i++) { + if (dT[i] > dtime) { + dT[i] = dtime; + idT[i] = cntP; + break; + } + } + auto dz = std::abs(pve.getZ() - vt.getZ()); + for (int i = 0; i < mMaxNeighbours; i++) { + if (dZ[i] > dz) { + dZ[i] = dz; + idZ[i] = cntP; + break; + } + } + } + for (int i = 0; i < mMaxNeighbours; i++) { + if (idT[i] != -1) { + pveT[i] = pveVec[idT[i]]; + } else { + break; + } + } + for (int i = 0; i < mMaxNeighbours; i++) { + if (idZ[i] != -1) { + pveZ[i] = pveVec[idZ[i]]; + } else { + break; + } + } (*mDBGOutVtx) << "pvExt" << "pve=" << pve - << "pveP=" << pvePrev - << "pveN=" << pveNext + << "pveT=" << pveT + << "pveZ=" << pveZ + << "tfID=" << TFCount << "\n"; } + + TFCount++; } void TrackingStudySpec::endOfStream(EndOfStreamContext& ec) @@ -217,7 +298,10 @@ DataProcessorSpec getTrackingStudySpec(GTrackID::mask_t srcTracks, GTrackID::mas dataRequest->inputs, outputs, AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, srcTracks, useMC)}, - Options{}}; + Options{ + {"max-vtx-neighbours", VariantType::Int, 2, {"Max PV neighbours fill, no PV study if < 0"}}, + {"max-vtx-timediff", VariantType::Float, 25.f, {"Max PV time difference to consider"}}, + }}; } } // namespace o2::trackstudy From cf1b805362e4bcdcf178ddd73af95299e6b07bd8 Mon Sep 17 00:00:00 2001 From: Ruben Shahoyan Date: Thu, 5 Oct 2023 00:51:46 +0200 Subject: [PATCH 210/324] Revert "[rANS] Fix Compiler Warnings" This reverts commit 354fbb1596de09aad1df51c460497d55d1e4ac7f. --- .../DetectorsCommonDataFormats/EncodedBlocks.h | 4 +++- .../internal/ExternalEntropyCoder.h | 2 +- .../internal/InplaceEntropyCoder.h | 1 + .../Detectors/Common/test/testCTFEntropyCoder.cxx | 4 ++-- Utilities/rANS/benchmarks/bench_ransHistogram.cxx | 4 ++-- .../rANS/internal/containers/DenseHistogram.h | 4 +++- .../internal/containers/ReverseSymbolLookupTable.h | 4 ++-- .../rANS/include/rANS/internal/containers/Symbol.h | 7 +++++-- .../rANS/include/rANS/internal/encode/Encoder.h | 4 ---- .../rANS/internal/encode/EncoderSymbolMapper.h | 4 ++++ .../rANS/internal/encode/SingleStreamEncoderImpl.h | 2 ++ .../rANS/internal/pack/DictionaryStreamReader.h | 2 +- .../include/rANS/internal/transform/algorithmImpl.h | 2 +- .../rANS/include/rANS/internal/transform/renorm.h | 1 + Utilities/rANS/run/bin-encode-decode.cxx | 2 +- Utilities/rANS/test/test_ransHistograms.cxx | 3 +++ Utilities/rANS/test/test_ransMetrics.cxx | 1 + Utilities/rANS/test/test_ransPack.cxx | 3 ++- Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx | 12 +++++------- Utilities/rANS/test/test_ransSparseVector.cxx | 2 ++ Utilities/rANS/test/test_ransSymbolTables.cxx | 2 +- 21 files changed, 43 insertions(+), 27 deletions(-) diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index 3deae46f00913..6afc171a79d7c 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -835,7 +835,7 @@ auto EncodedBlocks::getImage(const void* newHead) // we don't modify newHead, but still need to remove constness for relocation interface relocate(image.mRegistry.head, const_cast(reinterpret_cast(newHead)), reinterpret_cast(&image)); - return image; + return std::move(image); } ///_____________________________________________________________________________ @@ -945,6 +945,7 @@ CTFIOSize EncodedBlocks::decodeCompatImpl(dst_IT dstBegin, int slot, co { // get references to the right data + const auto& ansVersion = getANSHeader(); const auto& block = mBlocks[slot]; const auto& md = mMetadata[slot]; @@ -983,6 +984,7 @@ CTFIOSize EncodedBlocks::decodeRansV1Impl(dst_IT dstBegin, int slot, co { // get references to the right data + const auto& ansVersion = getANSHeader(); const auto& block = mBlocks[slot]; const auto& md = mMetadata[slot]; diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h index 5335514278e26..6a8be509c021c 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h @@ -79,7 +79,7 @@ template constexpr size_t Overhead = 10 * rans::utils::pow2(10); // 10KB overhead safety margin const double_t RelativeSafetyFactor = 2.0 * safetyFactor; const size_t messageSizeB = nElements * sizeof(source_type); - return rans::utils::nBytesTo(std::ceil(RelativeSafetyFactor * messageSizeB) + Overhead); + return rans::utils::nBytesTo(std::ceil(safetyFactor * messageSizeB) + Overhead); } template diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h index 8601469b34142..54302d51d2666 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h @@ -166,6 +166,7 @@ void InplaceEntropyCoder::makeEncoder() } const size_t rangeBits = rans::utils::getRangeBits(*mMetrics.getCoderProperties().min, *mMetrics.getCoderProperties().max); + const size_t nSamples = mMetrics.getDatasetProperties().numSamples; const size_t nUsedAlphabetSymbols = mMetrics.getDatasetProperties().nUsedAlphabetSymbols; if (rangeBits <= 18) { diff --git a/DataFormats/Detectors/Common/test/testCTFEntropyCoder.cxx b/DataFormats/Detectors/Common/test/testCTFEntropyCoder.cxx index 6b688fcebc7f7..3471a6c9e4dff 100644 --- a/DataFormats/Detectors/Common/test/testCTFEntropyCoder.cxx +++ b/DataFormats/Detectors/Common/test/testCTFEntropyCoder.cxx @@ -126,7 +126,7 @@ void encodeInplace(source_IT begin, source_IT end) std::vector dictBuffer(sizeEstimate.getCompressedDictionarySize(), 0); auto encoderEnd = entropyCoder.encode(begin, end, encodeBuffer.data(), encodeBuffer.data() + encodeBuffer.size()); - [[maybe_unused]] auto literalsEnd = entropyCoder.writeIncompressible(literalSymbolsBuffer.data(), literalSymbolsBuffer.data() + literalSymbolsBuffer.size()); + auto literalsEnd = entropyCoder.writeIncompressible(literalSymbolsBuffer.data(), literalSymbolsBuffer.data() + literalSymbolsBuffer.size()); auto dictEnd = entropyCoder.writeDictionary(dictBuffer.data(), dictBuffer.data() + dictBuffer.size()); // decode const auto& coderProperties = metrics.getCoderProperties(); @@ -303,7 +303,7 @@ void encodeExternal(source_IT begin, source_IT end) auto encoderEnd = entropyCoder.encode(begin, end, encodeBuffer.data(), encodeBuffer.data() + encodeBuffer.size()); std::vector literalSymbolsBuffer(entropyCoder.template computePackedIncompressibleSize(), 0); - [[maybe_unused]] auto literalsEnd = entropyCoder.writeIncompressible(literalSymbolsBuffer.data(), literalSymbolsBuffer.data() + literalSymbolsBuffer.size()); + auto literalsEnd = entropyCoder.writeIncompressible(literalSymbolsBuffer.data(), literalSymbolsBuffer.data() + literalSymbolsBuffer.size()); // decode auto decoder = ExternalEncoders.getDecoder(); diff --git a/Utilities/rANS/benchmarks/bench_ransHistogram.cxx b/Utilities/rANS/benchmarks/bench_ransHistogram.cxx index 084d4b8fca1bc..9c32117ba914b 100644 --- a/Utilities/rANS/benchmarks/bench_ransHistogram.cxx +++ b/Utilities/rANS/benchmarks/bench_ransHistogram.cxx @@ -137,7 +137,7 @@ void ransMakeHistogramBenchmark(benchmark::State& st, Args&&... args) histogram_type hist{}; hist.addSamples(gsl::span(inputData)); - for (std::ptrdiff_t symbol = histogram.getOffset(); symbol != histogram.getOffset() + static_cast(histogram.size()); ++symbol) { + for (std::ptrdiff_t symbol = histogram.getOffset(); symbol != histogram.getOffset() + histogram.size(); ++symbol) { if (histogram[symbol] > 0) { LOG_IF(info, histogram[symbol] != hist[symbol]) << fmt::format("[{}]: {} != {}", symbol, hist[symbol], histogram[symbol]); isSame = isSame && (histogram[symbol] == hist[symbol]); @@ -190,7 +190,7 @@ void ransAccessHistogramBenchmark(benchmark::State& st, Args&&... args) #endif bool isSame = true; - for (std::ptrdiff_t symbol = histogram.getOffset(); symbol != histogram.getOffset() + static_cast(histogram.size()); ++symbol) { + for (std::ptrdiff_t symbol = histogram.getOffset(); symbol != histogram.getOffset() + histogram.size(); ++symbol) { if (histogram[symbol] > 0) { LOG_IF(info, histogram[symbol] != hist[symbol]) << fmt::format("[{}]: {} != {}", symbol, hist[symbol], histogram[symbol]); isSame = isSame && (histogram[symbol] == hist[symbol]); diff --git a/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h b/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h index 177245ef7bec6..844e0c9695a32 100644 --- a/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h +++ b/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h @@ -184,7 +184,7 @@ inline bool DenseHistogram>::i ret = false; } } - if (max - min > static_cast(this->MaxSize)) { + if (max - min > this->MaxSize) { LOGP(warning, "DenseHistogram exceeds {} elements threshold", this->MaxSize); ret = false; } @@ -233,6 +233,8 @@ inline auto DenseHistogram>::a constexpr size_t nUnroll = 4 * ElemsPerQWord; auto iter = begin; + const source_type offset = this->getOffset(); + if (getRangeBits(min, max) <= 17) { container_type histogram{this->mContainer.size(), this->mContainer.getOffset()}; diff --git a/Utilities/rANS/include/rANS/internal/containers/ReverseSymbolLookupTable.h b/Utilities/rANS/include/rANS/internal/containers/ReverseSymbolLookupTable.h index 3a79619b2338d..506aaaf53fa40 100644 --- a/Utilities/rANS/include/rANS/internal/containers/ReverseSymbolLookupTable.h +++ b/Utilities/rANS/include/rANS/internal/containers/ReverseSymbolLookupTable.h @@ -71,8 +71,8 @@ class ReverseSymbolLookupTable return mLut[cumul]; }; - inline iterator_type begin() const noexcept { return mLut.data(); }; - inline iterator_type end() const noexcept { return mLut.data() + size(); }; + inline const iterator_type begin() const noexcept { return mLut.data(); }; + inline const iterator_type end() const noexcept { return mLut.data() + size(); }; container_type mLut{}; }; diff --git a/Utilities/rANS/include/rANS/internal/containers/Symbol.h b/Utilities/rANS/include/rANS/internal/containers/Symbol.h index 5269447e22344..0c00c46e1a627 100644 --- a/Utilities/rANS/include/rANS/internal/containers/Symbol.h +++ b/Utilities/rANS/include/rANS/internal/containers/Symbol.h @@ -37,8 +37,11 @@ class Symbol // TODO(milettri): fix once ROOT cling respects the standard http://wg21.link/p1286r2 constexpr Symbol() noexcept {}; // NOLINT - constexpr Symbol(value_type frequency, value_type cumulative, [[maybe_unused]] size_t symbolTablePrecision = 0) - : mSymbol{frequency, cumulative} {}; + constexpr Symbol(value_type frequency, value_type cumulative, size_t symbolTablePrecision = 0) + : mSymbol{frequency, cumulative} + { + (void)symbolTablePrecision; // silence compiler warnings + }; [[nodiscard]] inline constexpr value_type getFrequency() const noexcept { return mSymbol[0]; }; [[nodiscard]] inline constexpr value_type getCumulative() const noexcept { return mSymbol[1]; }; [[nodiscard]] inline constexpr const value_type* data() const noexcept { return mSymbol.data(); }; diff --git a/Utilities/rANS/include/rANS/internal/encode/Encoder.h b/Utilities/rANS/include/rANS/internal/encode/Encoder.h index fb6015b7aa021..ef097992ac9cd 100644 --- a/Utilities/rANS/include/rANS/internal/encode/Encoder.h +++ b/Utilities/rANS/include/rANS/internal/encode/Encoder.h @@ -143,11 +143,7 @@ decltype(auto) Encoder::process(source_IT EncoderSymbolMapper symbolMapper{this->mSymbolTable, literalsBegin}; typename coder_type::symbol_type encoderSymbols[2]{}; - // one past the end. Will not be dereferenced, thus safe. -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Warray-bounds" coder_type* codersREnd = advanceIter(coders.data(), -1); -#pragma GCC diagnostic pop coder_type* activeCoder = codersREnd + nPartialCoderIterations; // we are encoding backwards! diff --git a/Utilities/rANS/include/rANS/internal/encode/EncoderSymbolMapper.h b/Utilities/rANS/include/rANS/internal/encode/EncoderSymbolMapper.h index 8925dfb6b34cf..083dad90f81c6 100644 --- a/Utilities/rANS/include/rANS/internal/encode/EncoderSymbolMapper.h +++ b/Utilities/rANS/include/rANS/internal/encode/EncoderSymbolMapper.h @@ -254,6 +254,8 @@ class EncoderSymbolMapper frequencies; @@ -328,6 +330,8 @@ class EncoderSymbolMapper frequencies; diff --git a/Utilities/rANS/include/rANS/internal/encode/SingleStreamEncoderImpl.h b/Utilities/rANS/include/rANS/internal/encode/SingleStreamEncoderImpl.h index ff7d6535365e0..580df53fc64bd 100644 --- a/Utilities/rANS/include/rANS/internal/encode/SingleStreamEncoderImpl.h +++ b/Utilities/rANS/include/rANS/internal/encode/SingleStreamEncoderImpl.h @@ -145,6 +145,8 @@ class SingleStreamEncoderImpl : public SingleStreamEncoderImplBasegetFrequency() != 0); + const state_type old = this->mState; + const auto [newState, streamPosition] = this->renorm(this->mState, outputIter, symbol->getFrequency()); // coding function state_type quotient = static_cast((static_cast(newState) * symbol->getReciprocalFrequency()) >> 64); diff --git a/Utilities/rANS/include/rANS/internal/pack/DictionaryStreamReader.h b/Utilities/rANS/include/rANS/internal/pack/DictionaryStreamReader.h index 0109abe102fc3..f84eaebf25fb9 100644 --- a/Utilities/rANS/include/rANS/internal/pack/DictionaryStreamReader.h +++ b/Utilities/rANS/include/rANS/internal/pack/DictionaryStreamReader.h @@ -84,7 +84,7 @@ class DictionaryStreamParser template template -DictionaryStreamParser::DictionaryStreamParser(buffer_IT begin, buffer_IT end, source_type max) : mPos{end}, mEnd{begin}, mIndex(max) +DictionaryStreamParser::DictionaryStreamParser(buffer_IT begin, buffer_IT end, source_type max) : mEnd{begin}, mPos{end}, mIndex(max) { static_assert(std::is_pointer_v, "can only deserialize from raw pointers"); diff --git a/Utilities/rANS/include/rANS/internal/transform/algorithmImpl.h b/Utilities/rANS/include/rANS/internal/transform/algorithmImpl.h index 382f116d5ca04..84dff9609a574 100644 --- a/Utilities/rANS/include/rANS/internal/transform/algorithmImpl.h +++ b/Utilities/rANS/include/rANS/internal/transform/algorithmImpl.h @@ -161,7 +161,7 @@ inline void forEachIndexValue(container_T&& container, IT begin, IT end, F funct using container_type = removeCVRef_t; typename container_type::source_type index = container.getOffset() + std::distance(container.begin(), begin); - for (std::ptrdiff_t i = 0; i < std::distance(begin, end); ++i) { + for (size_t i = 0; i < std::distance(begin, end); ++i) { functor(index++, begin[i]); } } diff --git a/Utilities/rANS/include/rANS/internal/transform/renorm.h b/Utilities/rANS/include/rANS/internal/transform/renorm.h index 8d8ab238aaa91..5d55b3553ceca 100644 --- a/Utilities/rANS/include/rANS/internal/transform/renorm.h +++ b/Utilities/rANS/include/rANS/internal/transform/renorm.h @@ -74,6 +74,7 @@ decltype(auto) renorm(histogram_T histogram, Metrics(5), 5}, }; + const size_t fixedSizeOffset = std::numeric_limits::min(); + histogram_T histogram{}; histogram.addFrequencies(frequencies.begin(), frequencies.end(), 0); @@ -387,6 +389,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_addFrequenciesSignChange, histogram_T, histog const std::ptrdiff_t offset = utils::pow2(utils::toBits() - 1); if constexpr (std::is_same_v>) { + const std::ptrdiff_t largeOffset = utils::toBits() - 1; BOOST_CHECK_THROW(histogram.addFrequencies(frequencies2.begin(), frequencies2.end(), offset), HistogramError); BOOST_CHECK_THROW(histogram2.addFrequencies(gsl::make_span(frequencies2), offset), HistogramError); } else { diff --git a/Utilities/rANS/test/test_ransMetrics.cxx b/Utilities/rANS/test/test_ransMetrics.cxx index 4370194306f1d..42dcf7519f664 100644 --- a/Utilities/rANS/test/test_ransMetrics.cxx +++ b/Utilities/rANS/test/test_ransMetrics.cxx @@ -238,6 +238,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_singleElementMetrics, histogram_T, histogram_ std::vector frequencies{5}; histogram_T histogram{frequencies.begin(), frequencies.end(), 2}; const auto [min, max] = getMinMax(histogram); + const float eps = 1e-2; const size_t nUsedAlphabetSymbols = countNUsedAlphabetSymbols(histogram); const Metrics metrics{histogram}; diff --git a/Utilities/rANS/test/test_ransPack.cxx b/Utilities/rANS/test/test_ransPack.cxx index e6aaaffa79ebf..bc63ad04cdf96 100644 --- a/Utilities/rANS/test/test_ransPack.cxx +++ b/Utilities/rANS/test/test_ransPack.cxx @@ -56,6 +56,7 @@ using source_types = boost::mp11::mp_list BOOST_AUTO_TEST_CASE_TEMPLATE(test_computePackingBufferSize, buffer_T, buffer_types) { + size_t nElems{}; size_t packingWidth = utils::toBits() - 3; BOOST_CHECK_EQUAL(0, (computePackingBufferSize(0, packingWidth))); @@ -131,7 +132,7 @@ BOOST_AUTO_TEST_CASE(test_packUnpackStream) source_type min = *std::min_element(source.begin(), source.end()); - [[maybe_unused]] auto packingBufferEnd = pack(source.data(), source.size(), packingBuffer.data(), packingWidth, min); + auto packingBufferEnd = pack(source.data(), source.size(), packingBuffer.data(), packingWidth, min); std::vector unpackBuffer(source.size(), 0); unpack(packingBuffer.data(), source.size(), unpackBuffer.data(), packingWidth, min); diff --git a/Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx b/Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx index ea099fd2238f7..12f65a6c610b6 100644 --- a/Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx +++ b/Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx @@ -120,9 +120,7 @@ struct AosToSoaFixture { uint32_t counter = 0; for (size_t i = 0; i < nElems; ++i) { - const auto freq = counter++; - const auto cumul = counter++; - Symbol symbol{freq, cumul, 0}; + Symbol symbol{counter++, counter++, 0}; mFrequencies(i) = symbol.getFrequency(); mCumulative(i) = symbol.getCumulative(); @@ -230,10 +228,10 @@ struct SSERenormFixture { statesVec[0] = load(states[0]); statesVec[1] = load(states[1]); - [[maybe_unused]] stream_iterator newstreamOutIter = ransRenorm(statesVec, - frequenciesVec, - SymbolTablePrecisionBits, - streamOutBuffer.begin(), newStatesVec); + stream_iterator newstreamOutIter = ransRenorm(statesVec, + frequenciesVec, + SymbolTablePrecisionBits, + streamOutBuffer.begin(), newStatesVec); epi64_t newStates(0); store(newStatesVec[0], newStates[0]); diff --git a/Utilities/rANS/test/test_ransSparseVector.cxx b/Utilities/rANS/test/test_ransSparseVector.cxx index fc1a2980e3226..fab69aa5750ad 100644 --- a/Utilities/rANS/test/test_ransSparseVector.cxx +++ b/Utilities/rANS/test/test_ransSparseVector.cxx @@ -47,6 +47,8 @@ BOOST_AUTO_TEST_CASE(test_write) { sparseVector_type vec{}; + const size_t fixedSizeOffset = std::numeric_limits::min(); + std::vector samples{-5, -2, 1, 3, 5, 8, -5, 5, 1, 1, 1, 14, 8, 8, 8, 8, 8, 8, 8, 8, utils::pow2(18) + 1}; std::unordered_map results{{-5, 2}, {-2, 1}, {-1, 0}, {0, 0}, {1, 4}, {2, 0}, {3, 1}, {4, 0}, {5, 2}, {8, 9}, {14, 1}, {utils::pow2(18) + 1, 1}}; diff --git a/Utilities/rANS/test/test_ransSymbolTables.cxx b/Utilities/rANS/test/test_ransSymbolTables.cxx index bbadb8c8c46a0..5384607b2b0c4 100644 --- a/Utilities/rANS/test/test_ransSymbolTables.cxx +++ b/Utilities/rANS/test/test_ransSymbolTables.cxx @@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_symbolTable, histogram_T, histogram_t) BOOST_CHECK_EQUAL(symbolTable.getPrecision(), scaleBits); - for (source_type index = 0; index < static_cast(rescaledFrequencies.size()); ++index) { + for (source_type index = 0; index < rescaledFrequencies.size(); ++index) { auto symbol = symbolTable[index + 6]; BOOST_CHECK_EQUAL(symbol.getFrequency(), rescaledFrequencies[index]); BOOST_CHECK_EQUAL(symbol.getCumulative(), cumulativeFrequencies[index]); From a15d56b96d9afbff5b7afea4bef25334c3baee2c Mon Sep 17 00:00:00 2001 From: Ruben Shahoyan Date: Thu, 5 Oct 2023 00:51:46 +0200 Subject: [PATCH 211/324] Revert "[rANS] Enforce Consistent Histograms" This reverts commit d57a2647bff8fc62cf2675f38fbafa066e4f7ede. --- .../DetectorsCommonDataFormats/EncodedBlocks.h | 18 +----------------- .../rANS/internal/containers/DenseHistogram.h | 11 +---------- .../include/rANS/internal/transform/renorm.h | 2 +- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index 6afc171a79d7c..13cd7d2b122d5 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -339,10 +339,7 @@ class EncodedBlocks using dictionaryType = std::variant, rans::RenormedDenseHistogram>; #endif - void setHeader(const H& h) - { - mHeader = h; - } + void setHeader(const H& h) { mHeader = h; } const H& getHeader() const { return mHeader; } H& getHeader() { return mHeader; } std::shared_ptr cloneHeader() const { return std::shared_ptr(new H(mHeader)); } // for dictionary creation @@ -374,19 +371,6 @@ class EncodedBlocks assert(static_cast(std::numeric_limits::min()) <= static_cast(metadata.max)); assert(static_cast(std::numeric_limits::max()) >= static_cast(metadata.min)); - // check consistency of metadata and type - [&]() { - const int64_t sourceMin = std::numeric_limits::min(); - const int64_t sourceMax = std::numeric_limits::max(); - - const int64_t mdMin = metadata.min; - const int64_t mdMax = metadata.max; - - if ((mdMin < sourceMin) || (mdMax > sourceMax)) { - throw std::runtime_error(fmt::format("value range of dictionary and target datatype are incompatible: target type [{},{}] vs dictionary [{},{}]", sourceMin, sourceMax, mdMin, mdMax)); - } - }(); - if (ansVersion == ANSVersionCompat) { rans::DenseHistogram histogram{block.getDict(), block.getDict() + block.getNDict(), metadata.min}; return rans::compat::renorm(std::move(histogram), metadata.probabilityBits); diff --git a/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h b/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h index 844e0c9695a32..354ee96b84f48 100644 --- a/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h +++ b/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h @@ -586,16 +586,7 @@ auto DenseHistogram>::addFrequ addedHistogramView = trim(addedHistogramView); if constexpr (std::is_unsigned_v) { - LOG_IF(warning, addedHistogramView.getMin() < 0) << fmt::format("trying to add frequencies of a signed symbol type to a DenseHistogram of an unsiged type."); - } - if constexpr (std::is_signed_v) { - const std::ptrdiff_t sourceTypeMax = std::numeric_limits::max(); - const bool isMinOutOfRange = addedHistogramView.getMin() > sourceTypeMax; - const bool isMaxOutOfRange = addedHistogramView.getMax() > sourceTypeMax; - - if (isMaxOutOfRange || isMinOutOfRange) { - LOGP(warning, "trying to add frequencies of an unsigned symbol type to a DenseHistogram of a signed type"); - } + LOG_IF(warning, addedHistogramView.getMin() < 0) << fmt::format("trying to add frequencies for a signed symbol to a DenseHistogram of an unsiged type."); } const auto thisHistogramView = makeHistogramView(this->mContainer); diff --git a/Utilities/rANS/include/rANS/internal/transform/renorm.h b/Utilities/rANS/include/rANS/internal/transform/renorm.h index 5d55b3553ceca..5e3d7d551a665 100644 --- a/Utilities/rANS/include/rANS/internal/transform/renorm.h +++ b/Utilities/rANS/include/rANS/internal/transform/renorm.h @@ -143,7 +143,7 @@ decltype(auto) renorm(histogram_T histogram, Metrics Date: Thu, 5 Oct 2023 08:49:54 +0200 Subject: [PATCH 212/324] DPL: protect against multiple additions of 0xccdb queries (#12020) --- Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx | 4 +-- .../Core/include/Framework/DataSpecUtils.h | 3 ++ Framework/Core/src/DataSpecUtils.cxx | 16 ++++++++++ Framework/Core/src/WorkflowHelpers.cxx | 4 +-- .../Core/test/unittest_DataSpecUtils.cxx | 30 +++++++++++++++++++ 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx b/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx index bf20f0fe06039..32ba967ffd102 100644 --- a/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx +++ b/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx @@ -465,9 +465,9 @@ o2f::DataProcessorSpec o2::rawdd::getTFReaderSpec(o2::rawdd::TFReaderInp& rinp) } } } - spec.outputs.emplace_back(o2f::OutputSpec{{"stfDist"}, o2h::gDataOriginFLP, o2h::gDataDescriptionDISTSTF, 0}); + o2f::DataSpecUtils::updateOutputList(spec.outputs, o2f::OutputSpec{{"stfDist"}, o2h::gDataOriginFLP, o2h::gDataDescriptionDISTSTF, 0}); if (!rinp.sup0xccdb) { - spec.outputs.emplace_back(o2f::OutputSpec{{"stfDistCCDB"}, o2h::gDataOriginFLP, o2h::gDataDescriptionDISTSTF, 0xccdb}); + o2f::DataSpecUtils::updateOutputList(spec.outputs, o2f::OutputSpec{{"stfDistCCDB"}, o2h::gDataOriginFLP, o2h::gDataDescriptionDISTSTF, 0xccdb}); } if (!rinp.metricChannel.empty()) { spec.options.emplace_back(o2f::ConfigParamSpec{"channel-config", o2f::VariantType::String, rinp.metricChannel, {"Out-of-band channel config for TF throttling"}}); diff --git a/Framework/Core/include/Framework/DataSpecUtils.h b/Framework/Core/include/Framework/DataSpecUtils.h index 42cdc42841157..3dcdf6d790cd9 100644 --- a/Framework/Core/include/Framework/DataSpecUtils.h +++ b/Framework/Core/include/Framework/DataSpecUtils.h @@ -230,6 +230,9 @@ struct DataSpecUtils { /// Updates list of InputSpecs by merging metadata static void updateInputList(std::vector& list, InputSpec&& input); + + /// Updates list of OutputSpecs by merging metadata (or adding output). + static void updateOutputList(std::vector& list, OutputSpec&& input); }; } // namespace framework diff --git a/Framework/Core/src/DataSpecUtils.cxx b/Framework/Core/src/DataSpecUtils.cxx index 32d8a512672a3..7cc9b8d03b673 100644 --- a/Framework/Core/src/DataSpecUtils.cxx +++ b/Framework/Core/src/DataSpecUtils.cxx @@ -795,4 +795,20 @@ void DataSpecUtils::updateInputList(std::vector& list, InputSpec&& in } } +void DataSpecUtils::updateOutputList(std::vector& list, OutputSpec&& spec) +{ + auto locate = std::find(list.begin(), list.end(), spec); + if (locate != list.end()) { + // amend entry + auto& entryMetadata = locate->metadata; + entryMetadata.insert(entryMetadata.end(), spec.metadata.begin(), spec.metadata.end()); + std::sort(entryMetadata.begin(), entryMetadata.end(), [](ConfigParamSpec const& a, ConfigParamSpec const& b) { return a.name < b.name; }); + auto new_end = std::unique(entryMetadata.begin(), entryMetadata.end(), [](ConfigParamSpec const& a, ConfigParamSpec const& b) { return a.name == b.name; }); + entryMetadata.erase(new_end, entryMetadata.end()); + } else { + // add entry + list.emplace_back(std::move(spec)); + } +} + } // namespace o2::framework diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index ce56385f71dd4..cd9c3913de228 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -588,7 +588,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext } if (enumCandidate != -1) { auto& dp = workflow[enumCandidate]; - dp.outputs.push_back(OutputSpec{{"ccdb-diststf"}, dstf, Lifetime::Timeframe}); + DataSpecUtils::updateOutputList(dp.outputs, OutputSpec{{"ccdb-diststf"}, dstf, Lifetime::Timeframe}); ccdbBackend.inputs.push_back(InputSpec{"tfn", dstf, Lifetime::Timeframe}); } else if (timerCandidate != -1) { auto& dp = workflow[timerCandidate]; @@ -635,7 +635,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext } if (enumCandidate != -1) { auto& dp = workflow[enumCandidate]; - dp.outputs.push_back(OutputSpec{{"ccdb-diststf"}, dstf, Lifetime::Timeframe}); + DataSpecUtils::updateOutputList(dp.outputs, OutputSpec{{"ccdb-diststf"}, dstf, Lifetime::Timeframe}); ccdbBackend.inputs.push_back(InputSpec{"tfn", dstf, Lifetime::Timeframe}); } else if (timerCandidate != -1) { auto& dp = workflow[timerCandidate]; diff --git a/Framework/Core/test/unittest_DataSpecUtils.cxx b/Framework/Core/test/unittest_DataSpecUtils.cxx index 4ae6f3b0ff832..e6b2f4a22c018 100644 --- a/Framework/Core/test/unittest_DataSpecUtils.cxx +++ b/Framework/Core/test/unittest_DataSpecUtils.cxx @@ -460,3 +460,33 @@ TEST_CASE("optionalConcreteDataMatcherFrom") REQUIRE(DataSpecUtils::asOptionalConcreteDataMatcher(ConcreteDataMatcher{"ITS", "RAWDATA", 0}) == ConcreteDataMatcher{"ITS", "RAWDATA", 0}); REQUIRE(DataSpecUtils::asOptionalConcreteDataMatcher(ConcreteDataTypeMatcher{"ITS", "RAWDATA"}) == std::nullopt); } + +// Testcase for DataSpecUtils::updateOutputList +TEST_CASE("UpdateOutputList") +{ + // Empty vector of output specs should simply add the new spec + std::vector outputSpecs; + DataSpecUtils::updateOutputList(outputSpecs, {"TST", "DATA1", 0}); + CHECK(outputSpecs.size() == 1); + + // Adding the same spec again should not change the size + DataSpecUtils::updateOutputList(outputSpecs, {"TST", "DATA1", 0}); + CHECK(outputSpecs.size() == 1); + + // Adding a different spec should increase the size + DataSpecUtils::updateOutputList(outputSpecs, {"TST", "DATA2", 0}); + CHECK(outputSpecs.size() == 2); + + // Adding again the same spec again should not change the size + DataSpecUtils::updateOutputList(outputSpecs, {"TST", "DATA1", 0}); + CHECK(outputSpecs.size() == 2); + // Check with something real.. + ConcreteDataMatcher dstf{"FLP", "DISTSUBTIMEFRAME", 0xccdb}; + DataSpecUtils::updateOutputList(outputSpecs, OutputSpec{{"ccdb-diststf"}, dstf, Lifetime::Timeframe}); + CHECK(outputSpecs.size() == 3); + DataSpecUtils::updateOutputList(outputSpecs, OutputSpec{{"ccdb-diststf"}, dstf, Lifetime::Timeframe}); + CHECK(outputSpecs.size() == 3); + // Label does not matter + DataSpecUtils::updateOutputList(outputSpecs, OutputSpec{{"ccdb2-diststf"}, dstf, Lifetime::Timeframe}); + CHECK(outputSpecs.size() == 3); +} From 0f08c547bef6b0ba4cf0a6c7095ae1377eda48ed Mon Sep 17 00:00:00 2001 From: Francesco Mazzaschi <43742195+fmazzasc@users.noreply.github.com> Date: Thu, 5 Oct 2023 09:47:41 +0200 Subject: [PATCH 213/324] [SVertexer] Sort tracks by their decayRef when nthreads>1 (#12003) * Sort tracks by their decayRef when nthreads>1 * Optimize loops --- Detectors/Vertexing/src/SVertexer.cxx | 46 +++++++++++++++++++++------ 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/Detectors/Vertexing/src/SVertexer.cxx b/Detectors/Vertexing/src/SVertexer.cxx index b8978a2310a44..505f9baa2c2dc 100644 --- a/Detectors/Vertexing/src/SVertexer.cxx +++ b/Detectors/Vertexing/src/SVertexer.cxx @@ -170,14 +170,16 @@ void SVertexer::process(const o2::globaltracking::RecoContainer& recoData, o2::f for (int ith = 0; ith < mNThreads; ith++) { mNStrangeTracks += mStrTracker->getNTracks(ith); } - auto& strTracksOut = pc.outputs().make>(o2f::Output{"GLO", "STRANGETRACKS", 0, o2f::Lifetime::Timeframe}); - auto& strClustOut = pc.outputs().make>(o2f::Output{"GLO", "CLUSUPDATES", 0, o2f::Lifetime::Timeframe}); - o2::pmr::vector mcLabsOut; - strTracksOut.reserve(mNStrangeTracks); - strClustOut.reserve(mNStrangeTracks); + + std::vector strTracksTmp; + std::vector strClusTmp; + std::vector mcLabTmp; + strTracksTmp.reserve(mNStrangeTracks); + strClusTmp.reserve(mNStrangeTracks); if (mStrTracker->getMCTruthOn()) { - mcLabsOut.reserve(mNStrangeTracks); + mcLabTmp.reserve(mNStrangeTracks); } + for (int ith = 0; ith < mNThreads; ith++) { // merge results of all threads auto& strTracks = mStrTracker->getStrangeTrackVec(ith); auto& strClust = mStrTracker->getClusAttachments(ith); @@ -193,13 +195,39 @@ void SVertexer::process(const o2::globaltracking::RecoContainer& recoData, o2::f } else { LOGP(fatal, "Unknown strange track decay reference type {} for index {}", int(t.mPartType), t.mDecayRef); } - strTracksOut.push_back(t); - strClustOut.push_back(strClust[i]); + + strTracksTmp.push_back(t); + strClusTmp.push_back(strClust[i]); if (mStrTracker->getMCTruthOn()) { - mcLabsOut.push_back(stcTrMCLab[i]); + mcLabTmp.push_back(stcTrMCLab[i]); } } } + + auto& strTracksOut = pc.outputs().make>(o2f::Output{"GLO", "STRANGETRACKS", 0, o2f::Lifetime::Timeframe}); + auto& strClustOut = pc.outputs().make>(o2f::Output{"GLO", "CLUSUPDATES", 0, o2f::Lifetime::Timeframe}); + o2::pmr::vector mcLabsOut; + strTracksOut.resize(mNStrangeTracks); + strClustOut.resize(mNStrangeTracks); + if (mStrTracker->getMCTruthOn()) { + mcLabsOut.resize(mNStrangeTracks); + } + + std::vector sortIdx(strTracksTmp.size()); + std::iota(sortIdx.begin(), sortIdx.end(), 0); + // if mNTreads > 1 we need to sort tracks, clus and MCLabs by their mDecayRef + if (mNThreads > 1 && mNStrangeTracks > 1) { + std::sort(sortIdx.begin(), sortIdx.end(), [&strTracksTmp](int i1, int i2) { return strTracksTmp[i1].mDecayRef < strTracksTmp[i2].mDecayRef; }); + } + + for (int i = 0; i < (int)sortIdx.size(); i++) { + strTracksOut[i] = strTracksTmp[sortIdx[i]]; + strClustOut[i] = strClusTmp[sortIdx[i]]; + if (mStrTracker->getMCTruthOn()) { + mcLabsOut[i] = mcLabTmp[sortIdx[i]]; + } + } + if (mStrTracker->getMCTruthOn()) { auto& strTrMCLableOut = pc.outputs().make>(o2f::Output{"GLO", "STRANGETRACKS_MC", 0, o2f::Lifetime::Timeframe}); strTrMCLableOut.swap(mcLabsOut); From 6a220b4446f8120e4ad975e2b3d7a7da82be4593 Mon Sep 17 00:00:00 2001 From: noferini Date: Wed, 4 Oct 2023 16:46:56 +0200 Subject: [PATCH 214/324] fine tuning TOF calib with FT0 --- Detectors/GlobalTracking/src/MatchTOF.cxx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Detectors/GlobalTracking/src/MatchTOF.cxx b/Detectors/GlobalTracking/src/MatchTOF.cxx index 2fed841134117..3283f14b0bdde 100644 --- a/Detectors/GlobalTracking/src/MatchTOF.cxx +++ b/Detectors/GlobalTracking/src/MatchTOF.cxx @@ -1203,6 +1203,7 @@ int MatchTOF::findFITIndex(int bc, const gsl::span& FI int index = -1; int distMax = 0; + bool bestQuality = false; // prioritize FT0 BC with good quality (FT0-AC + vertex) to remove umbiguity in Pb-Pb (not a strict cut because inefficient in pp) const int distThr = 8; for (unsigned int i = 0; i < FITRecPoints.size(); i++) { @@ -1210,13 +1211,19 @@ int MatchTOF::findFITIndex(int bc, const gsl::span& FI if (mHasFillScheme && !mFillScheme[ir.bc]) { continue; } + bool quality = (fabs(FITRecPoints[i].getCollisionTime(0)) < 1000 && fabs(FITRecPoints[i].getVertex()) < 1000); + if (bestQuality && !quality) { // if current has no good quality and the one previoulsy selected has -> discard the current one + continue; + } int bct0 = (ir.orbit - firstOrbit) * o2::constants::lhc::LHCMaxBunches + ir.bc; int dist = bc - bct0; - if (dist < 0 || dist > distThr || dist < distMax) { + bool worseDistance = dist < 0 || dist > distThr || dist < distMax; + if (worseDistance && (!quality || bestQuality)) { // discard if BC is later than the one selected, but is has a better quality continue; } + bestQuality = quality; distMax = dist; index = i; } From 9c736a3411bb9b3950ee689c1addb3a6f8805e1e Mon Sep 17 00:00:00 2001 From: Chiara Zampolli Date: Wed, 27 Sep 2023 18:09:59 +0200 Subject: [PATCH 215/324] Adding plots to ITSTPC matching QC --- .../include/GlobalTracking/MatchITSTPCQC.h | 173 +++-- .../GlobalTracking/src/MatchITSTPCQC.cxx | 726 +++++++++++++----- 2 files changed, 629 insertions(+), 270 deletions(-) diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchITSTPCQC.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchITSTPCQC.h index 39acc8f93368f..08caa8cc09fe4 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchITSTPCQC.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchITSTPCQC.h @@ -28,6 +28,7 @@ #include "Steer/MCKinematicsReader.h" #include #include +#include namespace o2 { @@ -46,6 +47,10 @@ struct LblInfo { class MatchITSTPCQC { public: + enum matchType : int { TPC = 0, + ITS, + SIZE }; + MatchITSTPCQC() = default; ~MatchITSTPCQC(); @@ -56,37 +61,41 @@ class MatchITSTPCQC void finalize(); void reset(); - TH1D* getHistoPt() const { return mPt; } - TH1D* getHistoPtTPC() const { return mPtTPC; } - TEfficiency* getFractionITSTPCmatch() const { return mFractionITSTPCmatch; } + TH1D* getHistoPtNum(matchType m) const { return mPtNum[m]; } + TH1D* getHistoPtDen(matchType m) const { return mPtDen[m]; } + TEfficiency* getFractionITSTPCmatch(matchType m) const { return mFractionITSTPCmatch[m]; } + + TH1D* getHistoPtNumNoEta0(matchType m) const { return mPtNum_noEta0[m]; } + TH1D* getHistoPtDenNoEta0(matchType m) const { return mPtDen_noEta0[m]; } + TEfficiency* getFractionITSTPCmatchNoEta0(matchType m) const { return mFractionITSTPCmatch_noEta0[m]; } - TH1F* getHistoPhi() const { return mPhi; } - TH1F* getHistoPhiTPC() const { return mPhiTPC; } - TEfficiency* getFractionITSTPCmatchPhi() const { return mFractionITSTPCmatchPhi; } + TH1F* getHistoPhiNum(matchType m) const { return mPhiNum[m]; } + TH1F* getHistoPhiDen(matchType m) const { return mPhiDen[m]; } + TEfficiency* getFractionITSTPCmatchPhi(matchType m) const { return mFractionITSTPCmatchPhi[m]; } - TH2F* getHistoPhiVsPt() const { return mPhiVsPt; } - TH2F* getHistoPhiVsPtTPC() const { return mPhiVsPtTPC; } - TEfficiency* getFractionITSTPCmatchPhiVsPt() const { return mFractionITSTPCmatchPhiVsPt; } + TH2F* getHistoPhiVsPtNum(matchType m) const { return mPhiVsPtNum[m]; } + TH2F* getHistoPhiVsPtDen(matchType m) const { return mPhiVsPtDen[m]; } + TEfficiency* getFractionITSTPCmatchPhiVsPt(matchType m) const { return mFractionITSTPCmatchPhiVsPt[m]; } - TH1F* getHistoEta() const { return mEta; } - TH1F* getHistoEtaTPC() const { return mEtaTPC; } - TEfficiency* getFractionITSTPCmatchEta() const { return mFractionITSTPCmatchEta; } + TH1F* getHistoEtaNum(matchType m) const { return mEtaNum[m]; } + TH1F* getHistoEtaDen(matchType m) const { return mEtaDen[m]; } + TEfficiency* getFractionITSTPCmatchEta(matchType m) const { return mFractionITSTPCmatchEta[m]; } - TH2F* getHistoEtaVsPt() const { return mEtaVsPt; } - TH2F* getHistoEtaVsPtTPC() const { return mEtaVsPtTPC; } - TEfficiency* getFractionITSTPCmatchEtaVsPt() const { return mFractionITSTPCmatchEtaVsPt; } + TH2F* getHistoEtaVsPtNum(matchType m) const { return mEtaVsPtNum[m]; } + TH2F* getHistoEtaVsPtDen(matchType m) const { return mEtaVsPtDen[m]; } + TEfficiency* getFractionITSTPCmatchEtaVsPt(matchType m) const { return mFractionITSTPCmatchEtaVsPt[m]; } - TH1F* getHistoPtPhysPrim() const { return mPtPhysPrim; } - TH1F* getHistoPtTPCPhysPrim() const { return mPtTPCPhysPrim; } - TEfficiency* getFractionITSTPCmatchPhysPrim() const { return mFractionITSTPCmatchPhysPrim; } + TH1F* getHistoPtPhysPrimNum(matchType m) const { return mPtPhysPrimNum[m]; } + TH1F* getHistoPtPhysPrimDen(matchType m) const { return mPtPhysPrimDen[m]; } + TEfficiency* getFractionITSTPCmatchPhysPrim(matchType m) const { return mFractionITSTPCmatchPhysPrim[m]; } - TH1F* getHistoPhiPhysPrim() const { return mPhiPhysPrim; } - TH1F* getHistoPhiTPCPhysPrim() const { return mPhiTPCPhysPrim; } - TEfficiency* getFractionITSTPCmatchPhiPhysPrim() const { return mFractionITSTPCmatchPhiPhysPrim; } + TH1F* getHistoPhiPhysPrimNum(matchType m) const { return mPhiPhysPrimNum[m]; } + TH1F* getHistoPhiPhysPrimDen(matchType m) const { return mPhiPhysPrimDen[m]; } + TEfficiency* getFractionITSTPCmatchPhiPhysPrim(matchType m) const { return mFractionITSTPCmatchPhiPhysPrim[m]; } - TH1F* getHistoEtaPhysPrim() const { return mEtaPhysPrim; } - TH1F* getHistoEtaTPCPhysPrim() const { return mEtaTPCPhysPrim; } - TEfficiency* getFractionITSTPCmatchEtaPhysPrim() const { return mFractionITSTPCmatchEtaPhysPrim; } + TH1F* getHistoEtaPhysPrimNum(matchType m) const { return mEtaPhysPrimNum[m]; } + TH1F* getHistoEtaPhysPrimDen(matchType m) const { return mEtaPhysPrimDen[m]; } + TEfficiency* getFractionITSTPCmatchEtaPhysPrim(matchType m) const { return mFractionITSTPCmatchEtaPhysPrim[m]; } TH2F* getHistoResidualPt() const { return mResidualPt; } TH2F* getHistoResidualPhi() const { return mResidualPhi; } @@ -95,7 +104,18 @@ class MatchITSTPCQC TH1F* getHistoChi2Matching() const { return mChi2Matching; } TH1F* getHistoChi2Refit() const { return mChi2Refit; } TH2F* getHistoTimeResVsPt() const { return mTimeResVsPt; } + TH1F* getHistoDCAr() const { return mDCAr; } + + TH1D* getHisto1OverPtNum(matchType m) const { return m1OverPtNum[m]; } + TH1D* getHisto1OverPtDen(matchType m) const { return m1OverPtDen[m]; } + TEfficiency* getFractionITSTPCmatch1OverPt(matchType m) const { return mFractionITSTPCmatch1OverPt[m]; } + + TH1D* getHisto1OverPtPhysPrimNum(matchType m) const { return m1OverPtPhysPrimNum[m]; } + TH1D* getHisto1OverPtPhysPrimDen(matchType m) const { return m1OverPtPhysPrimDen[m]; } + TEfficiency* getFractionITSTPCmatchPhysPrim1OverPt(matchType m) const { return mFractionITSTPCmatchPhysPrim1OverPt[m]; } + void getHistos(TObjArray& objar); + void setSources(GID::mask_t src) { mSrc = src; } void setUseMC(bool b) { mUseMC = b; } bool getUseMC() const { return mUseMC; } @@ -115,52 +135,82 @@ class MatchITSTPCQC void setMinDCAtoBeamPipeDistanceCut(float v) { mDCACut = v; } void setMinDCAtoBeamPipeYCut(float v) { mDCACutY = v; } + // to remove after merging QC PR + TH1D* getHistoPt() const { return nullptr; } // old + TH1D* getHistoPtTPC() const { return nullptr; } // old + TEfficiency* getFractionITSTPCmatch() const { return nullptr; } // old + TH1F* getHistoPhi() const { return nullptr; } // old + TH1F* getHistoPhiTPC() const { return nullptr; } // old + TEfficiency* getFractionITSTPCmatchPhi() const { return nullptr; } // old + TH2F* getHistoPhiVsPt() const { return nullptr; } // old + TEfficiency* getFractionITSTPCmatchPhiVsPt() const { return nullptr; } // old + TH1F* getHistoEta() const { return nullptr; } // old + TH1F* getHistoEtaTPC() const { return nullptr; } // old + TEfficiency* getFractionITSTPCmatchEta() const { return nullptr; } // old + TH2F* getHistoEtaVsPt() const { return nullptr; } // old + TH2F* getHistoEtaVsPtTPC() const { return nullptr; } // old + TEfficiency* getFractionITSTPCmatchEtaVsPt() const { return nullptr; } // old + TH1F* getHistoPtPhysPrim() const { return nullptr; } // old + TH1F* getHistoPtTPCPhysPrim() const { return nullptr; } // old + TEfficiency* getFractionITSTPCmatchPhysPrim() const { return nullptr; } // old + TH1F* getHistoPhiPhysPrim() const { return nullptr; } // old + TH1F* getHistoPhiTPCPhysPrim() const { return nullptr; } // old + TEfficiency* getFractionITSTPCmatchPhiPhysPrim() const { return nullptr; } // old + TH1F* getHistoEtaPhysPrim() const { return nullptr; } // old + TH1F* getHistoEtaTPCPhysPrim() const { return nullptr; } // old + TEfficiency* getFractionITSTPCmatchEtaPhysPrim() const { return nullptr; } // old + private: std::shared_ptr mDataRequest; o2::globaltracking::RecoContainer mRecoCont; - GID::mask_t mSrc = GID::getSourcesMask("TPC,ITS-TPC"); - GID::mask_t mAllowedSources = GID::getSourcesMask("TPC,ITS-TPC"); + GID::mask_t mSrc = GID::getSourcesMask("ITS,TPC,ITS-TPC"); + GID::mask_t mAllowedSources = GID::getSourcesMask("ITS,TPC,ITS-TPC"); // TPC gsl::span mTPCTracks; + // ITS + gsl::span mITSTracks; // ITS-TPC gsl::span mITSTPCTracks; bool mUseMC = false; float mBz = 0; ///< nominal Bz - std::unordered_map mMapLabels; // map with labels that have been found for the matched ITSTPC tracks; key is the label, - // value is the LbLinfo with the id of the track with the highest pT found with that label so far, - // and the flag to say if it is a physical primary or not - std::unordered_map mMapTPCLabels; // map with labels that have been found for the unmatched TPC tracks; key is the label, - // value is the LblInfo with the id of the track with the highest number of TPC clusters found - // with that label so far, and the flag to say if it is a physical primary or not + std::array, matchType::SIZE> mMapLabels; // map with labels that have been found for the matched ITSTPC tracks; key is the label, + // value is the LbLinfo with the id of the track with the highest pT found with that label so far, + // and the flag to say if it is a physical primary or not + std::array, matchType::SIZE> mMapRefLabels; // map with labels that have been found for the unmatched TPC tracks; key is the label, + // value is the LblInfo with the id of the track with the highest number of TPC clusters found + // with that label so far, and the flag to say if it is a physical primary or not o2::steer::MCKinematicsReader mcReader; // reader of MC information // Pt - TH1D* mPt = nullptr; - TH1D* mPtTPC = nullptr; - TEfficiency* mFractionITSTPCmatch = nullptr; - TH1F* mPtPhysPrim = nullptr; - TH1F* mPtTPCPhysPrim = nullptr; - TEfficiency* mFractionITSTPCmatchPhysPrim = nullptr; + TH1D* mPtNum[matchType::SIZE] = {}; + TH1D* mPtDen[matchType::SIZE] = {}; + TEfficiency* mFractionITSTPCmatch[matchType::SIZE] = {}; + TH1D* mPtNum_noEta0[matchType::SIZE] = {}; + TH1D* mPtDen_noEta0[matchType::SIZE] = {}; + TEfficiency* mFractionITSTPCmatch_noEta0[matchType::SIZE] = {}; + TH1F* mPtPhysPrimNum[matchType::SIZE] = {}; + TH1F* mPtPhysPrimDen[matchType::SIZE] = {}; + TEfficiency* mFractionITSTPCmatchPhysPrim[matchType::SIZE] = {}; // Phi - TH1F* mPhi = nullptr; - TH1F* mPhiTPC = nullptr; - TEfficiency* mFractionITSTPCmatchPhi = nullptr; - TH1F* mPhiPhysPrim = nullptr; - TH1F* mPhiTPCPhysPrim = nullptr; - TEfficiency* mFractionITSTPCmatchPhiPhysPrim = nullptr; - TH2F* mPhiVsPt = nullptr; - TH2F* mPhiVsPtTPC = nullptr; - TEfficiency* mFractionITSTPCmatchPhiVsPt = nullptr; + TH1F* mPhiNum[matchType::SIZE] = {}; + TH1F* mPhiDen[matchType::SIZE] = {}; + TEfficiency* mFractionITSTPCmatchPhi[matchType::SIZE] = {}; + TH1F* mPhiPhysPrimNum[matchType::SIZE] = {}; + TH1F* mPhiPhysPrimDen[matchType::SIZE] = {}; + TEfficiency* mFractionITSTPCmatchPhiPhysPrim[matchType::SIZE] = {}; + TH2F* mPhiVsPtNum[matchType::SIZE] = {}; + TH2F* mPhiVsPtDen[matchType::SIZE] = {}; + TEfficiency* mFractionITSTPCmatchPhiVsPt[matchType::SIZE] = {}; // Eta - TH1F* mEta = nullptr; - TH1F* mEtaTPC = nullptr; - TEfficiency* mFractionITSTPCmatchEta = nullptr; - TH1F* mEtaPhysPrim = nullptr; - TH1F* mEtaTPCPhysPrim = nullptr; - TEfficiency* mFractionITSTPCmatchEtaPhysPrim = nullptr; - TH2F* mEtaVsPt = nullptr; - TH2F* mEtaVsPtTPC = nullptr; - TEfficiency* mFractionITSTPCmatchEtaVsPt = nullptr; + TH1F* mEtaNum[matchType::SIZE] = {}; + TH1F* mEtaDen[matchType::SIZE] = {}; + TEfficiency* mFractionITSTPCmatchEta[matchType::SIZE] = {}; + TH1F* mEtaPhysPrimNum[matchType::SIZE] = {}; + TH1F* mEtaPhysPrimDen[matchType::SIZE] = {}; + TEfficiency* mFractionITSTPCmatchEtaPhysPrim[matchType::SIZE] = {}; + TH2F* mEtaVsPtNum[matchType::SIZE] = {}; + TH2F* mEtaVsPtDen[matchType::SIZE] = {}; + TEfficiency* mFractionITSTPCmatchEtaVsPt[matchType::SIZE] = {}; // Residuals TH2F* mResidualPt = nullptr; TH2F* mResidualPhi = nullptr; @@ -169,11 +219,20 @@ class MatchITSTPCQC TH1F* mChi2Matching = nullptr; TH1F* mChi2Refit = nullptr; TH2F* mTimeResVsPt = nullptr; + TH1F* mDCAr = nullptr; + // 1/Pt + TH1D* m1OverPtNum[matchType::SIZE] = {}; + TH1D* m1OverPtDen[matchType::SIZE] = {}; + TEfficiency* mFractionITSTPCmatch1OverPt[matchType::SIZE] = {}; + TH1D* m1OverPtPhysPrimNum[matchType::SIZE] = {}; + TH1D* m1OverPtPhysPrimDen[matchType::SIZE] = {}; + TEfficiency* mFractionITSTPCmatchPhysPrim1OverPt[matchType::SIZE] = {}; void setEfficiency(TEfficiency* eff, TH1* hnum, TH1* hden, bool is2D = false); int mNTPCSelectedTracks = 0; - int mNITSTPCSelectedTracks = 0; + int mNITSSelectedTracks = 0; + int mNITSTPCSelectedTracks[matchType::SIZE] = {0, 0}; // cut values float mPtCut = 0.1f; diff --git a/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx b/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx index 2b54cab4c32ac..ff0cfae2df5e8 100644 --- a/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx +++ b/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx @@ -36,33 +36,46 @@ MatchITSTPCQC::~MatchITSTPCQC() void MatchITSTPCQC::deleteHistograms() { - // Pt - delete mPt; - delete mPtTPC; - delete mFractionITSTPCmatch; - delete mPtPhysPrim; - delete mPtTPCPhysPrim; - delete mFractionITSTPCmatchPhysPrim; - // Phi - delete mPhi; - delete mPhiTPC; - delete mFractionITSTPCmatchPhi; - delete mPhiPhysPrim; - delete mPhiTPCPhysPrim; - delete mFractionITSTPCmatchPhiPhysPrim; - delete mPhiVsPt; - delete mPhiVsPtTPC; - delete mFractionITSTPCmatchPhiVsPt; - // Eta - delete mEta; - delete mEtaTPC; - delete mFractionITSTPCmatchEta; - delete mEtaPhysPrim; - delete mEtaTPCPhysPrim; - delete mFractionITSTPCmatchEtaPhysPrim; - delete mEtaVsPt; - delete mEtaVsPtTPC; - delete mFractionITSTPCmatchEtaVsPt; + for (int i = 0; i < matchType::SIZE; ++i) { + // Pt + delete mPtNum[i]; + delete mPtDen[i]; + delete mFractionITSTPCmatch[i]; + delete mPtNum_noEta0[i]; + delete mPtDen_noEta0[i]; + delete mFractionITSTPCmatch_noEta0[i]; + delete mPtPhysPrimNum[i]; + delete mPtPhysPrimDen[i]; + delete mFractionITSTPCmatchPhysPrim[i]; + // Phi + delete mPhiNum[i]; + delete mPhiDen[i]; + delete mFractionITSTPCmatchPhi[i]; + delete mPhiPhysPrimNum[i]; + delete mPhiPhysPrimDen[i]; + delete mFractionITSTPCmatchPhiPhysPrim[i]; + delete mPhiVsPtNum[i]; + delete mPhiVsPtDen[i]; + delete mFractionITSTPCmatchPhiVsPt[i]; + // Eta + delete mEtaNum[i]; + delete mEtaDen[i]; + delete mFractionITSTPCmatchEta[i]; + delete mEtaPhysPrimNum[i]; + delete mEtaPhysPrimDen[i]; + delete mFractionITSTPCmatchEtaPhysPrim[i]; + delete mEtaVsPtNum[i]; + delete mEtaVsPtDen[i]; + delete mFractionITSTPCmatchEtaVsPt[i]; + // 1/Pt + delete m1OverPtNum[i]; + delete m1OverPtDen[i]; + delete mFractionITSTPCmatch1OverPt[i]; + delete m1OverPtPhysPrimNum[i]; + delete m1OverPtPhysPrimDen[i]; + delete mFractionITSTPCmatchPhysPrim1OverPt[i]; + } + // Residuals delete mResidualPt; delete mResidualPhi; @@ -71,31 +84,41 @@ void MatchITSTPCQC::deleteHistograms() delete mChi2Matching; delete mChi2Refit; delete mTimeResVsPt; + delete mDCAr; } //__________________________________________________________ void MatchITSTPCQC::reset() { - // Pt - mPt->Reset(); - mPtTPC->Reset(); - mPtPhysPrim->Reset(); - mPtTPCPhysPrim->Reset(); - // Phi - mPhi->Reset(); - mPhiTPC->Reset(); - mPhiPhysPrim->Reset(); - mPhiTPCPhysPrim->Reset(); - mPhiVsPt->Reset(); - mPhiVsPtTPC->Reset(); - // Eta - mEta->Reset(); - mEtaTPC->Reset(); - mEtaPhysPrim->Reset(); - mEtaTPCPhysPrim->Reset(); - mEtaVsPt->Reset(); - mEtaVsPtTPC->Reset(); + for (int i = 0; i < matchType::SIZE; ++i) { + // Pt + mPtNum[i]->Reset(); + mPtDen[i]->Reset(); + mPtNum_noEta0[i]->Reset(); + mPtDen_noEta0[i]->Reset(); + mPtPhysPrimNum[i]->Reset(); + mPtPhysPrimDen[i]->Reset(); + // Phi + mPhiNum[i]->Reset(); + mPhiDen[i]->Reset(); + mPhiPhysPrimNum[i]->Reset(); + mPhiPhysPrimDen[i]->Reset(); + mPhiVsPtNum[i]->Reset(); + mPhiVsPtDen[i]->Reset(); + // Eta + mEtaNum[i]->Reset(); + mEtaDen[i]->Reset(); + mEtaPhysPrimNum[i]->Reset(); + mEtaPhysPrimDen[i]->Reset(); + mEtaVsPtNum[i]->Reset(); + mEtaVsPtDen[i]->Reset(); + // 1/Pt + m1OverPtNum[i]->Reset(); + m1OverPtDen[i]->Reset(); + m1OverPtPhysPrimNum[i]->Reset(); + m1OverPtPhysPrimDen[i]->Reset(); + } // Residuals mResidualPt->Reset(); mResidualPhi->Reset(); @@ -104,43 +127,57 @@ void MatchITSTPCQC::reset() mChi2Matching->Reset(); mChi2Refit->Reset(); mTimeResVsPt->Reset(); + mDCAr->Reset(); } //__________________________________________________________ bool MatchITSTPCQC::init() { - // Pt - mPtTPC = new TH1D("mPtTPC", "Pt distribution of TPC tracks; Pt [GeV/c]; dNdPt", 100, 0.f, 20.f); - mFractionITSTPCmatch = new TEfficiency("mFractionITSTPCmatch", "Fraction of ITSTPC matched tracks vs Pt; Pt [GeV/c]; Eff", 100, 0.f, 20.f); - mPt = new TH1D("mPt", "Pt distribution of matched tracks; Pt [GeV/c]; dNdPt", 100, 0.f, 20.f); - // Phi - mPhiTPC = new TH1F("mPhiTPC", "Phi distribution of TPC tracks; Phi [rad]; dNdPhi", 100, 0.f, 2 * TMath::Pi()); - mFractionITSTPCmatchPhi = new TEfficiency("mFractionITSTPCmatchPhi", "Fraction of ITSTPC matched tracks vs Phi; Phi [rad]; Eff", 100, 0.f, 2 * TMath::Pi()); - mPhi = new TH1F("mPhi", "Phi distribution of matched tracks; Phi [rad]; dNdPhi", 100, 0.f, 2 * TMath::Pi()); - mPhiVsPt = new TH2F("mPhiVsPt", "Phi distribution of matched tracks vs Pt; #it{p}_{T} [GeV#it{c}]; Phi [rad]; dNdPhi", 100, 0.f, 20.f, 100, 0.f, 2 * TMath::Pi()); - mPhiVsPtTPC = new TH2F("mPhiVsPtTPC", "Phi distribution of TPC tracks vs Pt; #it{p}_{T} [GeV#it{c}]; Phi [rad]; dNdPhi", 100, 0.f, 20.f, 100, 0.f, 2 * TMath::Pi()); - mFractionITSTPCmatchPhiVsPt = new TEfficiency("mFractionITSTPCmatchPhiVsPt", "Fraction of ITSTPC matched tracks vs Phi; #it{p}_{T} [GeV#it{c}]; Phi [rad]; Eff", 100, 0.f, 20.f, 100, 0.f, 2 * TMath::Pi()); - // Eta - mEta = new TH1F("mEta", "Eta distribution of matched tracks; Eta; dNdEta", 100, -2.f, 2.f); - mEtaTPC = new TH1F("mEtaTPC", "Eta distribution of TPC tracks; Eta; dNdEta", 100, -2.f, 2.f); - mFractionITSTPCmatchEta = new TEfficiency("mFractionITSTPCmatchEta", "Fraction of ITSTPC matched tracks vs Eta; Eta; Eff", 100, -2.f, 2.f); - mEtaVsPt = new TH2F("mEtaVsPt", "Eta distribution of matched tracks vs Pt; #it{p}_{T} [GeV#it{c}]; Eta; dNdEta", 100, 0.f, 20.f, 100, -2.f, 2.f); - mEtaVsPtTPC = new TH2F("mEtaVsPtTPC", "Eta distribution of TPC tracks vs Pt; #it{p}_{T} [GeV#it{c}]; Eta ; dNdEta", 100, 0.f, 20.f, 100, -2.f, 2.f); - mFractionITSTPCmatchEtaVsPt = new TEfficiency("mFractionITSTPCmatchEtaVsPt", "Fraction of ITSTPC matched tracks vs Eta; #it{p}_{T} [GeV#it{c}]; Eta; Eff", 100, 0.f, 20.f, 100, -2.f, 2.f); - // These will be empty in case of no MC info... - mPhiTPCPhysPrim = new TH1F("mPhiTPCPhysPrim", "Phi distribution of TPC tracks (physical primary); Phi [rad]; dNdPhi", 100, 0.f, 2 * TMath::Pi()); - mFractionITSTPCmatchPhiPhysPrim = new TEfficiency("mFractionITSTPCmatchPhiPhysPrim", "Fraction of ITSTPC matched tracks vs Phi (physical primary); Phi [rad]; Eff", 100, 0.f, 2 * TMath::Pi()); - mFractionITSTPCmatchEtaPhysPrim = new TEfficiency("mFractionITSTPCmatchEtaPhysPrim", "Fraction of ITSTPC matched tracks vs Eta (physical primary); Eta; Eff", 100, -2.f, 2.f); - mPhiPhysPrim = new TH1F("mPhiPhysPrim", "Phi distribution of matched tracks (physical primary); Phi [rad]; dNdPhi", 100, 0.f, 2 * TMath::Pi()); - mEtaPhysPrim = new TH1F("mEtaPhysPrim", "Eta distribution of matched tracks (physical primary); Eta; dNdEta", 100, -2.f, 2.f); - mEtaTPCPhysPrim = new TH1F("mEtaTPCPhysPrim", "Eta distribution of TPC tracks (physical primary); Eta; dNdEta", 100, -2.f, 2.f); - // ...till here + + std::array title{"TPC", "ITS"}; + std::array etaSel{"", ", |eta| < 0.9"}; + for (int i = 0; i < matchType::SIZE; ++i) { + // Pt + mPtNum[i] = new TH1D(Form("mPtNum_%s", title[i].c_str()), Form("Pt distribution of ITSTPC matched tracks, wrt %s tracks %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f); + mPtDen[i] = new TH1D(Form("mPtDen_%s", title[i].c_str()), Form("Pt distribution of %s tracks %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f); + mFractionITSTPCmatch[i] = new TEfficiency(Form("mFractionITSTPCmatch_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks wrt %s tracks vs Pt %s; Pt [GeV/c]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f); + mPtNum_noEta0[i] = new TH1D(Form("mPtNum_noEta0_%s", title[i].c_str()), Form("Pt distribution of ITSTPC matched tracks without |eta| < 0.05, wrt %s tracks %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f); + mPtDen_noEta0[i] = new TH1D(Form("mPtDen_noEta0_%s", title[i].c_str()), Form("Pt distribution of %s tracks without |eta| < 0.05 %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f); + mFractionITSTPCmatch_noEta0[i] = new TEfficiency(Form("mFractionITSTPCmatch_noEta0_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks wrt %s tracks vs Pt without |eta| < 0.05 %s; Pt [GeV/c]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f); + // Phi + mPhiNum[i] = new TH1F(Form("mPhiNum_%s", title[i].c_str()), Form("Phi distribution of ITSTPC matched tracks, wrt %s tracks %s; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); + mPhiDen[i] = new TH1F(Form("mPhiDen_%s", title[i].c_str()), Form("Phi distribution of %s tracks %s; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); + mFractionITSTPCmatchPhi[i] = new TEfficiency(Form("mFractionITSTPCmatchPhi_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs Phi wrt %s tracks %s; Phi [rad]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); + mPhiVsPtNum[i] = new TH2F(Form("mPhiVsPtNum_%s", title[i].c_str()), Form("Phi vs Pt distribution of ITSTPC matched tracks wrt %s %s; #it{p}_{T} [GeV#it{c}]; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f, 100, 0.f, 2 * TMath::Pi()); + mPhiVsPtDen[i] = new TH2F(Form("mPhiVsPtDen_%s", title[i].c_str()), Form("Phi vs Pt distribution of %s tracks %s; #it{p}_{T} [GeV#it{c}]; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f, 100, 0.f, 2 * TMath::Pi()); + mFractionITSTPCmatchPhiVsPt[i] = new TEfficiency(Form("mFractionITSTPCmatchPhiVsPt_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks wrt %s tracks %s, Phi vs Pt; #it{p}_{T} [GeV#it{c}]; Phi [rad]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f, 100, 0.f, 2 * TMath::Pi()); + // Eta + mEtaNum[i] = new TH1F(Form("mEtaNum_%s", title[i].c_str()), Form("Eta distribution of ITSTPC matched tracks, wrt %s tracks; Eta; dNdEta", title[i].c_str()), 100, -2.f, 2.f); + mEtaDen[i] = new TH1F(Form("mEtaDen_%s", title[i].c_str()), Form("Eta distribution of %s tracks; Eta; dNdEta", title[i].c_str()), 100, -2.f, 2.f); + mFractionITSTPCmatchEta[i] = new TEfficiency(Form("mFractionITSTPCmatchEta_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks , wrt %s tracks, vs Eta; Eta; Eff", title[i].c_str()), 100, -2.f, 2.f); + mEtaVsPtNum[i] = new TH2F(Form("mEtaVsPtNum_%s", title[i].c_str()), Form("Eta vs Pt distribution of ITSTPC matched tracks, wrt %s tracks; #it{p}_{T} [GeV#it{c}]; #it{p}_{T} [GeV#it{c}]; Eta", title[i].c_str()), 100, 0.f, 20.f, 100, -2.f, 2.f); + mEtaVsPtDen[i] = new TH2F(Form("mEtaVsPtDen_%s", title[i].c_str()), Form("Eta vs Pt distribution of %s tracks; #it{p}_{T} [GeV#it{c}]; #it{p}_{T} [GeV#it{c}]; Eta", title[i].c_str()), 100, 0.f, 20.f, 100, -2.f, 2.f); + mFractionITSTPCmatchEtaVsPt[i] = new TEfficiency(Form("mFractionITSTPCmatchEtaVsPt_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks, wrt %s tracks, Eta vs Pt; #it{p}_{T} [GeV#it{c}]; Eta; Eff", title[i].c_str()), 100, 0.f, 20.f, 100, -2.f, 2.f); + // 1/pt + m1OverPtNum[i] = new TH1D(Form("m1OverPtNum_%s", title[i].c_str()), Form("1/Pt distribution of matched tracks, wrt %s tracks %s; 1/Pt [c/GeV]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); + m1OverPtDen[i] = new TH1D(Form("m1OverPtDen_%s", title[i].c_str()), Form("1/Pt distribution of %s tracks %s; 1/Pt [c/GeV]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); + mFractionITSTPCmatch1OverPt[i] = new TEfficiency(Form("mFractionITSTPCmatch1OverPt_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs 1/Pt, wrt %s tracks %s; 1/Pt [c/GeV]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); + + // These will be empty in case of no MC info... + mPhiPhysPrimNum[i] = new TH1F(Form("mPhiPhysPrimNum_%s", title[i].c_str()), Form("Phi distribution of matched tracks (physical primary), wrt %s tracks %s; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); + mPhiPhysPrimDen[i] = new TH1F(Form("mPhiPhysPrimDen_%s", title[i].c_str()), Form("Phi distribution of %s tracks (physical primary) %s; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); + mFractionITSTPCmatchPhiPhysPrim[i] = new TEfficiency(Form("mFractionITSTPCmatchPhiPhysPrim_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs Phi (physical primary), wrt %s tracks %s; Phi [rad]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); + mEtaPhysPrimNum[i] = new TH1F(Form("mEtaPhysPrimNum_%s", title[i].c_str()), Form("Eta distribution of matched tracks (physical primary), wrt %s tracks; Eta; dNdEta", title[i].c_str()), 100, -2.f, 2.f); + mEtaPhysPrimDen[i] = new TH1F(Form("mEtaPhysPrimDen_%s", title[i].c_str()), Form("Eta distribution of %s tracks (physical primary); Eta; dNdEta", title[i].c_str()), 100, -2.f, 2.f); + mFractionITSTPCmatchEtaPhysPrim[i] = new TEfficiency(Form("mFractionITSTPCmatchEtaPhysPrim_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs Eta (physical primary), wrt %s tracks; Eta; Eff", title[i].c_str()), 100, -2.f, 2.f); + } mResidualPt = new TH2F("mResidualPt", "Residuals of ITS-TPC matching in #it{p}_{T}; #it{p}_{T}^{ITS-TPC} [GeV/c]; #it{p}_{T}^{ITS-TPC} - #it{p}_{T}^{TPC} [GeV/c]", 100, 0.f, 20.f, 100, -1.f, 1.f); mResidualPhi = new TH2F("mResidualPhi", "Residuals of ITS-TPC matching in #it{#phi}; #it{#phi}^{ITS-TPC} [rad]; #it{#phi}^{ITS-TPC} - #it{#phi}^{TPC} [rad]", 100, 0.f, 2 * TMath::Pi(), 100, -1.f, 1.f); mResidualEta = new TH2F("mResidualEta", "Residuals of ITS-TPC matching in #it{#eta}; #it{#eta}^{ITS-TPC}; #it{#eta}^{ITS-TPC} - #it{#eta}^{TPC}", 100, -2.f, 2.f, 100, -1.f, 1.f); mChi2Matching = new TH1F("mChi2Matching", "Chi2 of matching; chi2", 200, 0, 300); mChi2Refit = new TH1F("mChi2Refit", "Chi2 of refit; chi2", 200, 0, 300); + mDCAr = new TH1F("mDCAr", "DCA of TPC tracks; DCAr", 200, -100, 100); // log binning for pT const Int_t nbinsPt = 100; @@ -155,36 +192,57 @@ bool MatchITSTPCQC::init() xbinsPt[i] = TMath::Exp(TMath::Log(10) * xlogPt); } mTimeResVsPt = new TH2F("mTimeResVsPt", "Time resolution vs Pt; Pt [GeV/c]; time res [us]", nbinsPt, xbinsPt, 100, 0.f, 2.f); - mPtTPCPhysPrim = new TH1F("mPtTPPhysPrimC", "Pt distribution of TPC tracks (physical primary); Pt [GeV/c]; dNdPt", nbinsPt, xbinsPt); - mFractionITSTPCmatchPhysPrim = new TEfficiency("mFractionITSTPCmatchPhysPrim", "Fraction of ITSTPC matched tracks vs Pt (physical primary); Pt [GeV/c]; Eff", nbinsPt, xbinsPt); - mPtPhysPrim = new TH1F("mPtPhysPrim", "Pt distribution of matched tracks (physical primary); Pt [GeV/c]; dNdPt", nbinsPt, xbinsPt); - - mPtTPC->Sumw2(); - mPt->Sumw2(); - mPhiTPC->Sumw2(); - mPhi->Sumw2(); - mPhiVsPt->Sumw2(); - mPhiVsPtTPC->Sumw2(); - mPtTPCPhysPrim->Sumw2(); - mPtPhysPrim->Sumw2(); - mPhiTPCPhysPrim->Sumw2(); - mPhiPhysPrim->Sumw2(); - mEtaTPC->Sumw2(); - mEtaPhysPrim->Sumw2(); - mEtaTPCPhysPrim->Sumw2(); - mEtaVsPt->Sumw2(); - mEtaVsPtTPC->Sumw2(); - - mPtTPC->SetOption("logy"); - mPt->SetOption("logy"); - mEta->SetOption("logy"); + + for (int i = 0; i < matchType::SIZE; ++i) { + mPtPhysPrimNum[i] = new TH1F(Form("mPtPhysPrimNum_%s", title[i].c_str()), Form("Pt distribution of matched tracks (physical primary), wrt %s tracks %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), nbinsPt, xbinsPt); + mPtPhysPrimDen[i] = new TH1F(Form("mPtPhysPrimDen_%s", title[i].c_str()), Form("Pt distribution of %s tracks (physical primary) %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), nbinsPt, xbinsPt); + mFractionITSTPCmatchPhysPrim[i] = new TEfficiency(Form("mFractionITSTPCmatchPhysPrim_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs Pt (physical primary), wrt %s tracks %s; Pt [GeV/c]; Eff", title[i].c_str(), etaSel[i].c_str()), nbinsPt, xbinsPt); + m1OverPtPhysPrimNum[i] = new TH1D(Form("m1OverPtPhysPrimNum_%s", title[i].c_str()), Form("1/Pt distribution of matched tracks (physical primary), wrt %s tracks %s; 1/Pt [c/GeV]; dNd1/Pt", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); + m1OverPtPhysPrimDen[i] = new TH1D(Form("m1OverPtPhysPrimDen_%s", title[i].c_str()), Form("1/PtPt distribution of %s tracks (physical primary) %s; 1/Pt [c/GeV]; dNd1/Pt", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); + mFractionITSTPCmatchPhysPrim1OverPt[i] = new TEfficiency(Form("mFractionITSTPCmatchPhysPrim1OverPt_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs 1/Pt (physical primary), wrt %s tracks %s; 1/Pt [c/GeV]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); + + // some extra settings + mPtNum[i]->Sumw2(); + mPtDen[i]->Sumw2(); + mPtNum_noEta0[i]->Sumw2(); + mPtDen_noEta0[i]->Sumw2(); + mPhiNum[i]->Sumw2(); + mPhiDen[i]->Sumw2(); + mPhiVsPtNum[i]->Sumw2(); + mPhiVsPtDen[i]->Sumw2(); + mPtPhysPrimNum[i]->Sumw2(); + mPtPhysPrimDen[i]->Sumw2(); + mPhiPhysPrimNum[i]->Sumw2(); + mPhiPhysPrimDen[i]->Sumw2(); + mEtaNum[i]->Sumw2(); + mEtaDen[i]->Sumw2(); + mEtaPhysPrimNum[i]->Sumw2(); + mEtaPhysPrimDen[i]->Sumw2(); + mEtaVsPtNum[i]->Sumw2(); + mEtaVsPtDen[i]->Sumw2(); + + m1OverPtNum[i]->Sumw2(); + m1OverPtDen[i]->Sumw2(); + m1OverPtPhysPrimNum[i]->Sumw2(); + m1OverPtPhysPrimDen[i]->Sumw2(); + + mPtNum_noEta0[i]->SetOption("logy"); + mPtDen_noEta0[i]->SetOption("logy"); + mPtNum[i]->SetOption("logy"); + mPtDen[i]->SetOption("logy"); + + mPtNum[i]->GetYaxis()->SetTitleOffset(1.4); + mPtDen[i]->GetYaxis()->SetTitleOffset(1.4); + mPtNum_noEta0[i]->GetYaxis()->SetTitleOffset(1.4); + mPtDen_noEta0[i]->GetYaxis()->SetTitleOffset(1.4); + mEtaNum[i]->GetYaxis()->SetTitleOffset(1.4); + mEtaDen[i]->GetYaxis()->SetTitleOffset(1.4); + } + mChi2Matching->SetOption("logy"); mChi2Refit->SetOption("logy"); mTimeResVsPt->SetOption("colz logz logy logx"); - mPtTPC->GetYaxis()->SetTitleOffset(1.4); - mPt->GetYaxis()->SetTitleOffset(1.4); - mEta->GetYaxis()->SetTitleOffset(1.4); mChi2Matching->GetYaxis()->SetTitleOffset(1.4); mChi2Refit->GetYaxis()->SetTitleOffset(1.4); mTimeResVsPt->GetYaxis()->SetTitleOffset(1.4); @@ -205,7 +263,7 @@ void MatchITSTPCQC::initDataRequest() mSrc &= mAllowedSources; - if ((mSrc[GID::Source::ITSTPC] == 0 || mSrc[GID::Source::TPC] == 0)) { + if (mSrc[GID::Source::ITSTPC] == 0 || mSrc[GID::Source::TPC] == 0 || mSrc[GID::Source::ITS] == 0) { LOG(fatal) << "We cannot do ITSTPC QC, some sources are missing, check sources in " << mSrc; } @@ -224,13 +282,16 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) static int evCount = 0; mRecoCont.collectData(ctx, *mDataRequest.get()); mTPCTracks = mRecoCont.getTPCTracks(); + mITSTracks = mRecoCont.getITSTracks(); mITSTPCTracks = mRecoCont.getTPCITSTracks(); LOG(debug) << "****** Number of found ITSTPC tracks = " << mITSTPCTracks.size(); LOG(debug) << "****** Number of found TPC tracks = " << mTPCTracks.size(); + LOG(debug) << "****** Number of found ITS tracks = " << mITSTracks.size(); - // cache selection for TPC tracks + // cache selection for TPC and ITS tracks std::vector isTPCTrackSelectedEntry(mTPCTracks.size(), false); + std::vector isITSTrackSelectedEntry(mITSTracks.size(), false); TrackCuts cuts; for (size_t itrk = 0; itrk < mTPCTracks.size(); ++itrk) { @@ -244,28 +305,58 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) } } + for (size_t itrk = 0; itrk < mITSTracks.size(); ++itrk) { + auto const& trkIts = mITSTracks[itrk]; + o2::dataformats::GlobalTrackID id(itrk, GID::ITS); + if (cuts.isSelected(id, mRecoCont)) { + isITSTrackSelectedEntry[itrk] = true; + } + } + // numerator + eta, chi2... if (mUseMC) { - mMapLabels.clear(); + for (int i = 0; i < matchType::SIZE; ++i) { + mMapLabels[i].clear(); + } for (int itrk = 0; itrk < static_cast(mITSTPCTracks.size()); ++itrk) { auto const& trk = mITSTPCTracks[itrk]; auto idxTrkTpc = trk.getRefTPC().getIndex(); if (isTPCTrackSelectedEntry[idxTrkTpc] == true) { auto lbl = mRecoCont.getTrackMCLabel({(unsigned int)(itrk), GID::Source::ITSTPC}); - if (mMapLabels.find(lbl) == mMapLabels.end()) { + if (mMapLabels[matchType::TPC].find(lbl) == mMapLabels[matchType::TPC].end()) { + int source = lbl.getSourceID(); + int event = lbl.getEventID(); + const std::vector& pcontainer = mcReader.getTracks(source, event); + const o2::MCTrack& p = pcontainer[lbl.getTrackID()]; + if (MCTrackNavigator::isPhysicalPrimary(p, pcontainer)) { + mMapLabels[matchType::TPC].insert({lbl, {itrk, true}}); + } else { + mMapLabels[matchType::TPC].insert({lbl, {itrk, false}}); + } + } else { + // winner (if more tracks have the same label) has the highest pt + if (mITSTPCTracks[mMapLabels[matchType::TPC].at(lbl).mIdx].getPt() < trk.getPt()) { + mMapLabels[matchType::TPC].at(lbl).mIdx = itrk; + } + } + } + auto idxTrkIts = trk.getRefITS().getIndex(); + if (isITSTrackSelectedEntry[idxTrkIts] == true) { + auto lbl = mRecoCont.getTrackMCLabel({(unsigned int)(itrk), GID::Source::ITSTPC}); + if (mMapLabels[matchType::ITS].find(lbl) == mMapLabels[matchType::ITS].end()) { int source = lbl.getSourceID(); int event = lbl.getEventID(); const std::vector& pcontainer = mcReader.getTracks(source, event); const o2::MCTrack& p = pcontainer[lbl.getTrackID()]; if (MCTrackNavigator::isPhysicalPrimary(p, pcontainer)) { - mMapLabels.insert({lbl, {itrk, true}}); + mMapLabels[matchType::ITS].insert({lbl, {itrk, true}}); } else { - mMapLabels.insert({lbl, {itrk, false}}); + mMapLabels[matchType::ITS].insert({lbl, {itrk, false}}); } } else { // winner (if more tracks have the same label) has the highest pt - if (mITSTPCTracks[mMapLabels.at(lbl).mIdx].getPt() < trk.getPt()) { - mMapLabels.at(lbl).mIdx = itrk; + if (mITSTPCTracks[mMapLabels[matchType::ITS].at(lbl).mIdx].getPt() < trk.getPt()) { + mMapLabels[matchType::ITS].at(lbl).mIdx = itrk; } } } @@ -273,120 +364,290 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) LOG(info) << "number of entries in map for nominator (without duplicates) = " << mMapLabels.size(); // now we use only the tracks in the map to fill the histograms (--> tracks have passed the // track selection and there are no duplicated tracks wrt the same MC label) - for (auto const& el : mMapLabels) { - auto const& trk = mITSTPCTracks[el.second.mIdx]; - auto const& trkTpc = mTPCTracks[trk.getRefTPC()]; - mPt->Fill(trkTpc.getPt()); - mPhi->Fill(trkTpc.getPhi()); - mPhiVsPt->Fill(trkTpc.getPt(), trkTpc.getPhi()); - mEta->Fill(trkTpc.getEta()); - mEtaVsPt->Fill(trkTpc.getPt(), trkTpc.getEta()); - // we fill also the denominator - mPtTPC->Fill(trkTpc.getPt()); - mPhiTPC->Fill(trkTpc.getPhi()); - mPhiVsPtTPC->Fill(trkTpc.getPt(), trkTpc.getPhi()); - mEtaTPC->Fill(trkTpc.getEta()); - mEtaVsPtTPC->Fill(trkTpc.getPt(), trkTpc.getEta()); - if (el.second.mIsPhysicalPrimary) { - mPtPhysPrim->Fill(trkTpc.getPt()); - mPhiPhysPrim->Fill(trkTpc.getPhi()); - mEtaPhysPrim->Fill(trkTpc.getEta()); + for (int i = 0; i < matchType::SIZE; ++i) { + for (auto const& el : mMapLabels[i]) { + auto const& trk = mITSTPCTracks[el.second.mIdx]; + o2::track::TrackParCov trkDen; + bool isEtaITSOk = true; + if (i == matchType::TPC) { + trkDen = mTPCTracks[trk.getRefTPC()]; + } else { + trkDen = mITSTracks[trk.getRefITS()]; + if (std::abs(trkDen.getEta()) > 0.9) { + // ITS track outside |eta | < 0.9, we don't fill pt, nor phi , nor phi vs pt histos + isEtaITSOk = false; + } + } + if (isEtaITSOk) { + mPtNum[i]->Fill(trkDen.getPt()); + if (std::abs(trkDen.getEta()) > 0.05) { + mPtNum_noEta0[i]->Fill(trkDen.getPt()); + } + mPhiNum[i]->Fill(trkDen.getPhi()); + mPhiVsPtNum[i]->Fill(trkDen.getPt(), trkDen.getPhi()); + m1OverPtNum[i]->Fill(trkDen.getSign() * trkDen.getPtInv()); + // we fill also the denominator + mPtDen[i]->Fill(trkDen.getPt()); + if (std::abs(trkDen.getEta()) > 0.05) { + mPtDen_noEta0[i]->Fill(trkDen.getPt()); + } + mPhiDen[i]->Fill(trkDen.getPhi()); + mPhiVsPtDen[i]->Fill(trkDen.getPt(), trkDen.getPhi()); + m1OverPtDen[i]->Fill(trkDen.getSign() * trkDen.getPtInv()); + } + mEtaNum[i]->Fill(trkDen.getEta()); + mEtaVsPtNum[i]->Fill(trkDen.getPt(), trkDen.getEta()); // we fill also the denominator - mPtTPCPhysPrim->Fill(trkTpc.getPt()); - mPhiTPCPhysPrim->Fill(trkTpc.getPhi()); - mEtaTPCPhysPrim->Fill(trkTpc.getEta()); + mEtaDen[i]->Fill(trkDen.getEta()); + mEtaVsPtDen[i]->Fill(trkDen.getPt(), trkDen.getEta()); + if (el.second.mIsPhysicalPrimary) { + if (isEtaITSOk) { + mPtPhysPrimNum[i]->Fill(trkDen.getPt()); + mPhiPhysPrimNum[i]->Fill(trkDen.getPhi()); + m1OverPtPhysPrimNum[i]->Fill(trkDen.getSign() * trkDen.getPtInv()); + // we fill also the denominator + mPtPhysPrimDen[i]->Fill(trkDen.getPt()); + mPhiPhysPrimDen[i]->Fill(trkDen.getPhi()); + m1OverPtPhysPrimDen[i]->Fill(trkDen.getSign() * trkDen.getPtInv()); + } + mEtaPhysPrimNum[i]->Fill(trkDen.getEta()); + // we fill also the denominator + mEtaPhysPrimDen[i]->Fill(trkDen.getEta()); + } + ++mNITSTPCSelectedTracks[i]; } - ++mNITSTPCSelectedTracks; } } - + int iITSTPC = 0; for (auto const& trk : mITSTPCTracks) { if (trk.getRefTPC().getIndex() >= mTPCTracks.size()) { - LOG(fatal) << "******************** ATTENTION! idx = " << trk.getRefTPC().getIndex() << ", size of container = " << mTPCTracks.size() << " in TF " << evCount; - continue; + LOG(fatal) << "******************** ATTENTION! for TPC track associated to matched track: idx = " << trk.getRefTPC().getIndex() << ", size of container = " << mTPCTracks.size() << " in TF " << evCount; } - auto const& trkTpc = mTPCTracks[trk.getRefTPC()]; - auto idxTrkTpc = trk.getRefTPC().getIndex(); - if (isTPCTrackSelectedEntry[idxTrkTpc] == true) { - if (!mUseMC) { - mPt->Fill(trkTpc.getPt()); - mPhi->Fill(trkTpc.getPhi()); - mPhiVsPt->Fill(trkTpc.getPt(), trkTpc.getPhi()); - mEta->Fill(trkTpc.getEta()); - mEtaVsPt->Fill(trkTpc.getPt(), trkTpc.getEta()); + if (trk.getRefITS().getIndex() >= mITSTracks.size()) { + LOG(fatal) << "******************** ATTENTION! for ITS track associated to matched track: idx = " << trk.getRefITS().getIndex() << ", size of container = " << mITSTracks.size() << " in TF " << evCount; + } + std::array title{"TPC", "ITS"}; + for (int i = 0; i < matchType::SIZE; ++i) { + o2::track::TrackParCov trkRef; + int idxTrkRef; + bool fillHisto = false; + bool isEtaITSOk = true; + if (i == matchType::TPC) { + trkRef = mTPCTracks[trk.getRefTPC()]; + idxTrkRef = trk.getRefTPC().getIndex(); + if (isTPCTrackSelectedEntry[idxTrkRef] == true) { + fillHisto = true; + ++mNITSTPCSelectedTracks[i]; + } + } else { + trkRef = mITSTracks[trk.getRefITS()]; + idxTrkRef = trk.getRefITS().getIndex(); + LOG(debug) << "Checking track (ITS) with id " << idxTrkRef << " for ITSTPC track " << iITSTPC << " and pt = " << trkRef.getPt(); + if (trk.getRefITS().getSource() == GID::ITSAB) { + // do not use afterburner tracks + LOG(debug) << "Track (ITS) with id " << idxTrkRef << " for ITSTPC track " << iITSTPC << " is from afterburner"; + continue; + } + if (isITSTrackSelectedEntry[idxTrkRef] == true) { + LOG(debug) << "Track was selected (ITS), with id " << idxTrkRef << " for ITSTPC track " << iITSTPC << " , we keep it in the numerator, pt = " << trkRef.getPt(); + fillHisto = true; + ++mNITSTPCSelectedTracks[i]; + } else { + LOG(debug) << "Track was not selected (ITS), with id " << idxTrkRef << " for ITSTPC track " << iITSTPC << " , we don't keep it in the numerator, pt = " << trkRef.getPt(); + } + if (std::abs(trkRef.getEta()) > 0.9) { + // ITS track outside |eta | < 0.9, we don't fill pt, nor phi , nor phi vs pt histos + isEtaITSOk = false; + LOG(debug) << "Track (ITS), with id " << idxTrkRef << " for ITSTPC track " << iITSTPC << " will be discarded when filling pt of phi related histograms, since eta = " << trkRef.getEta() << " , we don't keep it in the numerator, pt = " << trkRef.getPt(); + } + } + if (fillHisto == true) { + if (!mUseMC) { + LOG(debug) << "Filling num (" << title[i] << ") with track with id " << idxTrkRef << " for ITSTPC track " << iITSTPC << " with pt = " << trkRef.getPt(); + if (isEtaITSOk) { + mPtNum[i]->Fill(trkRef.getPt()); + if (std::abs(trkRef.getEta()) > 0.05) { + mPtNum_noEta0[i]->Fill(trkRef.getPt()); + } + mPhiNum[i]->Fill(trkRef.getPhi()); + mPhiVsPtNum[i]->Fill(trkRef.getPt(), trkRef.getPhi()); + m1OverPtNum[i]->Fill(trkRef.getSign() * trkRef.getPtInv()); + } + mEtaNum[i]->Fill(trkRef.getEta()); + mEtaVsPtNum[i]->Fill(trkRef.getPt(), trkRef.getEta()); + } + if (i == matchType::TPC) { + mResidualPt->Fill(trk.getPt(), trk.getPt() - trkRef.getPt()); + mResidualPhi->Fill(trk.getPhi(), trk.getPhi() - trkRef.getPhi()); + mResidualEta->Fill(trk.getEta(), trk.getEta() - trkRef.getEta()); + mChi2Matching->Fill(trk.getChi2Match()); + mChi2Refit->Fill(trk.getChi2Refit()); + mTimeResVsPt->Fill(trkRef.getPt(), trk.getTimeMUS().getTimeStampError()); + math_utils::Point3D v{}; + std::array dca; + if (trkRef.propagateParamToDCA(v, mBz, &dca)) { + mDCAr->Fill(dca[0]); + } + LOG(debug) << "*** chi2Matching = " << trk.getChi2Match() << ", chi2refit = " << trk.getChi2Refit() << ", timeResolution = " << trk.getTimeMUS().getTimeStampError(); + } + } else { + LOG(debug) << "Not filling num (" << title[i] << ") for ITSTPC track " << iITSTPC << " for track with pt " << trkRef.getPt(); } - mResidualPt->Fill(trk.getPt(), trk.getPt() - trkTpc.getPt()); - mResidualPhi->Fill(trk.getPhi(), trk.getPhi() - trkTpc.getPhi()); - mResidualEta->Fill(trk.getEta(), trk.getEta() - trkTpc.getEta()); - mChi2Matching->Fill(trk.getChi2Match()); - mChi2Refit->Fill(trk.getChi2Refit()); - mTimeResVsPt->Fill(trkTpc.getPt(), trk.getTimeMUS().getTimeStampError()); - LOG(debug) << "*** chi2Matching = " << trk.getChi2Match() << ", chi2refit = " << trk.getChi2Refit() << ", timeResolution = " << trk.getTimeMUS().getTimeStampError(); - ++mNITSTPCSelectedTracks; } + ++iITSTPC; } // now filling the denominator for the efficiency calculation if (mUseMC) { - mMapTPCLabels.clear(); + for (int i = 0; i < matchType::SIZE; ++i) { + mMapRefLabels[i].clear(); + } // filling the map where we store for each MC label, the track id of the reconstructed // track with the highest number of TPC clusters for (int itrk = 0; itrk < static_cast(mTPCTracks.size()); ++itrk) { auto const& trk = mTPCTracks[itrk]; if (isTPCTrackSelectedEntry[itrk] == true) { auto lbl = mRecoCont.getTrackMCLabel({(unsigned int)(itrk), GID::Source::TPC}); - if (mMapLabels.find(lbl) != mMapLabels.end()) { + if (mMapLabels[matchType::TPC].find(lbl) != mMapLabels[matchType::TPC].end()) { // the track was already added to the denominator continue; } - if (mMapTPCLabels.find(lbl) == mMapTPCLabels.end()) { + if (mMapRefLabels[matchType::TPC].find(lbl) == mMapRefLabels[matchType::TPC].end()) { int source = lbl.getSourceID(); int event = lbl.getEventID(); const std::vector& pcontainer = mcReader.getTracks(source, event); const o2::MCTrack& p = pcontainer[lbl.getTrackID()]; if (MCTrackNavigator::isPhysicalPrimary(p, pcontainer)) { - mMapTPCLabels.insert({lbl, {itrk, true}}); + mMapRefLabels[matchType::TPC].insert({lbl, {itrk, true}}); } else { - mMapTPCLabels.insert({lbl, {itrk, false}}); + mMapRefLabels[matchType::TPC].insert({lbl, {itrk, false}}); } } else { // winner (if more tracks have the same label) has the highest number of TPC clusters - if (mTPCTracks[mMapTPCLabels.at(lbl).mIdx].getNClusters() < trk.getNClusters()) { - mMapTPCLabels.at(lbl).mIdx = itrk; + if (mTPCTracks[mMapRefLabels[matchType::TPC].at(lbl).mIdx].getNClusters() < trk.getNClusters()) { + mMapRefLabels[matchType::TPC].at(lbl).mIdx = itrk; + } + } + } + } + // same for ITS + // filling the map where we store for each MC label, the track id of the reconstructed + // track with the highest number of ITS clusters + for (int itrk = 0; itrk < static_cast(mITSTracks.size()); ++itrk) { + auto const& trk = mITSTracks[itrk]; + if (isITSTrackSelectedEntry[itrk] == true) { + auto lbl = mRecoCont.getTrackMCLabel({(unsigned int)(itrk), GID::Source::ITS}); + if (mMapLabels[matchType::ITS].find(lbl) != mMapLabels[matchType::ITS].end()) { + // the track was already added to the denominator + continue; + } + if (mMapRefLabels[matchType::ITS].find(lbl) == mMapRefLabels[matchType::ITS].end()) { + int source = lbl.getSourceID(); + int event = lbl.getEventID(); + const std::vector& pcontainer = mcReader.getTracks(source, event); + const o2::MCTrack& p = pcontainer[lbl.getTrackID()]; + if (MCTrackNavigator::isPhysicalPrimary(p, pcontainer)) { + mMapRefLabels[matchType::ITS].insert({lbl, {itrk, true}}); + } else { + mMapRefLabels[matchType::ITS].insert({lbl, {itrk, false}}); + } + } else { + // winner (if more tracks have the same label) has the highest number of ITS clusters + if (mITSTracks[mMapRefLabels[matchType::ITS].at(lbl).mIdx].getNClusters() < trk.getNClusters()) { + mMapRefLabels[matchType::ITS].at(lbl).mIdx = itrk; } } } } - LOG(info) << "number of entries in map for denominator (without duplicates) = " << mMapTPCLabels.size() + mMapLabels.size(); + LOG(info) << "number of entries in map for denominator of TPC tracks (without duplicates) = " << mMapRefLabels[matchType::TPC].size() + mMapLabels[matchType::TPC].size(); + LOG(info) << "number of entries in map for denominator of ITS tracks (without duplicates) = " << mMapRefLabels[matchType::ITS].size() + mMapLabels[matchType::ITS].size(); // now we use only the tracks in the map to fill the histograms (--> tracks have passed the // track selection and there are no duplicated tracks wrt the same MC label) - for (auto const& el : mMapTPCLabels) { + for (auto const& el : mMapRefLabels[matchType::TPC]) { auto const& trk = mTPCTracks[el.second.mIdx]; - mPtTPC->Fill(trk.getPt()); - mPhiTPC->Fill(trk.getPhi()); - mPhiVsPtTPC->Fill(trk.getPt(), trk.getPhi()); - mEtaTPC->Fill(trk.getEta()); - mEtaVsPtTPC->Fill(trk.getPt(), trk.getEta()); + mPtDen[matchType::TPC]->Fill(trk.getPt()); + if (std::abs(trk.getEta()) > 0.05) { + mPtDen_noEta0[matchType::TPC]->Fill(trk.getPt()); + } + mPhiDen[matchType::TPC]->Fill(trk.getPhi()); + mPhiVsPtDen[matchType::TPC]->Fill(trk.getPt(), trk.getPhi()); + mEtaDen[matchType::TPC]->Fill(trk.getEta()); + mEtaVsPtDen[matchType::TPC]->Fill(trk.getPt(), trk.getEta()); + m1OverPtDen[matchType::TPC]->Fill(trk.getSign() * trk.getPtInv()); if (el.second.mIsPhysicalPrimary) { - mPtTPCPhysPrim->Fill(trk.getPt()); - mPhiTPCPhysPrim->Fill(trk.getPhi()); - mEtaTPCPhysPrim->Fill(trk.getEta()); + mPtPhysPrimDen[matchType::TPC]->Fill(trk.getPt()); + mPhiPhysPrimDen[matchType::TPC]->Fill(trk.getPhi()); + mEtaPhysPrimDen[matchType::TPC]->Fill(trk.getEta()); + m1OverPtPhysPrimDen[matchType::TPC]->Fill(trk.getSign() * trk.getPtInv()); } ++mNTPCSelectedTracks; } + for (auto const& el : mMapRefLabels[matchType::ITS]) { + auto const& trk = mITSTracks[el.second.mIdx]; + if (std::abs(trk.getEta()) < 0.9) { + mPtDen[matchType::ITS]->Fill(trk.getPt()); + if (std::abs(trk.getEta()) > 0.05) { + mPtDen_noEta0[matchType::ITS]->Fill(trk.getPt()); + } + mPhiDen[matchType::ITS]->Fill(trk.getPhi()); + mPhiVsPtDen[matchType::ITS]->Fill(trk.getPt(), trk.getPhi()); + m1OverPtDen[matchType::ITS]->Fill(trk.getSign() * trk.getPtInv()); + } + mEtaDen[matchType::ITS]->Fill(trk.getEta()); + mEtaVsPtDen[matchType::ITS]->Fill(trk.getPt(), trk.getEta()); + if (el.second.mIsPhysicalPrimary) { + if (std::abs(trk.getEta()) < 0.9) { + mPtPhysPrimDen[matchType::ITS]->Fill(trk.getPt()); + mPhiPhysPrimDen[matchType::ITS]->Fill(trk.getPhi()); + m1OverPtPhysPrimDen[matchType::ITS]->Fill(trk.getSign() * trk.getPtInv()); + } + mEtaPhysPrimDen[matchType::ITS]->Fill(trk.getEta()); + } + ++mNITSSelectedTracks; + } } else { // if we are in data, we loop over all tracks (no check on the label) for (size_t itrk = 0; itrk < mTPCTracks.size(); ++itrk) { auto const& trk = mTPCTracks[itrk]; if (isTPCTrackSelectedEntry[itrk] == true) { - mPtTPC->Fill(trk.getPt()); - mPhiTPC->Fill(trk.getPhi()); - mPhiVsPtTPC->Fill(trk.getPt(), trk.getPhi()); - mEtaTPC->Fill(trk.getEta()); - mEtaVsPtTPC->Fill(trk.getPt(), trk.getEta()); + LOG(debug) << "Filling den (TPC) with track with pt = " << trk.getPt(); + mPtDen[matchType::TPC]->Fill(trk.getPt()); + if (std::abs(trk.getEta()) > 0.05) { + mPtDen_noEta0[matchType::TPC]->Fill(trk.getPt()); + } else { + LOG(debug) << "Track (ITS) " << itrk << " with pt = " << trk.getPt() << " and eta = " << trk.getEta() << " not used for den pt, phi, phi vs pt, 1.pt histos"; + } + mPhiDen[matchType::TPC]->Fill(trk.getPhi()); + mPhiVsPtDen[matchType::TPC]->Fill(trk.getPt(), trk.getPhi()); + mEtaDen[matchType::TPC]->Fill(trk.getEta()); + mEtaVsPtDen[matchType::TPC]->Fill(trk.getPt(), trk.getEta()); + m1OverPtDen[matchType::TPC]->Fill(trk.getSign() * trk.getPtInv()); ++mNTPCSelectedTracks; } } + for (size_t itrk = 0; itrk < mITSTracks.size(); ++itrk) { + auto const& trk = mITSTracks[itrk]; + LOG(debug) << "Checking den for track (ITS) " << itrk << " with pt " << trk.getPt() << " and eta = " << trk.getEta(); + if (isITSTrackSelectedEntry[itrk] == true) { + if (std::abs(trk.getEta()) < 0.9) { + LOG(debug) << "Filling den for track (ITS) " << itrk << " with pt = " << trk.getPt() << " and eta = " << trk.getEta(); + mPtDen[matchType::ITS]->Fill(trk.getPt()); + if (std::abs(trk.getEta()) > 0.05) { + mPtDen_noEta0[matchType::ITS]->Fill(trk.getPt()); + } + mPhiDen[matchType::ITS]->Fill(trk.getPhi()); + mPhiVsPtDen[matchType::ITS]->Fill(trk.getPt(), trk.getPhi()); + m1OverPtDen[matchType::ITS]->Fill(trk.getSign() * trk.getPtInv()); + } else { + LOG(debug) << "Track (ITS) " << itrk << " with pt = " << trk.getPt() << " and eta = " << trk.getEta() << " not used for num pt, phi, phi vs pt, 1.pt histos"; + } + mEtaDen[matchType::ITS]->Fill(trk.getEta()); + mEtaVsPtDen[matchType::ITS]->Fill(trk.getPt(), trk.getEta()); + ++mNITSSelectedTracks; + } else { + LOG(debug) << "Not filling for this track (ITS) " << itrk << " with pt = " << trk.getPt(); + } + } } evCount++; } @@ -420,36 +681,48 @@ bool MatchITSTPCQC::selectTrack(o2::tpc::TrackTPC const& track) void MatchITSTPCQC::finalize() { + std::array title{"TPC", "ITS"}; + // first we use denominators and nominators to set the TEfficiency; later they are scaled - for (int i = 0; i < mPtTPC->GetNbinsX(); ++i) { - if (mPtTPC->GetBinContent(i + 1) < mPt->GetBinContent(i + 1)) { - LOG(error) << "bin " << i + 1 << ": mPtTPC[i] = " << mPtTPC->GetBinContent(i + 1) << ", mPt[i] = " << mPt->GetBinContent(i + 1); + // some checks + for (int i = 0; i < matchType::SIZE; ++i) { + for (int i = 0; i < mPtDen[i]->GetNbinsX(); ++i) { + if (mPtDen[i]->GetBinContent(i + 1) < mPtNum[i]->GetBinContent(i + 1)) { + LOG(error) << title[i] << ": bin " << i + 1 << " in [" << mPtNum[i]->GetBinLowEdge(i + 1) << " , " << mPtNum[i]->GetBinLowEdge(i + 1) + mPtNum[i]->GetBinWidth(i + 1) << "]: mPtDen[i] = " << mPtDen[i]->GetBinContent(i + 1) << ", mPtNum[i] = " << mPtNum[i]->GetBinContent(i + 1); + } } - } - for (int i = 0; i < mPhiTPC->GetNbinsX(); ++i) { - if (mPhiTPC->GetBinContent(i + 1) < mPhi->GetBinContent(i + 1)) { - LOG(error) << "bin " << i + 1 << ": mPhiTPC[i] = " << mPhiTPC->GetBinContent(i + 1) << ", mPhi[i] = " << mPhi->GetBinContent(i + 1); + for (int i = 0; i < mPtDen_noEta0[i]->GetNbinsX(); ++i) { + if (mPtDen_noEta0[i]->GetBinContent(i + 1) < mPtNum_noEta0[i]->GetBinContent(i + 1)) { + LOG(error) << title[i] << ": bin " << i + 1 << " in [" << mPtNum_noEta0[i]->GetBinLowEdge(i + 1) << " , " << mPtNum_noEta0[i]->GetBinLowEdge(i + 1) + mPtNum_noEta0[i]->GetBinWidth(i + 1) << "]: mPtDen_noEta0[i] = " << mPtDen_noEta0[i]->GetBinContent(i + 1) << ", mPtNum_noEta0[i] = " << mPtNum_noEta0[i]->GetBinContent(i + 1); + } } - } - for (int i = 0; i < mEtaTPC->GetNbinsX(); ++i) { - if (mEtaTPC->GetBinContent(i + 1) < mEta->GetBinContent(i + 1)) { - LOG(error) << "bin " << i + 1 << ": mEtaTPC[i] = " << mEtaTPC->GetBinContent(i + 1) << ", mEta[i] = " << mEta->GetBinContent(i + 1); + for (int i = 0; i < mPhiDen[i]->GetNbinsX(); ++i) { + if (mPhiDen[i]->GetBinContent(i + 1) < mPhiNum[i]->GetBinContent(i + 1)) { + LOG(error) << title[i] << ": bin " << i + 1 << " in [" << mPhiNum[i]->GetBinLowEdge(i + 1) << " , " << mPhiNum[i]->GetBinLowEdge(i + 1) + mPhiNum[i]->GetBinWidth(i + 1) << "]: mPhiDen[i] = " << mPhiDen[i]->GetBinContent(i + 1) << ", mPhiNum[i] = " << mPhiNum[i]->GetBinContent(i + 1); + } + } + for (int i = 0; i < mEtaDen[i]->GetNbinsX(); ++i) { + if (mEtaDen[i]->GetBinContent(i + 1) < mEtaNum[i]->GetBinContent(i + 1)) { + LOG(error) << title[i] << ": bin " << i + 1 << " in [" << mEtaNum[i]->GetBinLowEdge(i + 1) << " , " << mEtaNum[i]->GetBinLowEdge(i + 1) + mEtaNum[i]->GetBinWidth(i + 1) << "]: mEtaDen[i] = " << mEtaDen[i]->GetBinContent(i + 1) << ", mEtaNum[i] = " << mEtaNum[i]->GetBinContent(i + 1); + } } - } - // we need to force to replace the total histogram, otherwise it will compare it to the previous passed one, and it might get an error of inconsistency in the bin contents - setEfficiency(mFractionITSTPCmatch, mPt, mPtTPC); - setEfficiency(mFractionITSTPCmatchPhi, mPhi, mPhiTPC); - setEfficiency(mFractionITSTPCmatchEta, mEta, mEtaTPC); - setEfficiency(mFractionITSTPCmatchPhiVsPt, mPhiVsPt, mPhiVsPtTPC, true); - setEfficiency(mFractionITSTPCmatchEtaVsPt, mEtaVsPt, mEtaVsPtTPC, true); - if (mUseMC) { - setEfficiency(mFractionITSTPCmatchPhysPrim, mPtPhysPrim, mPtTPCPhysPrim); - setEfficiency(mFractionITSTPCmatchPhiPhysPrim, mPhiPhysPrim, mPhiTPCPhysPrim); - setEfficiency(mFractionITSTPCmatchEtaPhysPrim, mEtaPhysPrim, mEtaTPCPhysPrim); + // filling the efficiency + setEfficiency(mFractionITSTPCmatch[i], mPtNum[i], mPtDen[i]); + setEfficiency(mFractionITSTPCmatch_noEta0[i], mPtNum_noEta0[i], mPtDen_noEta0[i]); + setEfficiency(mFractionITSTPCmatchPhi[i], mPhiNum[i], mPhiDen[i]); + setEfficiency(mFractionITSTPCmatchEta[i], mEtaNum[i], mEtaDen[i]); + setEfficiency(mFractionITSTPCmatchPhiVsPt[i], mPhiVsPtNum[i], mPhiVsPtDen[i], true); + setEfficiency(mFractionITSTPCmatchEtaVsPt[i], mEtaVsPtNum[i], mEtaVsPtDen[i], true); + setEfficiency(mFractionITSTPCmatch1OverPt[i], m1OverPtNum[i], m1OverPtDen[i]); + if (mUseMC) { + setEfficiency(mFractionITSTPCmatchPhysPrim[i], mPtPhysPrimNum[i], mPtPhysPrimDen[i]); + setEfficiency(mFractionITSTPCmatchPhiPhysPrim[i], mPhiPhysPrimNum[i], mPhiPhysPrimDen[i]); + setEfficiency(mFractionITSTPCmatchEtaPhysPrim[i], mEtaPhysPrimNum[i], mEtaPhysPrimDen[i]); + setEfficiency(mFractionITSTPCmatchPhysPrim1OverPt[i], m1OverPtPhysPrimNum[i], m1OverPtPhysPrimDen[i]); + } } - /* mPtTPC->Scale(scaleFactTPC); mPt->Scale(scaleFactITSTPC); @@ -493,6 +766,7 @@ void MatchITSTPCQC::setEfficiency(TEfficiency* eff, TH1* hnum, TH1* hden, bool i } } } + // we need to force to replace the total histogram, otherwise it will compare it to the previous passed one, and it might get an error of inconsistency in the bin contents if (!eff->SetTotalHistogram(*hden, "f")) { LOG(fatal) << "Something went wrong when defining the efficiency denominator " << eff->GetName() << " from " << hnum->GetName(); } @@ -511,30 +785,56 @@ void MatchITSTPCQC::setEfficiency(TEfficiency* eff, TH1* hnum, TH1* hden, bool i void MatchITSTPCQC::getHistos(TObjArray& objar) { - objar.Add(mPtTPC); - objar.Add(mFractionITSTPCmatch); - objar.Add(mPt); - objar.Add(mPhiTPC); - objar.Add(mPhiVsPtTPC); - objar.Add(mFractionITSTPCmatchPhi); - objar.Add(mPhi); - objar.Add(mPhiVsPt); - objar.Add(mPtTPCPhysPrim); - objar.Add(mFractionITSTPCmatchPhysPrim); - objar.Add(mPtPhysPrim); - objar.Add(mPhiTPCPhysPrim); - objar.Add(mFractionITSTPCmatchPhiPhysPrim); - objar.Add(mPhiPhysPrim); - objar.Add(mEta); - objar.Add(mEtaVsPt); + for (int i = 0; i < matchType::SIZE; ++i) { + objar.Add(mPtNum[i]); + objar.Add(mPtDen[i]); + objar.Add(mFractionITSTPCmatch[i]); + + objar.Add(mPtNum_noEta0[i]); + objar.Add(mPtDen_noEta0[i]); + objar.Add(mFractionITSTPCmatch_noEta0[i]); + + objar.Add(mPtPhysPrimNum[i]); + objar.Add(mPtPhysPrimDen[i]); + objar.Add(mFractionITSTPCmatchPhysPrim[i]); + + objar.Add(mPhiNum[i]); + objar.Add(mPhiDen[i]); + objar.Add(mFractionITSTPCmatchPhi[i]); + + objar.Add(mPhiPhysPrimNum[i]); + objar.Add(mPhiPhysPrimDen[i]); + objar.Add(mFractionITSTPCmatchPhiPhysPrim[i]); + + objar.Add(mPhiVsPtNum[i]); + objar.Add(mPhiVsPtDen[i]); + objar.Add(mFractionITSTPCmatchPhiVsPt[i]); + + objar.Add(mEtaNum[i]); + objar.Add(mEtaDen[i]); + objar.Add(mFractionITSTPCmatchEta[i]); + + objar.Add(mEtaPhysPrimNum[i]); + objar.Add(mEtaPhysPrimDen[i]); + objar.Add(mFractionITSTPCmatchEtaPhysPrim[i]); + + objar.Add(mEtaVsPtNum[i]); + objar.Add(mEtaVsPtDen[i]); + objar.Add(mFractionITSTPCmatchEtaVsPt[i]); + + objar.Add(m1OverPtNum[i]); + objar.Add(m1OverPtDen[i]); + objar.Add(mFractionITSTPCmatch1OverPt[i]); + + objar.Add(m1OverPtPhysPrimNum[i]); + objar.Add(m1OverPtPhysPrimDen[i]); + objar.Add(mFractionITSTPCmatchPhysPrim1OverPt[i]); + } objar.Add(mChi2Matching); objar.Add(mChi2Refit); objar.Add(mTimeResVsPt); - objar.Add(mEtaPhysPrim); - objar.Add(mEtaTPC); - objar.Add(mEtaVsPtTPC); - objar.Add(mEtaTPCPhysPrim); objar.Add(mResidualPt); objar.Add(mResidualPhi); objar.Add(mResidualEta); + objar.Add(mDCAr); } From 7c881354703869acc9bc5b3ab7ef51d347b991f4 Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 5 Oct 2023 14:01:15 +0200 Subject: [PATCH 216/324] uniform disable-strangeness-tracker opt., enable str.tracker by default --- Detectors/AOD/src/aod-producer-workflow.cxx | 4 ++-- prodtests/full-system-test/dpl-workflow.sh | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Detectors/AOD/src/aod-producer-workflow.cxx b/Detectors/AOD/src/aod-producer-workflow.cxx index 855f84e3031b3..1f39f11218be3 100644 --- a/Detectors/AOD/src/aod-producer-workflow.cxx +++ b/Detectors/AOD/src/aod-producer-workflow.cxx @@ -36,7 +36,7 @@ void customize(std::vector& workflowOptions) {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation"}}, {"disable-secondary-vertices", o2::framework::VariantType::Bool, false, {"disable filling secondary vertices"}}, - {"disable-strangeness-tracking", o2::framework::VariantType::Bool, false, {"disable filling strangeness tracking"}}, + {"disable-strangeness-tracker", o2::framework::VariantType::Bool, false, {"disable filling strangeness tracking"}}, {"info-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}, {"combine-source-devices", o2::framework::VariantType::Bool, false, {"merge DPL source devices"}}, @@ -52,7 +52,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); auto useMC = !configcontext.options().get("disable-mc"); bool enableSV = !configcontext.options().get("disable-secondary-vertices"); - bool enableST = !configcontext.options().get("disable-strangeness-tracking"); + bool enableST = !configcontext.options().get("disable-strangeness-tracker"); bool ctpcfgperrun = !configcontext.options().get("ctpconfig-run-independent"); GID::mask_t allowedSrc = GID::getSourcesMask("ITS,MFT,MCH,MID,MCH-MID,TPC,TRD,ITS-TPC,TPC-TOF,TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD,TPC-TRD-TOF,ITS-TPC-TRD-TOF,MFT-MCH,FT0,FV0,FDD,ZDC,EMC,CTP,PHS,CPV,HMP"); diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 8934a5b7924ef..6d970c6f905eb 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -87,6 +87,7 @@ EMCRAW2C_CONFIG= PHS_CONFIG= MCH_CONFIG_KEY= CTP_CONFIG= +: ${STRTRACKING:=} : ${ITSEXTRAERR:=} : ${TRACKTUNETPCINNER:=} : ${ITSTPC_CONFIG_KEY:=} @@ -145,17 +146,13 @@ fi if [[ $BEAMTYPE == "PbPb" ]]; then PVERTEXING_CONFIG_KEY+="pvertexer.maxChi2TZDebris=2000;" - : ${STRTRACKING:=" --disable-strangeness-tracker "} - AODPROD_OPT+=" --disable-strangeness-tracking " elif [[ $BEAMTYPE == "pp" ]]; then PVERTEXING_CONFIG_KEY+="pvertexer.maxChi2TZDebris=10;" - : ${STRTRACKING:=" "} fi if [[ $BEAMTYPE == "cosmic" ]]; then [[ -z ${ITS_CONFIG+x} ]] && ITS_CONFIG=" --tracking-mode cosmics" : ${STRTRACKING:=" --disable-strangeness-tracker "} - AODPROD_OPT+=" --disable-strangeness-tracking " elif [[ $SYNCMODE == 1 ]]; then [[ -z ${ITS_CONFIG+x} ]] && ITS_CONFIG=" --tracking-mode sync" else @@ -566,6 +563,7 @@ workflow_has_parameter GPU_DISPLAY && [[ $NUMAID == 0 ]] && add_W o2-gpu-display # --------------------------------------------------------------------------------------------------------------------- # AOD [[ ${SECTVTX_ON:-} != "1" ]] && AODPROD_OPT+=" --disable-secondary-vertices " +AODPROD_OPT+=" $STRTRACKING " workflow_has_parameter AOD && [[ ! -z "$AOD_INPUT" ]] && add_W o2-aod-producer-workflow "$AODPROD_OPT --info-sources $AOD_INPUT $DISABLE_ROOT_INPUT --aod-writer-keep dangling --aod-writer-resfile \"AO2D\" --aod-writer-resmode UPDATE $DISABLE_MC --pipeline $(get_N aod-producer-workflow AOD REST 1 AODPROD)" # --------------------------------------------------------------------------------------------------------------------- From cd75d2ce56556c876c9bbc2f9d9a633838d29e5f Mon Sep 17 00:00:00 2001 From: Dmitri Peresunko Date: Thu, 5 Oct 2023 08:50:38 +0300 Subject: [PATCH 217/324] Dont send CCDB if not calculated --- Detectors/PHOS/calib/src/PHOSL1phaseCalibDevice.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Detectors/PHOS/calib/src/PHOSL1phaseCalibDevice.cxx b/Detectors/PHOS/calib/src/PHOSL1phaseCalibDevice.cxx index d19a9fc080766..1ed04baa77892 100644 --- a/Detectors/PHOS/calib/src/PHOSL1phaseCalibDevice.cxx +++ b/Detectors/PHOS/calib/src/PHOSL1phaseCalibDevice.cxx @@ -48,6 +48,10 @@ void PHOSL1phaseCalibDevice::endOfStream(o2::framework::EndOfStreamContext& ec) mCalibrator->checkSlotsToFinalize(o2::calibration::INFINITE_TF); mCalibrator->endOfStream(); + if (mRunStartTime == 0 || mCalibrator->getCalibration() == 0) { // run not started || calibration was not produced + return; // do not create CCDB object + } + std::vector l1phase{mCalibrator->getCalibration()}; LOG(info) << "End of stream reached, sending output to CCDB"; // prepare all info to be sent to CCDB From adeb9432a99e3c7ae10074ca4805410d6615ab17 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Oct 2023 09:59:29 +0200 Subject: [PATCH 218/324] GPU: Fix compiler warning --- GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index 07a3b22b5f649..59e4df2246b4c 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -936,10 +936,10 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) } } - if (mWaitForFinalInputs && iSliceBase >= 21 && iSliceBase < 21 + GetProcessingSettings().nTPCClustererLanes) { + if (mWaitForFinalInputs && iSliceBase >= 21 && (int)iSliceBase < 21 + GetProcessingSettings().nTPCClustererLanes) { notifyForeignChainFinished(); } - if (mWaitForFinalInputs && iSliceBase >= 30 && iSliceBase < 30 + GetProcessingSettings().nTPCClustererLanes) { + if (mWaitForFinalInputs && iSliceBase >= 30 && (int)iSliceBase < 30 + GetProcessingSettings().nTPCClustererLanes) { mWaitForFinalInputs(); synchronizeCalibUpdate = DoQueuedUpdates(0, false); } From 8bb8e7b5fe6f61d376fa1de36ec5d642a3bff5a7 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Oct 2023 15:50:37 +0200 Subject: [PATCH 219/324] DPL: Fix: move allfound optimization to correct loop --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 4de5c7aa28aa9..73c282ae79327 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -241,7 +241,6 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve present.resize(routes.size(), false); static std::vector unmatchedDescriptions; unmatchedDescriptions.clear(); - bool allFound = true; DataProcessingHeader const* dph = nullptr; DataHeader const* firstDH = nullptr; bool hassih = false; @@ -261,6 +260,7 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve size_t foundDataSpecs = 0; for (int msgidx = 0; msgidx < parts.Size(); msgidx += 2) { + bool allFound = true; const auto dh = o2::header::get(parts.At(msgidx)->GetData()); auto const sih = o2::header::get(parts.At(msgidx)->GetData()); if (sih != nullptr) { From 756c0cceb0a746f9b832a5a0570f6e1ee3bf0824 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Oct 2023 16:29:24 +0200 Subject: [PATCH 220/324] DPL: Add option to raw-proxy to print input sizes per spec --- .../Framework/ExternalFairMQDeviceProxy.h | 4 +- .../Core/src/ExternalFairMQDeviceProxy.cxx | 67 +++++++++++++++---- Framework/Utils/src/raw-proxy.cxx | 7 +- 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h b/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h index b69b388150b4f..b75ef6a9815eb 100644 --- a/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h +++ b/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h @@ -106,8 +106,8 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* label, InjectorFunction converter, uint64_t minSHM = 0, bool sendTFcounter = false, - bool doInjectMissingData = false - ); + bool doInjectMissingData = false, + unsigned int doPrintSizes = 0); DataProcessorSpec specifyFairMQDeviceOutputProxy(char const* label, Inputs const& inputSpecs, diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 73c282ae79327..bca734375895d 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -233,12 +233,19 @@ auto getFinalIndex(DataHeader const& dh, size_t msgidx) -> size_t return finalBlockIndex; }; -void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::vector const& routes) +void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::vector const& routes, bool doInjectMissingData, unsigned int doPrintSizes) { // Check for missing data. static std::vector present; + static std::vector dataSizes; + static std::vector showSize; present.clear(); present.resize(routes.size(), false); + dataSizes.clear(); + dataSizes.resize(routes.size(), 0); + showSize.clear(); + showSize.resize(routes.size(), false); + static std::vector unmatchedDescriptions; unmatchedDescriptions.clear(); DataProcessingHeader const* dph = nullptr; @@ -261,6 +268,7 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve size_t foundDataSpecs = 0; for (int msgidx = 0; msgidx < parts.Size(); msgidx += 2) { bool allFound = true; + int addToSize = -1; const auto dh = o2::header::get(parts.At(msgidx)->GetData()); auto const sih = o2::header::get(parts.At(msgidx)->GetData()); if (sih != nullptr) { @@ -284,9 +292,12 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve } if (firstDH == nullptr) { firstDH = dh; + if (doPrintSizes && firstDH->tfCounter % doPrintSizes != 0) { + doPrintSizes = 0; + } } for (size_t pi = 0; pi < present.size(); ++pi) { - if (present[pi]) { + if (present[pi] && !doPrintSizes) { continue; } // Consider uninvolved pipelines as present. @@ -298,24 +309,53 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve auto& spec = routes[pi].matcher; OutputSpec query{dh->dataOrigin, dh->dataDescription, dh->subSpecification}; if (DataSpecUtils::match(spec, query)) { - present[pi] = true; - ++foundDataSpecs; + if (!present[pi]) { + ++foundDataSpecs; + present[pi] = true; + showSize[pi] = true; + } + addToSize = pi; break; } } - // Skip the rest of the block of messages. We subtract 2 because above - // we increment by 2. - msgidx = getFinalIndex(*dh, msgidx) - 2; - if (allFound) { + int msgidxLast = getFinalIndex(*dh, msgidx); + if (addToSize >= 0) { + int increment = (dh->splitPayloadParts > 0 && dh->splitPayloadParts == dh->splitPayloadIndex) ? 1 : 2; + for (int msgidx2 = msgidx + 1; msgidx2 < msgidxLast; msgidx2 += increment) { + dataSizes[addToSize] += parts.At(msgidx2)->GetSize(); + } + } + // Skip the rest of the block of messages. We subtract 2 because above we increment by 2. + msgidx = msgidxLast - 2; + if (allFound && !doPrintSizes) { return; } } + for (size_t pi = 0; pi < present.size(); ++pi) { if (!present[pi]) { + showSize[pi] = true; unmatchedDescriptions.push_back(pi); } } + if (firstDH && doPrintSizes) { + std::string sizes = ""; + size_t totalSize = 0; + for (size_t pi = 0; pi < present.size(); ++pi) { + if (showSize[pi]) { + totalSize += dataSizes[pi]; + auto& spec = routes[pi].matcher; + sizes += DataSpecUtils::describe(spec) + fmt::format(":{} ", fmt::group_digits(dataSizes[pi])); + } + } + LOGP(important, "RAW {} size report:{}- Total:{}", firstDH->tfCounter, sizes, fmt::group_digits(totalSize)); + } + + if (!doInjectMissingData) { + return; + } + if (unmatchedDescriptions.size() > 0) { if (hassih) { if (firstDH) { @@ -363,7 +403,7 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve static int maxWarn = 10; // Correct would be o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef, but Framework does not depend on CommonUtils..., but not so critical since receives will send correct number of DEADBEEF messages static int contDeadBeef = 0; if (++contDeadBeef <= maxWarn) { - LOGP(alarm, "Found {}/{} data specs, missing data specs: {}, injecting 0xDEADBEEF", foundDataSpecs, expectedDataSpecs, missing); + LOGP(alarm, "Found {}/{} data specs, missing data specs: {}, injecting 0xDEADBEEF{}", foundDataSpecs, expectedDataSpecs, missing, contDeadBeef == maxWarn ? " - disabling alarm now to stop flooding the log" : ""); } } } @@ -573,7 +613,8 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, InjectorFunction converter, uint64_t minSHM, bool sendTFcounter, - bool doInjectMissingData) + bool doInjectMissingData, + unsigned int doPrintSizes) { DataProcessorSpec spec; spec.name = strdup(name); @@ -585,7 +626,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, // The Init method will register a new "Out of band" channel and // attach an OnData to it which is responsible for converting incoming // messages into DPL messages. - spec.algorithm = AlgorithmSpec{[converter, minSHM, deviceName = spec.name, sendTFcounter, doInjectMissingData](InitContext& ctx) { + spec.algorithm = AlgorithmSpec{[converter, minSHM, deviceName = spec.name, sendTFcounter, doInjectMissingData, doPrintSizes](InitContext& ctx) { auto* device = ctx.services().get().device(); // make a copy of the output routes and pass to the lambda by move auto outputRoutes = ctx.services().get().spec().outputs; @@ -709,7 +750,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, return count; }; - auto dataHandler = [device, converter, doInjectMissingData, + auto dataHandler = [device, converter, doInjectMissingData, doPrintSizes, outputRoutes = std::move(outputRoutes), control = &ctx.services().get(), deviceState = &ctx.services().get(), @@ -740,7 +781,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, // For reference, the oldest possible timeframe passed as newTimesliceId here comes from LifetimeHelpers::enumDrivenCreation() bool shouldstop = false; if (doInjectMissingData) { - injectMissingData(*device, inputs, outputRoutes); + injectMissingData(*device, inputs, outputRoutes, doInjectMissingData, doPrintSizes); } converter(timingInfo, *device, inputs, channelRetriever, timesliceIndex->getOldestPossibleOutput().timeslice.value, shouldstop); diff --git a/Framework/Utils/src/raw-proxy.cxx b/Framework/Utils/src/raw-proxy.cxx index f85323ba0d321..195e1bd61d081 100644 --- a/Framework/Utils/src/raw-proxy.cxx +++ b/Framework/Utils/src/raw-proxy.cxx @@ -35,6 +35,10 @@ void customize(std::vector& workflowOptions) ConfigParamSpec{ "inject-missing-data", VariantType::Bool, false, {"inject missing data according to dataspec if not found in the input"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "print-input-sizes", VariantType::Int, 0, {"print statistics about sizes per input spec every n TFs"}}); + workflowOptions.push_back( ConfigParamSpec{ "throwOnUnmatched", VariantType::Bool, false, {"throw if unmatched input data is found"}}); @@ -51,6 +55,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) std::string processorName = config.options().get("proxy-name"); std::string outputconfig = config.options().get("dataspec"); bool injectMissingData = config.options().get("inject-missing-data"); + unsigned int printSizes = config.options().get("print-input-sizes"); bool throwOnUnmatched = config.options().get("throwOnUnmatched"); uint64_t minSHM = std::stoul(config.options().get("timeframes-shm-limit")); std::vector matchers = select(outputconfig.c_str()); @@ -65,7 +70,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) processorName.c_str(), std::move(readoutProxyOutput), "type=pair,method=connect,address=ipc:///tmp/readout-pipe-0,rateLogging=1,transport=shmem", - dplModelAdaptor(filterSpecs, throwOnUnmatched), minSHM, false, injectMissingData); + dplModelAdaptor(filterSpecs, throwOnUnmatched), minSHM, false, injectMissingData, printSizes); WorkflowSpec workflow; workflow.emplace_back(readoutProxy); From 4be135c6a669c69a0fc62083d0a8f7d666d1ff8d Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Oct 2023 20:54:10 +0200 Subject: [PATCH 221/324] CTF: Print also the total size in size report --- Detectors/CTF/workflow/src/CTFWriterSpec.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/CTF/workflow/src/CTFWriterSpec.cxx b/Detectors/CTF/workflow/src/CTFWriterSpec.cxx index aecb34abb08d9..44d726dd7e4f4 100644 --- a/Detectors/CTF/workflow/src/CTFWriterSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFWriterSpec.cxx @@ -494,7 +494,7 @@ void CTFWriterSpec::run(ProcessingContext& pc) szCTF += processDet(pc, DetID::FDD, header, mCTFTreeOut.get()); szCTF += processDet(pc, DetID::CTP, header, mCTFTreeOut.get()); if (mReportInterval > 0 && (mTimingInfo.tfCounter % mReportInterval) == 0) { - LOGP(important, "CTF {} size report:{}", mTimingInfo.tfCounter, mSizeReport); + LOGP(important, "CTF {} size report:{} - Total:{}", mTimingInfo.tfCounter, mSizeReport, fmt::group_digits(szCTF)); } mTimer.Stop(); From a72955188d25bac4cc3a10412f4510935137c6f8 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Oct 2023 20:54:42 +0200 Subject: [PATCH 222/324] dpl-workflow: enable size-report for raw-proxy, and downscale in online mode --- prodtests/full-system-test/dpl-workflow.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 6d970c6f905eb..40a290e918ef4 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -399,7 +399,13 @@ if [[ ! -z $INPUT_DETECTOR_LIST ]]; then done done [[ ! -z ${TIMEFRAME_RATE_LIMIT:-} ]] && [[ $TIMEFRAME_RATE_LIMIT != 0 ]] && PROXY_CHANNEL+=";name=metric-feedback,type=pull,method=connect,address=ipc://${UDS_PREFIX}metric-feedback-${O2JOBID:-$NUMAID},transport=shmem,rateLogging=0" - add_W o2-dpl-raw-proxy "--dataspec \"$PROXY_INSPEC\" --inject-missing-data --readout-proxy \"--channel-config \\\"$PROXY_CHANNEL\\\"\" ${TIMEFRAME_SHM_LIMIT+--timeframes-shm-limit} ${TIMEFRAME_SHM_LIMIT:-}" "" 0 + if [[ $EPNSYNCMODE == 1 ]]; then + RAWPROXY_CONFIG="--print-input-sizes 1000" + else + RAWPROXY_CONFIG="--print-input-sizes 1" + fi + + add_W o2-dpl-raw-proxy "--dataspec \"$PROXY_INSPEC\" --inject-missing-data $RAWPROXY_CONFIG --readout-proxy \"--channel-config \\\"$PROXY_CHANNEL\\\"\" ${TIMEFRAME_SHM_LIMIT+--timeframes-shm-limit} ${TIMEFRAME_SHM_LIMIT:-}" "" 0 elif [[ $DIGITINPUT == 1 ]]; then [[ $NTIMEFRAMES != 1 ]] && { echo "Digit input works only with NTIMEFRAMES=1" 1>&2; exit 1; } DISABLE_DIGIT_ROOT_INPUT= From c476aee39000ea2b0d7bb257e1dc7074ea9d88b4 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Oct 2023 21:17:53 +0200 Subject: [PATCH 223/324] DPL: Fix injectMissingData not always marking all inactive pipelines as present when exiting early due to allFound --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index bca734375895d..5568848405fb1 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -279,10 +279,6 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve LOG(error) << "unexpected nullptr found. Skipping message pair."; continue; } - // Copy the DataProcessingHeader from the first message. - if (dph == nullptr) { - dph = o2::header::get(parts.At(msgidx)->GetData()); - } if (!dh) { LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataHeader missing"; if (msgidx > 0) { @@ -296,6 +292,15 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve doPrintSizes = 0; } } + // Copy the DataProcessingHeader from the first message. + if (dph == nullptr) { + dph = o2::header::get(parts.At(msgidx)->GetData()); + for (size_t pi = 0; pi < present.size(); ++pi) { + if (routes[pi].timeslice != (dph->startTime % routes[pi].maxTimeslices)) { + present[pi] = true; + } + } + } for (size_t pi = 0; pi < present.size(); ++pi) { if (present[pi] && !doPrintSizes) { continue; From 78a350c41a39819b25b97a81a6e5251787813c1a Mon Sep 17 00:00:00 2001 From: mfasel Date: Thu, 5 Oct 2023 11:56:20 +0200 Subject: [PATCH 224/324] [EMCAL-1048] Consistent check fo RCU trailer and channel header integrity - RCU trailer must have a valid trailer marker, valid trailer version and the corresponding expected size of the trailer - Channel header must have a valid branch ID (0-1), FEC ID (0-9) and ALTRO ID (0,2,3,4) - Channel headers only accept if bit 30 is set and bit 31 is not set Treating corruptions in case of bitflip of bit 31 leading to an artificial interpretation of a RCU trailer word in case the word is the last word on the page, even though the payload continues on the next page. --- .../EMCAL/base/include/EMCALBase/RCUTrailer.h | 5 ++ Detectors/EMCAL/base/src/RCUTrailer.cxx | 23 +++++++++ .../EMCALReconstruction/AltroDecoder.h | 8 ++- .../EMCAL/reconstruction/src/AltroDecoder.cxx | 50 ++++++++++++++++--- .../reconstruction/src/RawReaderMemory.cxx | 2 +- .../test/testMinorAltroDecodingError.cxx | 10 ++-- 6 files changed, 86 insertions(+), 12 deletions(-) diff --git a/Detectors/EMCAL/base/include/EMCALBase/RCUTrailer.h b/Detectors/EMCAL/base/include/EMCALBase/RCUTrailer.h index ca82e60aa33ab..0fcb87f20f2ff 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/RCUTrailer.h +++ b/Detectors/EMCAL/base/include/EMCALBase/RCUTrailer.h @@ -388,6 +388,11 @@ class RCUTrailer /// are assigned based on the trailer word marker. static RCUTrailer constructFromPayloadWords(const gsl::span payloadwords); + /// \brief Check whether the word is a valid last trailer word + /// \param trailerword Word to be checked + /// \return True if the word is a valid last trailer word, false if there are inconsistencies + static bool checkLastTrailerWord(uint32_t trailerword); + private: /// \struct AltroConfig /// \brief Bit field configuration of the ALTRO config registers diff --git a/Detectors/EMCAL/base/src/RCUTrailer.cxx b/Detectors/EMCAL/base/src/RCUTrailer.cxx index 7cc54f188bc33..6d10d0cb93c1d 100644 --- a/Detectors/EMCAL/base/src/RCUTrailer.cxx +++ b/Detectors/EMCAL/base/src/RCUTrailer.cxx @@ -35,6 +35,29 @@ void RCUTrailer::reset() mIsInitialized = false; } +bool RCUTrailer::checkLastTrailerWord(uint32_t trailerword) +{ + const int MIN_FWVERSION = 2; + const int MAX_FWVERSION = 2; + if ((trailerword >> 30) != 3) { + return false; + } + auto firmwarevesion = (trailerword >> 16) & 0xFF; + auto trailerSize = (trailerword & 0x7F); + if (firmwarevesion < MIN_FWVERSION || firmwarevesion > MAX_FWVERSION) { + return false; + } + if (trailerSize < 2) { + return false; + } + if (firmwarevesion == 2) { + if (trailerSize < 9) { + return false; + } + } + return true; +} + void RCUTrailer::constructFromRawPayload(const gsl::span payloadwords) { reset(); diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h index e5a9c59158828..be661a105395d 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h @@ -156,6 +156,7 @@ class MinorAltroDecodingError /// \brief Error codes connected with the ALTRO decoding enum class ErrorType_t { BUNCH_HEADER_NULL, ///< Bunch header is 0 + CHANNEL_HEADER, ///< Channel header corruption CHANNEL_END_PAYLOAD_UNEXPECT, ///< Unexpected end of payload (channel or trailer word in bunch words) CHANNEL_PAYLOAD_EXCEED, ///< Exceeding channel payload block CHANNEL_ORDER, ///< Channels not in increasing order @@ -210,7 +211,7 @@ class MinorAltroDecodingError /// \brief Get the number of error types handled by the AltroDecoderError /// \return Number of error types - static constexpr int getNumberOfErrorTypes() noexcept { return 7; } + static constexpr int getNumberOfErrorTypes() noexcept { return 8; } /// \brief Get the name connected to the error type /// @@ -352,6 +353,11 @@ class AltroDecoder /// In case of failure an exception is thrown. void checkRCUTrailer(); + /// \brief Check hardware address in channel header for consistency + /// \param hwaddress Hardware address to check + /// \return True if the channel is consistent (branch, FEC and Altro in expected range) - false otherwise + bool checkChannelHWAddress(int hwaddress); + RawReaderMemory& mRawReader; ///< underlying raw reader RCUTrailer mRCUTrailer; ///< RCU trailer std::vector mChannels; ///< vector of channels in the raw stream diff --git a/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx b/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx index 1e0cdfc36003d..2adeac0122068 100644 --- a/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx +++ b/Detectors/EMCAL/reconstruction/src/AltroDecoder.cxx @@ -75,6 +75,13 @@ void AltroDecoder::readChannels() uint16_t payloadsize = (channelheader >> 16) & 0x3FF; bool badchannel = (channelheader >> 29) & 0x1; + // check hardware address for consistency + if (!checkChannelHWAddress(hwaddress)) { + // Inconsistent HW address information, channel header corrupted, payload must be skipped + mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::CHANNEL_ORDER, channelheader, currentword); + continue; + } + int currentfec = 10 * Channel::getBranchIndexFromHwAddress(hwaddress) + Channel::getFecIndexFromHwAddress(hwaddress); // std::cout << "Branch: " << Channel::getBranchIndexFromHwAddress(hwaddress) << ", FEC " << Channel::getFecIndexFromHwAddress(hwaddress) << " -> " << currentfec << " (channel " << Channel::getChannelIndexFromHwAddress(hwaddress) << " )" << std::endl; if (currentfec < lastFEC) { @@ -160,6 +167,23 @@ void AltroDecoder::readChannels() mChannelsInitialized = true; } +bool AltroDecoder::checkChannelHWAddress(int hwaddress) +{ + unsigned int branch = Channel::getBranchIndexFromHwAddress(hwaddress), + fec = Channel::getFecIndexFromHwAddress(hwaddress), + altro = Channel::getAltroIndexFromHwAddress(hwaddress); + if (branch > 1) { + return false; + } + if (fec > 9) { + return false; + } + if (!(altro == 0 || altro == 2 || altro == 3 || altro == 4)) { + return false; + } + return true; +} + const RCUTrailer& AltroDecoder::getRCUTrailer() const { if (!mRCUTrailer.isInitialized()) { @@ -354,18 +378,21 @@ int MinorAltroDecodingError::errorTypeToInt(MinorAltroErrType errortype) case MinorAltroErrType::CHANNEL_ORDER: errorNumber = 2; break; - case MinorAltroErrType::BUNCH_HEADER_NULL: + case MinorAltroErrType::CHANNEL_HEADER: errorNumber = 3; break; - case MinorAltroErrType::BUNCH_LENGTH_EXCEED: + case MinorAltroErrType::BUNCH_HEADER_NULL: errorNumber = 4; break; - case MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED: + case MinorAltroErrType::BUNCH_LENGTH_EXCEED: errorNumber = 5; break; - case MinorAltroErrType::BUNCH_STARTTIME: + case MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED: errorNumber = 6; break; + case MinorAltroErrType::BUNCH_STARTTIME: + errorNumber = 7; + break; }; return errorNumber; @@ -387,15 +414,18 @@ MinorAltroErrType MinorAltroDecodingError::intToErrorType(int errornumber) errorType = MinorAltroErrType::CHANNEL_ORDER; break; case 3: - errorType = MinorAltroErrType::BUNCH_HEADER_NULL; + errorType = MinorAltroErrType::CHANNEL_HEADER; break; case 4: - errorType = MinorAltroErrType::BUNCH_LENGTH_EXCEED; + errorType = MinorAltroErrType::BUNCH_HEADER_NULL; break; case 5: - errorType = MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED; + errorType = MinorAltroErrType::BUNCH_LENGTH_EXCEED; break; case 6: + errorType = MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED; + break; + case 7: errorType = MinorAltroErrType::BUNCH_STARTTIME; break; default: @@ -414,6 +444,8 @@ const char* MinorAltroDecodingError::getErrorTypeName(ErrorType_t errortype) return "ChannelPayloadExceed"; case MinorAltroErrType::CHANNEL_ORDER: return "ChannelOrderError"; + case MinorAltroErrType::CHANNEL_HEADER: + return "ChannelHeader"; case MinorAltroErrType::BUNCH_HEADER_NULL: return "BunchHeaderNull"; case MinorAltroErrType::BUNCH_LENGTH_EXCEED: @@ -435,6 +467,8 @@ const char* MinorAltroDecodingError::getErrorTypeTitle(ErrorType_t errortype) return "Channel exceed"; case MinorAltroErrType::CHANNEL_ORDER: return "FEC order"; + case MinorAltroErrType::CHANNEL_HEADER: + return "Channel header invalid"; case MinorAltroErrType::BUNCH_HEADER_NULL: return "Bunch header null"; case MinorAltroErrType::BUNCH_LENGTH_EXCEED: @@ -456,6 +490,8 @@ const char* MinorAltroDecodingError::getErrorTypeDescription(ErrorType_t errorty return "Trying to access out-of-bound payload!"; case MinorAltroErrType::CHANNEL_ORDER: return "Invalid FEC order"; + case MinorAltroErrType::CHANNEL_HEADER: + return "Invalid channel header"; case MinorAltroErrType::BUNCH_HEADER_NULL: return "Bunch header 0 or not configured!"; case MinorAltroErrType::BUNCH_LENGTH_EXCEED: diff --git a/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx b/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx index 977c55f7225d3..8ccbc5d63104a 100644 --- a/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx +++ b/Detectors/EMCAL/reconstruction/src/RawReaderMemory.cxx @@ -173,7 +173,7 @@ void RawReaderMemory::nextPage(bool doResetPayload) // The trailer is only decoded if the DDL is in the range of SRU DDLs. STU pages are propagated // 1-1 without trailer parsing auto lastword = *(mRawBuffer.getDataWords().rbegin()); - if (lastword >> 30 == 3) { + if (RCUTrailer::checkLastTrailerWord(lastword)) { // lastword is a trailer word // decode trailer and chop try { diff --git a/Detectors/EMCAL/reconstruction/test/testMinorAltroDecodingError.cxx b/Detectors/EMCAL/reconstruction/test/testMinorAltroDecodingError.cxx index 472954a90e6df..c14ab175f7bdf 100644 --- a/Detectors/EMCAL/reconstruction/test/testMinorAltroDecodingError.cxx +++ b/Detectors/EMCAL/reconstruction/test/testMinorAltroDecodingError.cxx @@ -23,10 +23,11 @@ namespace emcal BOOST_AUTO_TEST_CASE(MinorAltroDecodingError_test) { - BOOST_CHECK_EQUAL(MinorAltroDecodingError::getNumberOfErrorTypes(), 7); - std::array errornames = {{"ChannelEndPayloadUnexpected", + BOOST_CHECK_EQUAL(MinorAltroDecodingError::getNumberOfErrorTypes(), 8); + std::array errornames = {{"ChannelEndPayloadUnexpected", "ChannelPayloadExceed", "ChannelOrderError", + "ChannelHeader", "BunchHeaderNull", "BunchLengthExceed", "BunchLengthAllowExceed", @@ -34,6 +35,7 @@ BOOST_AUTO_TEST_CASE(MinorAltroDecodingError_test) errortitles = {{"Channel end unexpected", "Channel exceed", "FEC order", + "Channel header invalid", "Bunch header null", "Bunch length exceed", "Bunch length impossible", @@ -41,13 +43,15 @@ BOOST_AUTO_TEST_CASE(MinorAltroDecodingError_test) errordescriptions = {{"Unexpected end of payload in altro channel payload!", "Trying to access out-of-bound payload!", "Invalid FEC order", + "Invalid channel header", "Bunch header 0 or not configured!", "Bunch length exceeding channel payload size!", "Bunch length exceeding max. possible bunch size!", "Bunch start time outside range!"}}; - std::array errortypes = {{MinorAltroDecodingError::ErrorType_t::CHANNEL_END_PAYLOAD_UNEXPECT, + std::array errortypes = {{MinorAltroDecodingError::ErrorType_t::CHANNEL_END_PAYLOAD_UNEXPECT, MinorAltroDecodingError::ErrorType_t::CHANNEL_PAYLOAD_EXCEED, MinorAltroDecodingError::ErrorType_t::CHANNEL_ORDER, + MinorAltroDecodingError::ErrorType_t::CHANNEL_HEADER, MinorAltroDecodingError::ErrorType_t::BUNCH_HEADER_NULL, MinorAltroDecodingError::ErrorType_t::BUNCH_LENGTH_EXCEED, MinorAltroDecodingError::ErrorType_t::BUNCH_LENGTH_ALLOW_EXCEED, From 9331ea387bc8f3c0fe1b977c4aa41ed3360054dc Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Thu, 5 Oct 2023 13:01:09 +0200 Subject: [PATCH 225/324] SVertexer: use mean vertex Signed-off-by: Felix Schlepper --- .../src/SecondaryVertexingSpec.cxx | 10 ++++++++++ .../include/DetectorsVertexing/SVertexer.h | 14 ++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx index f2dc738891b62..bd454678d6cc1 100644 --- a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx @@ -12,6 +12,8 @@ /// @file SecondaryVertexingSpec.cxx #include +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "Framework/CCDBParamSpec.h" #include "ReconstructionDataFormats/Decay3Body.h" #include "DataFormatsGlobalTracking/RecoContainer.h" #include "ReconstructionDataFormats/TrackTPCITS.h" @@ -135,6 +137,11 @@ void SecondaryVertexingSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* ob mStrTracker.setClusterDictionary((const o2::itsmft::TopologyDictionary*)obj); return; } + if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) { + LOG(info) << "Imposing new MeanVertex: " << ((const o2::dataformats::MeanVertexObject*)obj)->asString(); + mVertexer.setMeanVertex((const o2::dataformats::MeanVertexObject*)obj); + return; + } } void SecondaryVertexingSpec::updateTimeDependentParams(ProcessingContext& pc) @@ -179,6 +186,8 @@ void SecondaryVertexingSpec::updateTimeDependentParams(ProcessingContext& pc) mStrTracker.setupFitters(); } } + + pc.inputs().get("meanvtx"); } DataProcessorSpec getSecondaryVertexingSpec(GTrackID::mask_t src, bool enableCasc, bool enable3body, bool enableStrangenesTracking, bool useMC) @@ -195,6 +204,7 @@ DataProcessorSpec getSecondaryVertexingSpec(GTrackID::mask_t src, bool enableCas } dataRequest->requestTracks(src, useMC); dataRequest->requestPrimaryVertertices(useMC); + dataRequest->inputs.emplace_back("meanvtx", "GLO", "MEANVERTEX", 0, Lifetime::Condition, ccdbParamSpec("GLO/Calib/MeanVertex", {}, 1)); auto ggRequest = std::make_shared(false, // orbitResetTime true, // GRPECS=true false, // GRPLHCIF diff --git a/Detectors/Vertexing/include/DetectorsVertexing/SVertexer.h b/Detectors/Vertexing/include/DetectorsVertexing/SVertexer.h index 49eb6670eae94..a10ff3d1b0f30 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/SVertexer.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/SVertexer.h @@ -16,6 +16,7 @@ #define O2_S_VERTEXER_H #include "gsl/span" +#include "DataFormatsCalibration/MeanVertexObject.h" #include "DataFormatsGlobalTracking/RecoContainer.h" #include "ReconstructionDataFormats/PrimaryVertex.h" #include "ReconstructionDataFormats/V0.h" @@ -49,8 +50,6 @@ class CorrectionMapsHelper; namespace vertexing { -namespace o2d = o2::dataformats; - class SVertexer { public: @@ -112,7 +111,14 @@ class SVertexer int getN3Bodies() const { return mN3Bodies; } int getNStrangeTracks() const { return mNStrangeTracks; } auto& getMeanVertex() const { return mMeanVertex; } - void setMeanVertex(const o2d::VertexBase& v) { mMeanVertex = v; } + void setMeanVertex(const o2::dataformats::MeanVertexObject* v) + { + if (v == nullptr) { + return; + } + mMeanVertex = v->getMeanVertex(); + } + void setNThreads(int n); int getNThreads() const { return mNThreads; } void setUseMC(bool v) { mUseMC = v; } @@ -161,7 +167,7 @@ class SVertexer std::array, 2> mTracksPool{}; // pools of positive and negative seeds sorted in min VtxID std::array, 2> mVtxFirstTrack{}; // 1st pos. and neg. track of the pools for each vertex - o2d::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; + o2::dataformats::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; const SVertexerParams* mSVParams = nullptr; std::array mV0Hyps; std::array mCascHyps; From e027deb15bdfa988ee0388eda05c62184bc39f69 Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Thu, 5 Oct 2023 10:31:01 +0200 Subject: [PATCH 226/324] [EMCAL-791] Require CCDB access for EMCAL digitizer EMCAL sim params should be handled via the CCDB, therefore CCDB access is required for EMCAL. --- prodtests/full_system_test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prodtests/full_system_test.sh b/prodtests/full_system_test.sh index b8017172d929c..3497229bc480f 100755 --- a/prodtests/full_system_test.sh +++ b/prodtests/full_system_test.sh @@ -140,7 +140,7 @@ taskwrapper sim.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} --seed $O2SIMSEED if [[ $DO_EMBEDDING == 1 ]]; then taskwrapper embed.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} -j $NJOBS --run ${RUNNUMBER} -n $NEvents -g pythia8pp -e ${FST_MC_ENGINE} -o sig --configKeyValues ${FST_EMBEDDING_CONFIG} --embedIntoFile o2sim_Kine.root fi -taskwrapper digi.log o2-sim-digitizer-workflow -n $NEvents ${DIGIQED} ${NOMCLABELS} --sims ${SIM_SOURCES} --tpc-lanes $((NJOBS < 36 ? NJOBS : 36)) --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} ${DIGITOPT} --configKeyValues "\"${DIGITOPTKEY}\"" --interactionRate $FST_COLRATE +taskwrapper digi.log o2-sim-digitizer-workflow -n $NEvents ${DIGIQED} ${NOMCLABELS} --sims ${SIM_SOURCES} --tpc-lanes $((NJOBS < 36 ? NJOBS : 36)) --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} ${DIGITOPT} --configKeyValues "\"${DIGITOPTKEY}\"" --interactionRate $FST_COLRATE --use-ccdb-emc [[ $SPLITTRDDIGI == "1" ]] && taskwrapper digiTRD.log o2-sim-digitizer-workflow -n $NEvents ${NOMCLABELS} --onlyDet TRD --trd-digit-downscaling ${DIGITDOWNSCALINGTRD} --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} --incontext collisioncontext.root --configKeyValues "\"${DIGITOPTKEYTRD}\"" touch digiTRD.log_done From d286ca76c2bbc065757e37a228fa1d8dd35ba1e2 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 6 Oct 2023 10:08:32 +0200 Subject: [PATCH 227/324] ITS3: Add macros for Cluster Size, Hits and Digits (#11835) Signed-off-by: Felix Schlepper --- .../Upgrades/ITS3/macros/test/CMakeLists.txt | 48 ++ .../ITS3/macros/test/CheckClusterSize.C | 420 ++++++++++++++++ .../ITS3/macros/test/CheckDigitsDensity.C | 356 +++++++++++++ .../Upgrades/ITS3/macros/test/CheckHits.C | 466 ++++++++++++++++++ .../ITS3/macros/test/CompareClusterSize.C | 122 +++++ 5 files changed, 1412 insertions(+) create mode 100755 Detectors/Upgrades/ITS3/macros/test/CheckClusterSize.C create mode 100755 Detectors/Upgrades/ITS3/macros/test/CheckDigitsDensity.C create mode 100644 Detectors/Upgrades/ITS3/macros/test/CheckHits.C create mode 100755 Detectors/Upgrades/ITS3/macros/test/CompareClusterSize.C diff --git a/Detectors/Upgrades/ITS3/macros/test/CMakeLists.txt b/Detectors/Upgrades/ITS3/macros/test/CMakeLists.txt index ea24aa43b1561..6f6ac2945fd0d 100644 --- a/Detectors/Upgrades/ITS3/macros/test/CMakeLists.txt +++ b/Detectors/Upgrades/ITS3/macros/test/CMakeLists.txt @@ -82,3 +82,51 @@ o2_add_test_root_macro(buildMatBudLUT.C O2::SimulationDataFormat O2::DetectorsBase LABELS its3) + +o2_add_test_root_macro(CheckHits.C + PUBLIC_LINK_LIBRARIES O2::ITSBase + O2::ITS3Base + O2::ITSMFTBase + O2::ITSMFTSimulation + O2::ITS3Simulation + O2::ITS3Reconstruction + O2::MathUtils + O2::SimulationDataFormat + O2::DetectorsBase + LABELS its3) + +o2_add_test_root_macro(CheckDigitsDensity.C + PUBLIC_LINK_LIBRARIES O2::ITSBase + O2::ITS3Base + O2::ITSMFTBase + O2::ITSMFTSimulation + O2::ITS3Simulation + O2::ITS3Reconstruction + O2::MathUtils + O2::SimulationDataFormat + O2::DetectorsBase + LABELS its3) + +o2_add_test_root_macro(CheckClusterSize.C + PUBLIC_LINK_LIBRARIES O2::ITSBase + O2::ITS3Base + O2::ITSMFTBase + O2::ITSMFTSimulation + O2::ITS3Simulation + O2::ITS3Reconstruction + O2::MathUtils + O2::SimulationDataFormat + O2::DetectorsBase + LABELS its3) + +o2_add_test_root_macro(CompareClusterSize.C + PUBLIC_LINK_LIBRARIES O2::ITSBase + O2::ITS3Base + O2::ITSMFTBase + O2::ITSMFTSimulation + O2::ITS3Simulation + O2::ITS3Reconstruction + O2::MathUtils + O2::SimulationDataFormat + O2::DetectorsBase + LABELS its3) diff --git a/Detectors/Upgrades/ITS3/macros/test/CheckClusterSize.C b/Detectors/Upgrades/ITS3/macros/test/CheckClusterSize.C new file mode 100755 index 0000000000000..cd69cb9c2cf3c --- /dev/null +++ b/Detectors/Upgrades/ITS3/macros/test/CheckClusterSize.C @@ -0,0 +1,420 @@ +// Copyright 2020-2022 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CheckClusterSize.C +/// \brief analyze ITS3 cluster sizes +/// \dependencies CreateDictionariesITS3.C +/// \author felix.schlepper@cern.ch + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define ENABLE_UPGRADES +#include "DataFormatsITS3/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsCommonDataFormats/DetectorNameConf.h" +#include "ITS3Reconstruction/TopologyDictionary.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCEventHeader.h" +#include "SimulationDataFormat/MCTrack.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#endif + +static constexpr int nLayers = 4; // 3 Layers + 1 combined outer layer + +struct ParticleInfo { + int event{}; + int pdg{}; + double pt{}; + double eta{}; + double phi{}; + bool isPrimary{false}; +}; + +using o2::its3::CompClusterExt; +using ROFRec = o2::itsmft::ROFRecord; + +void checkFile(const std::unique_ptr& file); + +inline auto hist_map(unsigned short id) +{ + return std::clamp(id, static_cast(0), static_cast(6)) / 2; +} + +void CheckClusterSize(std::string clusFileName = "o2clus_it3.root", + std::string kineFileName = "o2sim_Kine.root", + std::string dictFileName = "", bool batch = true) +{ + gROOT->SetBatch(batch); + TStopwatch sw; + sw.Start(); + // TopologyDictionary + if (dictFileName.empty()) { + dictFileName = + o2::base::DetectorNameConf::getAlpideClusterDictionaryFileName( + o2::detectors::DetID::IT3, "", "root"); + } + o2::its3::TopologyDictionary dict; + std::ifstream file(dictFileName.c_str()); + if (file.good()) { + LOG(info) << "Running with dictionary: " << dictFileName.c_str(); + dict.readFromFile(dictFileName); + } else { + LOG(info) << "Running without dictionary !"; + } + + // Histograms + constexpr int maxClusterSize = 50; + TH1F hOuterBarrel("outerbarrel", "ClusterSize in OuterBarrel", maxClusterSize, 0, maxClusterSize); + std::vector hPrimary; + std::vector hPrimaryEta; + std::vector hPrimaryPt; + std::vector hPrimaryPhi; + std::vector hSecondary; + std::vector hSecondaryEta; + std::vector hSecondaryPt; + std::vector hSecondaryPhi; + std::vector hProtonPrimary; + std::vector hProtonPrimaryEta; + std::vector hProtonPrimaryPt; + std::vector hProtonPrimaryPhi; + std::vector hProtonSecondary; + std::vector hProtonSecondaryEta; + std::vector hProtonSecondaryPt; + std::vector hProtonSecondaryPhi; + std::vector hPionPrimary; + std::vector hPionPrimaryEta; + std::vector hPionPrimaryPt; + std::vector hPionPrimaryPhi; + std::vector hPionSecondary; + std::vector hPionSecondaryEta; + std::vector hPionSecondaryPt; + std::vector hPionSecondaryPhi; + std::vector hKaonPrimary; + std::vector hKaonPrimaryEta; + std::vector hKaonPrimaryPt; + std::vector hKaonPrimaryPhi; + std::vector hKaonSecondary; + std::vector hKaonSecondaryEta; + std::vector hKaonSecondaryPt; + std::vector hKaonSecondaryPhi; + std::vector hOtherPrimary; + std::vector hOtherPrimaryEta; + std::vector hOtherPrimaryPt; + std::vector hOtherPrimaryPhi; + std::vector hOtherSecondary; + std::vector hOtherSecondaryEta; + std::vector hOtherSecondaryPt; + std::vector hOtherSecondaryPhi; + for (int i = 0; i < 4; ++i) { + hPrimary.emplace_back(Form("primary/L%d", i), Form("L%d Primary Cluster Size", i), maxClusterSize, 0, maxClusterSize); + hPrimaryEta.emplace_back(Form("primary/EtaL%d", i), Form("L%d Primary Cluster Size vs Eta", i), maxClusterSize, 0, maxClusterSize, 100, -3.0, 3.0); + hPrimaryPt.emplace_back(Form("primary/Pt%d", i), Form("L%d Primary Cluster Size vs Pt", i), maxClusterSize, 0, maxClusterSize, 100, 0.0, 10.0); + hPrimaryPhi.emplace_back(Form("primary/Phi%d", i), Form("L%d Primary Cluster Size vs Phi", i), maxClusterSize, 0, maxClusterSize, 100, 0., 2 * o2::constants::math::PI); + hSecondary.emplace_back(Form("seconday/L%d", i), Form("L%d Secondary Cluster Size", i), maxClusterSize, 0, maxClusterSize); + hSecondaryEta.emplace_back(Form("seconday/EtaL%d", i), Form("L%d Secondary Cluster Size vs Eta", i), maxClusterSize, 0, maxClusterSize, 100, -3.0, 3.0); + hSecondaryPt.emplace_back(Form("seconday/Pt%d", i), Form("L%d Secondary Cluster Size vs Pt", i), maxClusterSize, 0, maxClusterSize, 100, 0.0, 10.0); + hSecondaryPhi.emplace_back(Form("seconday/Phi%d", i), Form("L%d Secondary Cluster Size vs Phi", i), maxClusterSize, 0, maxClusterSize, 100, 0., 2 * o2::constants::math::PI); + + hProtonPrimary.emplace_back(Form("proton/primary/L%d", i), Form("Proton - L%d Primary Cluster Size", i), maxClusterSize, 0, maxClusterSize); + hProtonPrimaryEta.emplace_back(Form("proton/primary/EtaL%d", i), Form("Proton - L%d Primary Cluster Size vs Eta", i), maxClusterSize, 0, maxClusterSize, 100, -3.0, 3.0); + hProtonPrimaryPt.emplace_back(Form("proton/primary/Pt%d", i), Form("Proton - L%d Primary Cluster Size vs Pt", i), maxClusterSize, 0, maxClusterSize, 100, 0.0, 10.0); + hProtonPrimaryPhi.emplace_back(Form("proton/primary/Phi%d", i), Form("Proton - L%d Primary Cluster Size vs Phi", i), maxClusterSize, 0, maxClusterSize, 100, 0., 2 * o2::constants::math::PI); + hProtonSecondary.emplace_back(Form("proton/seconday/L%d", i), Form("Proton - L%d Secondary Cluster Size", i), maxClusterSize, 0, maxClusterSize); + hProtonSecondaryEta.emplace_back(Form("proton/seconday/EtaL%d", i), Form("Proton - L%d Secondary Cluster Size vs Eta", i), maxClusterSize, 0, maxClusterSize, 100, -3.0, 3.0); + hProtonSecondaryPt.emplace_back(Form("proton/seconday/Pt%d", i), Form("Proton - L%d Secondary Cluster Size vs Pt", i), maxClusterSize, 0, maxClusterSize, 100, 0.0, 10.0); + hProtonSecondaryPhi.emplace_back(Form("proton/seconday/Phi%d", i), Form("Proton - L%d Secondary Cluster Size vs Phi", i), maxClusterSize, 0, maxClusterSize, 100, 0., 2 * o2::constants::math::PI); + + hPionPrimary.emplace_back(Form("pion/primary/L%d", i), Form("Pion- L%d Primary Cluster Size", i), maxClusterSize, 0, maxClusterSize); + hPionPrimaryEta.emplace_back(Form("pion/primary/EtaL%d", i), Form("Pion- L%d Primary Cluster Size vs Eta", i), maxClusterSize, 0, maxClusterSize, 100, -3.0, 3.0); + hPionPrimaryPt.emplace_back(Form("pion/primary/Pt%d", i), Form("Pion- L%d Primary Cluster Size vs Pt", i), maxClusterSize, 0, maxClusterSize, 100, 0.0, 10.0); + hPionPrimaryPhi.emplace_back(Form("pion/primary/Phi%d", i), Form("Pion- L%d Primary Cluster Size vs Phi", i), maxClusterSize, 0, maxClusterSize, 100, 0., 2 * o2::constants::math::PI); + hPionSecondary.emplace_back(Form("pion/seconday/L%d", i), Form("Pion- L%d Secondary Cluster Size", i), maxClusterSize, 0, maxClusterSize); + hPionSecondaryEta.emplace_back(Form("pion/seconday/EtaL%d", i), Form("Pion- L%d Secondary Cluster Size vs Eta", i), maxClusterSize, 0, maxClusterSize, 100, -3.0, 3.0); + hPionSecondaryPt.emplace_back(Form("pion/seconday/Pt%d", i), Form("Pion- L%d Secondary Cluster Size vs Pt", i), maxClusterSize, 0, maxClusterSize, 100, 0.0, 10.0); + hPionSecondaryPhi.emplace_back(Form("pion/seconday/Phi%d", i), Form("Pion- L%d Secondary Cluster Size vs Phi", i), maxClusterSize, 0, maxClusterSize, 100, 0., 2 * o2::constants::math::PI); + + hKaonPrimary.emplace_back(Form("kaon/primary/L%d", i), Form("Kaon- L%d Primary Cluster Size", i), maxClusterSize, 0, maxClusterSize); + hKaonPrimaryEta.emplace_back(Form("kaon/primary/EtaL%d", i), Form("Kaon- L%d Primary Cluster Size vs Eta", i), maxClusterSize, 0, maxClusterSize, 100, -3.0, 3.0); + hKaonPrimaryPt.emplace_back(Form("kaon/primary/Pt%d", i), Form("Kaon- L%d Primary Cluster Size vs Pt", i), maxClusterSize, 0, maxClusterSize, 100, 0.0, 10.0); + hKaonPrimaryPhi.emplace_back(Form("kaon/primary/Phi%d", i), Form("Kaon- L%d Primary Cluster Size vs Phi", i), maxClusterSize, 0, maxClusterSize, 100, 0., 2 * o2::constants::math::PI); + hKaonSecondary.emplace_back(Form("kaon/seconday/L%d", i), Form("Kaon- L%d Secondary Cluster Size", i), maxClusterSize, 0, maxClusterSize); + hKaonSecondaryEta.emplace_back(Form("kaon/seconday/EtaL%d", i), Form("Kaon- L%d Secondary Cluster Size vs Eta", i), maxClusterSize, 0, maxClusterSize, 100, -3.0, 3.0); + hKaonSecondaryPt.emplace_back(Form("kaon/seconday/Pt%d", i), Form("Kaon- L%d Secondary Cluster Size vs Pt", i), maxClusterSize, 0, maxClusterSize, 100, 0.0, 10.0); + hKaonSecondaryPhi.emplace_back(Form("kaon/seconday/Phi%d", i), Form("Kaon- L%d Secondary Cluster Size vs Phi", i), maxClusterSize, 0, maxClusterSize, 100, 0., 2 * o2::constants::math::PI); + + hOtherPrimary.emplace_back(Form("other/primary/L%d", i), Form("Other - L%d Primary Cluster Size", i), maxClusterSize, 0, maxClusterSize); + hOtherPrimaryEta.emplace_back(Form("other/primary/EtaL%d", i), Form("Other - L%d Primary Cluster Size vs Eta", i), maxClusterSize, 0, maxClusterSize, 100, -3.0, 3.0); + hOtherPrimaryPt.emplace_back(Form("other/primary/Pt%d", i), Form("Other - L%d Primary Cluster Size vs Pt", i), maxClusterSize, 0, maxClusterSize, 100, 0.0, 10.0); + hOtherPrimaryPhi.emplace_back(Form("other/primary/Phi%d", i), Form("Other - L%d Primary Cluster Size vs Phi", i), maxClusterSize, 0, maxClusterSize, 100, 0., 2 * o2::constants::math::PI); + hOtherSecondary.emplace_back(Form("other/seconday/L%d", i), Form("Other - L%d Secondary Cluster Size", i), maxClusterSize, 0, maxClusterSize); + hOtherSecondaryEta.emplace_back(Form("other/seconday/EtaL%d", i), Form("Other - L%d Secondary Cluster Size vs Eta", i), maxClusterSize, 0, maxClusterSize, 100, -3.0, 3.0); + hOtherSecondaryPt.emplace_back(Form("other/seconday/Pt%d", i), Form("Other - L%d Secondary Cluster Size vs Pt", i), maxClusterSize, 0, maxClusterSize, 100, 0.0, 10.0); + hOtherSecondaryPhi.emplace_back(Form("other/seconday/Phi%d", i), Form("Other - L%d Secondary Cluster Size vs Phi", i), maxClusterSize, 0, maxClusterSize, 100, 0., 2 * o2::constants::math::PI); + } + + // Clusters + std::unique_ptr clusFile(TFile::Open(clusFileName.data())); + checkFile(clusFile); + auto clusTree = clusFile->Get("o2sim"); + std::vector clusArr; + std::vector* clusArrP{&clusArr}; + clusTree->SetBranchAddress("IT3ClusterComp", &clusArrP); + std::vector patterns; + std::vector* patternsPtr{&patterns}; + clusTree->SetBranchAddress("IT3ClusterPatt", &patternsPtr); + + // MC tracks + std::unique_ptr kineFile(TFile::Open(kineFileName.data())); + checkFile(kineFile); + auto mcTree = kineFile->Get("o2sim"); + mcTree->SetBranchStatus("*", false); // disable all branches + mcTree->SetBranchStatus("MCTrack*", true); + mcTree->SetBranchStatus("MCEventHeader*", true); + + std::vector mcArr; + std::vector* mcArrP{&mcArr}; + mcTree->SetBranchAddress("MCTrack", &mcArrP); + o2::dataformats::MCEventHeader* mcEvent = nullptr; + mcTree->SetBranchAddress("MCEventHeader.", &mcEvent); + + // Cluster MC labels + o2::dataformats::MCTruthContainer* clusLabArr = nullptr; + clusTree->SetBranchAddress("IT3ClusterMCTruth", &clusLabArr); + + std::cout << "** Filling particle table ... " << std::flush; + int lastEventIDcl = -1; + auto nev = mcTree->GetEntriesFast(); + std::vector> info(nev); + for (int iEntry = 0; mcTree->LoadTree(iEntry) >= 0; ++iEntry) { // loop over MC events + mcTree->GetEvent(iEntry); + info[iEntry].resize(mcArr.size()); + for (unsigned int mcI{0}; mcI < mcArr.size(); ++mcI) { + const auto part = mcArr[mcI]; + info[iEntry][mcI].event = iEntry; + info[iEntry][mcI].pdg = std::abs(part.GetPdgCode()); + info[iEntry][mcI].pt = part.GetPt(); + info[iEntry][mcI].phi = part.GetPhi(); + info[iEntry][mcI].eta = part.GetEta(); + if (std::sqrt(part.GetStartVertexCoordinatesX() * part.GetStartVertexCoordinatesX() + part.GetStartVertexCoordinatesY() * part.GetStartVertexCoordinatesY()) < 0.1) { + info[iEntry][mcI].isPrimary = true; + } + } + } + std::cout << " done." << std::endl; + + // ROFrecords + std::vector rofRecVec; + std::vector* rofRecVecP{&rofRecVec}; + clusTree->SetBranchAddress("IT3ClustersROF", &rofRecVecP); + clusTree->GetEntry(0); + int nROFRec = (int)rofRecVec.size(); + auto pattIt = patternsPtr->cbegin(); + + for (int irof = 0; irof < nROFRec; irof++) { + const auto& rofRec = rofRecVec[irof]; + // rofRec.print(); + + for (int icl = 0; icl < rofRec.getNEntries(); icl++) { + int clEntry = rofRec.getFirstEntry() + icl; + const auto& cluster = clusArr[clEntry]; + // cluster.print(); + + auto pattId = cluster.getPatternID(); + auto id = cluster.getSensorID(); + int clusterSize{-1}; + if (pattId == o2::its3::CompCluster::InvalidPatternID || + dict.isGroup(pattId)) { + o2::itsmft::ClusterPattern patt(pattIt); + clusterSize = patt.getNPixels(); + } else { + clusterSize = dict.getNpixels(pattId); + } + + const auto& label = (clusLabArr->getLabels(clEntry))[0]; + if (!label.isValid() || label.getSourceID() != 0 || !label.isCorrect()) { + continue; + } + + const int trackID = label.getTrackID(); + int evID = label.getEventID(); + const auto& pInfo = info[evID][trackID]; + if (id > 6) { + hOuterBarrel.Fill(clusterSize); + } + + if (pInfo.isPrimary) { + hPrimary[hist_map(id)].Fill(clusterSize); + hPrimaryEta[hist_map(id)].Fill(clusterSize, pInfo.eta); + hPrimaryPt[hist_map(id)].Fill(clusterSize, pInfo.pt); + hPrimaryPhi[hist_map(id)].Fill(clusterSize, pInfo.phi); + } else { + hSecondary[hist_map(id)].Fill(clusterSize); + hSecondaryEta[hist_map(id)].Fill(clusterSize, pInfo.eta); + hSecondaryPt[hist_map(id)].Fill(clusterSize, pInfo.pt); + hSecondaryPhi[hist_map(id)].Fill(clusterSize, pInfo.phi); + } + if (pInfo.pdg == kProton) { + if (pInfo.isPrimary) { + hProtonPrimary[hist_map(id)].Fill(clusterSize); + hProtonPrimaryEta[hist_map(id)].Fill(clusterSize, pInfo.eta); + hProtonPrimaryPt[hist_map(id)].Fill(clusterSize, pInfo.pt); + hProtonPrimaryPhi[hist_map(id)].Fill(clusterSize, pInfo.phi); + } else { + hProtonSecondary[hist_map(id)].Fill(clusterSize); + hProtonSecondaryEta[hist_map(id)].Fill(clusterSize, pInfo.eta); + hProtonSecondaryPt[hist_map(id)].Fill(clusterSize, pInfo.pt); + hProtonSecondaryPhi[hist_map(id)].Fill(clusterSize, pInfo.phi); + } + } else if (pInfo.pdg == kPiPlus) { + if (pInfo.isPrimary) { + hProtonPrimary[hist_map(id)].Fill(clusterSize); + hProtonPrimaryEta[hist_map(id)].Fill(clusterSize, pInfo.eta); + hProtonPrimaryPt[hist_map(id)].Fill(clusterSize, pInfo.pt); + hProtonPrimaryPhi[hist_map(id)].Fill(clusterSize, pInfo.phi); + } else { + hPionSecondary[hist_map(id)].Fill(clusterSize); + hPionSecondaryEta[hist_map(id)].Fill(clusterSize, pInfo.eta); + hPionSecondaryPt[hist_map(id)].Fill(clusterSize, pInfo.pt); + hPionSecondaryPhi[hist_map(id)].Fill(clusterSize, pInfo.phi); + } + } else if (pInfo.pdg == kKPlus) { + if (pInfo.isPrimary) { + hKaonPrimary[hist_map(id)].Fill(clusterSize); + hKaonPrimaryEta[hist_map(id)].Fill(clusterSize, pInfo.eta); + hKaonPrimaryPt[hist_map(id)].Fill(clusterSize, pInfo.pt); + hKaonPrimaryPhi[hist_map(id)].Fill(clusterSize, pInfo.phi); + } else { + hKaonSecondary[hist_map(id)].Fill(clusterSize); + hKaonSecondaryEta[hist_map(id)].Fill(clusterSize, pInfo.eta); + hKaonSecondaryPt[hist_map(id)].Fill(clusterSize, pInfo.pt); + hKaonSecondaryPhi[hist_map(id)].Fill(clusterSize, pInfo.phi); + } + } else { + if (pInfo.isPrimary) { + hOtherPrimary[hist_map(id)].Fill(clusterSize); + hOtherPrimaryEta[hist_map(id)].Fill(clusterSize, pInfo.eta); + hOtherPrimaryPt[hist_map(id)].Fill(clusterSize, pInfo.pt); + hOtherPrimaryPhi[hist_map(id)].Fill(clusterSize, pInfo.phi); + } else { + hOtherSecondary[hist_map(id)].Fill(clusterSize); + hOtherSecondaryEta[hist_map(id)].Fill(clusterSize, pInfo.eta); + hOtherSecondaryPt[hist_map(id)].Fill(clusterSize, pInfo.pt); + hOtherSecondaryPhi[hist_map(id)].Fill(clusterSize, pInfo.phi); + } + } + } + } + std::cout << "Done measuring cluster sizes:" << std::endl; + for (int i = 0; i < nLayers; ++i) { + std::cout << "* Layer " << i << ":\n"; + std::cout << "** Primary " << hPrimary[i].GetMean() << " +/- " << hPrimary[i].GetRMS() << "\n"; + std::cout << "** Secondary " << hSecondary[i].GetMean() << " +/- " << hSecondary[i].GetRMS() << std::endl; + } + std::unique_ptr oFile( + TFile::Open("checkClusterSize.root", "RECREATE")); + checkFile(oFile); + + char const* name[nLayers] = {"L0", "L1", "L2", "OuterBarrel"}; + const double delta = 0.2; + double x[nLayers], xP[nLayers], xS[nLayers], yP[nLayers], yS[nLayers], vyP[nLayers], vyS[nLayers]; + for (int i = 0; i < nLayers; ++i) { + x[i] = i; + xP[i] = i - delta; + xS[i] = i + delta; + yP[i] = hPrimary[i].GetMean(); + vyP[i] = hPrimary[i].GetRMS(); + yS[i] = hSecondary[i].GetMean(); + vyS[i] = hSecondary[i].GetRMS(); + } + + auto c1 = new TCanvas("c1", "A Simple Graph Example", 200, 10, 700, 500); + auto h = new TH1F("h", "", nLayers, x[0] - 0.5, x[nLayers - 1] + 0.5); + h->SetTitle("Cluster Sizes"); + h->GetYaxis()->SetTitleOffset(1.); + h->GetXaxis()->SetTitleOffset(1.); + h->GetYaxis()->SetTitle("cluster size"); + h->GetXaxis()->SetTitle("Layer"); + h->GetXaxis()->SetNdivisions(-10); + for (int i = 1; i <= nLayers; i++) + h->GetXaxis()->SetBinLabel(i, name[i - 1]); + h->SetMaximum(20); + h->SetMinimum(0); + h->SetStats(false); + h->Draw(); + auto grP = new TGraphErrors(nLayers, xP, yP, nullptr, vyP); + grP->SetMarkerStyle(4); + grP->SetMarkerSize(2); + grP->SetTitle("Primary"); + auto grS = new TGraphErrors(nLayers, xS, yS, nullptr, vyS); + grS->SetMarkerStyle(3); + grS->SetMarkerSize(2); + grS->SetTitle("Secondary"); + auto mg = new TMultiGraph("mg", ""); + mg->Add(grP); + mg->Add(grS); + mg->Draw("P pmc plc"); + auto leg = new TLegend(0.75, 0.75, 0.9, 0.9); + leg->AddEntry(grP); + leg->AddEntry(grS); + leg->Draw(); + c1->Write(); + c1->SaveAs("its3ClusterSize.pdf"); + for (const auto& hh : {hPrimary, hSecondary, hPionPrimary, hPionSecondary, hProtonPrimary, hProtonSecondary, hKaonPrimary, hKaonSecondary, hOtherPrimary, hOtherSecondary}) { + for (const auto& h : hh) { + h.Write(); + } + } + for (const auto& hh : {hPrimaryEta, hSecondaryEta, hPionPrimaryEta, hPionSecondaryEta, hProtonPrimaryEta, hProtonSecondaryEta, hKaonPrimaryEta, hKaonSecondaryEta, hOtherPrimaryEta, hOtherSecondaryEta}) { + for (const auto& h : hh) { + h.Write(); + } + } + for (const auto& hh : {hPrimaryPt, hSecondaryPt, hPionPrimaryPt, hPionSecondaryPt, hProtonPrimaryPt, hProtonSecondaryPt, hKaonPrimaryPt, hKaonSecondaryPt, hOtherPrimaryPt, hOtherSecondaryPt}) { + for (const auto& h : hh) { + h.Write(); + } + } + for (const auto& hh : {hPrimaryPhi, hSecondaryPhi, hPionPrimaryPhi, hPionSecondaryPhi, hProtonPrimaryPhi, hProtonSecondaryPhi, hKaonPrimaryPhi, hKaonSecondaryPhi, hOtherPrimaryPhi, hOtherSecondaryPhi}) { + for (const auto& h : hh) { + h.Write(); + } + } + hOuterBarrel.Write(); + sw.Stop(); + sw.Print(); +} + +void checkFile(const std::unique_ptr& file) +{ + if (!file || file->IsZombie()) { + printf("Could not open %s!\n", file->GetName()); + std::exit(1); + } +} diff --git a/Detectors/Upgrades/ITS3/macros/test/CheckDigitsDensity.C b/Detectors/Upgrades/ITS3/macros/test/CheckDigitsDensity.C new file mode 100755 index 0000000000000..1542b9a847d9e --- /dev/null +++ b/Detectors/Upgrades/ITS3/macros/test/CheckDigitsDensity.C @@ -0,0 +1,356 @@ +// Copyright 2020-2022 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CheckDigitsDensity.C +/// \brief analyze ITS3 digit density +/// \author felix.schlepper@cern.ch + +#include +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define ENABLE_UPGRADES +#include "CommonConstants/MathConstants.h" +#include "DataFormatsITSMFT/Digit.h" +#include "ITS3Base/SegmentationSuperAlpide.h" +#endif + +/* + * How to simulate: + * $o2-sim-digitizer-workflow -b + */ + +constexpr double interaction_rate = 50e3; // Hz +constexpr double integration_time = 10e-6; // s +constexpr double qedXSection = 34346.9; // barn +constexpr double hadXSection = 8.f; // barn +constexpr double qedRate = qedXSection / hadXSection * interaction_rate; // Hz +constexpr double qedFactor = qedRate * integration_time; // a.u. +using o2::itsmft::Digit; +using densMap = std::pair; +using densMaps = std::vector; + +void checkFile(const std::unique_ptr& file); +densMaps makeDensMaps(int nLayers, std::string n = ""); +struct Maximum { + double y; + double vy; + Maximum(double y, double vy) : y{y}, vy{vy} {} +}; + +std::vector densityProjection(densMaps& maps, int nEvents, bool qed); +std::vector makeCanvasProjection(const densMaps& maps); + +std::vector CheckDigitsDensity(int nLayers = 3, int nEvents = 100, float pitchCol = 22.e-4f, + float pitchRow = 22.e-4f, + std::string digitFileName = "it3digits.root", + bool qed = false, bool batch = true) +{ + gROOT->SetBatch(batch); + + // Vars + const int nHemis = nLayers * 2; + o2::its3::SegmentationSuperAlpide temp; + std::vector seg; + std::vector totArea; + for (auto i = 0; i < nLayers; ++i) { + seg.emplace_back(i, pitchCol, pitchRow, 50.e-4, 26.f, temp.mRadii); + totArea.emplace_back(seg[i].mRadii[i] * seg[i].mLength * TMath::Pi()); + } + + // Digits + std::unique_ptr digitFile(TFile::Open(digitFileName.data())); + checkFile(digitFile); + auto digitTree = digitFile->Get("o2sim"); + std::vector digitArray; + std::vector* digitArrayPtr{&digitArray}; + digitTree->SetBranchAddress("IT3Digit", &digitArrayPtr); + std::vector hist; + auto densityMaps = makeDensMaps(nLayers); + auto densMG = new TMultiGraph("g_densMG", "Digit Density along z"); + for (auto i = 0; i < nLayers; ++i) { + hist.emplace_back(Form("h_L%d", i), Form("Digits L%i", i), seg[i].mNCols, 0, + seg[i].mNCols, seg[i].mNRows, 0, seg[i].mNRows); + } + + // Digits Loop + for (int iEntry = 0; digitTree->LoadTree(iEntry) >= 0; ++iEntry) { + digitTree->GetEntry(iEntry); + + // Digit + for (const auto& digit : digitArray) { + auto id = digit.getChipIndex(); + if (id >= nHemis) { // outside of Inner Barrel + continue; + } + auto col = digit.getColumn(); + auto row = digit.getRow(); + auto z = static_cast(seg[0].mLength) / + static_cast(seg[0].mNCols) * col - + seg[0].mLength / 2.f; + hist[id / 2].Fill(col, row); + if (id == 0 || id == 1) { + auto r = static_cast(TMath::Pi()) * seg[0].mRadii[0] / + static_cast(seg[0].mNRows) * row; + densityMaps[0].first->Fill(z, r); + } else if (id == 2 || id == 3) { + auto r = static_cast(TMath::Pi()) * seg[1].mRadii[1] / + static_cast(seg[1].mNRows) * row; + densityMaps[1].first->Fill(z, r); + } else if (id == 4 || id == 5) { + auto r = static_cast(TMath::Pi()) * seg[2].mRadii[2] / + static_cast(seg[2].mNRows) * row; + densityMaps[2].first->Fill(z, r); + } + } + } + + auto maxes = densityProjection(densityMaps, nEvents, qed); + + printf("----\n"); + printf("NEvents %d\n", nEvents); + for (auto i = 0; i < nLayers; ++i) { + printf("Layer %d\n", i); + auto nDigits = hist[i].Integral(); + printf("nDigits %f\n", nDigits); + printf("Number of digits per Area (cm^-2) per Event: %.2f\n", + nDigits / static_cast(totArea[i] * nEvents * 2)); + double nPixels = + seg[i].mNCols * seg[i].mNRows * 2; // both hemispheres combined + printf("Total number of Pixel %f\n", nPixels); + printf("Occupancy: %.6f\n", nDigits / (nPixels * nEvents)); + printf("L%i = %f +- %f\n", i, maxes[i].y, maxes[i].vy); + } + + std::unique_ptr oFile(TFile::Open("checkDigitsDensity.root", "RECREATE")); + checkFile(oFile); + for (auto& h : hist) { + h.Scale(1.f / (22.e-4 * 22.e-4 * nEvents * 2)); + h.Write(); + } + + auto canvDens = makeCanvasProjection(densityMaps); + for (auto& canvDen : canvDens) { + canvDen->Write(); + } + + auto canvDensLayers = new TCanvas("canvDensLayers", "", 1000, 800); + canvDensLayers->cd(); + for (const auto& [_, g] : densityMaps) { + densMG->Add(g); + g->Write(); + } + densMG->GetXaxis()->SetTitle("z (cm)"); + densMG->GetYaxis()->SetTitle("digit density (cm^{-2})"); + densMG->Draw("AP pmc plc"); + canvDensLayers->BuildLegend(0.75, 0.75, 0.9, 0.9); + canvDensLayers->Write(); + canvDensLayers->SaveAs("cDigits.pdf"); + + return maxes; +} + +void checkFile(const std::unique_ptr& file) +{ + if (!file || file->IsZombie()) { + printf("Could not open %s!\n", file->GetName()); + std::exit(1); + } +} + +// Make density plots for nLayers +densMaps makeDensMaps(int nLayers, std::string n) +{ + const o2::its3::SegmentationSuperAlpide ssAlpide; + const double half_length = ssAlpide.mLength / 2.f; + densMaps map; + for (int i = 0; i < nLayers; ++i) { + auto densityZ = + new TH2F(Form("h_densityZL%d%s", i, n.data()), "Local Digit Density", + static_cast(ssAlpide.mLength), -half_length, half_length, + static_cast(ssAlpide.mRadii[i] * o2::constants::math::PI / + (ssAlpide.mPitchRow * 100)), + 0.f, ssAlpide.mRadii[i] * o2::constants::math::PI); + densityZ->GetXaxis()->SetTitle("z (cm)"); + densityZ->GetYaxis()->SetTitle("#varphi"); + auto densityZErr = new TGraphErrors(densityZ->GetNbinsX()); + densityZErr->SetMarkerStyle(21); + densityZErr->SetTitle(Form("L%d", i)); + densityZErr->GetXaxis()->SetTitle("z (cm)"); + densityZErr->GetYaxis()->SetTitle("hit density (cm^{-2})"); + map.emplace_back(std::move(densityZ), std::move(densityZErr)); + } + return map; +} +std::vector densityProjection(densMaps& maps, int nEvents, bool qed) +{ + std::vector maxes; + for (auto& [densityZ, densityProZErr] : maps) { + double binArea = densityZ->GetXaxis()->GetBinWidth(1) * + densityZ->GetYaxis()->GetBinWidth(1); + double maxHitDensity = 0.f; + double maxHitDensityErr = 0.f; + // Calculate Hit density for each pixel + // For PbPb just per event + densityZ->Scale( + 1.f / + (2 * binArea * + nEvents)); // to increase statistics we looked at both hemispheres + if (qed) { + densityZ->Scale(qedFactor); + } + // Fill hit density projection + for (int x = 1; x <= densityZ->GetNbinsX(); ++x) { + std::vector v; + for (int y = 1; y <= densityZ->GetNbinsY(); ++y) { + if (densityZ->GetBinContent(x, y) > 0) { + v.push_back(densityZ->GetBinContent(x, y)); + } + } + double sum = std::accumulate(v.begin(), v.end(), 0.0); + double mean = sum / v.size(); + std::vector diff(v.size()); + std::transform(v.begin(), v.end(), diff.begin(), + [mean](double x) { return x - mean; }); + double sq_sum = + std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0); + double stdev = std::sqrt(sq_sum / v.size()); + // Set point + densityProZErr->SetPoint(x - 1, densityZ->GetXaxis()->GetBinCenter(x), + mean); + densityProZErr->SetPointError( + x - 1, densityZ->GetXaxis()->GetBinWidth(x) / 2.f, stdev); + // update max + if (mean > maxHitDensity) { + maxHitDensity = mean; + maxHitDensityErr = stdev; + } + } + maxes.emplace_back(maxHitDensity, maxHitDensityErr); + } + return maxes; +} + +std::vector makeCanvasProjection(const densMaps& maps) +{ + std::vector canvases; + for (const auto& [densityZ, densityProZErr] : maps) { + auto canvDens = + new TCanvas(Form("c%s", densityZ->GetName()), "", 1600, 800); + canvDens->Divide(2, 1); + canvDens->cd(1); + densityZ->Draw("colz"); + canvDens->cd(2); + densityProZErr->Draw("AP"); + canvases.push_back(canvDens); + } + return canvases; +} + +void Plot() +{ + int i = 0; + int j = 0; + std::vector centralities{ + "0.00", "1.57", "2.22", "2.71", "3.13", "3.50", "4.94", + "6.05", "6.98", "7.81", "8.55", "9.23", "9.88", "10.47", + "11.04", "11.58", "12.09", "12.58", "13.05", "13.52", "13.97", + "14.43", "14.96", "15.67", "20.00"}; + std::vector> data; + for (auto it = centralities.cbegin(); it != centralities.cend() - 1; ++it) { + auto path = "./" + *it + "_" + *(it + 1) + "/"; + gSystem->cd(path.c_str()); + gSystem->Exec("pwd"); + data.push_back(CheckDigitsDensity()); + gSystem->cd(".."); + } + for (const auto& elem : data) { + std::cout << "+++++++++++++++++++++++++++++++++++++++++\n"; + std::cout << ++j << std::endl; + for (int i = 0; i < 3; ++i) { + std::cout << "===\nLayer " << i << "\n"; + std::cout << elem[i].y << " +/- " << elem[i].vy << "\n"; + } + std::cout << "-----------------------------------------" << std::endl; + } + auto c1 = new TCanvas("c1", "A Simple Graph Example", 200, 10, 700, 500); + const Int_t n = 24; + char const* range[n] = { + "0-1", "1-2", "2-3", "3-4", "4-5", "5-10", "10-15", "15-20", + "20-25", "25-30", "30-35", "35-40", "40-45", "45-50", "50-55", "55-60", + "60-65", "65-70", "70-75", "75-80", "80-85", "85-90", "90-95", "95-100"}; + double x[n]; + double y0[n], y1[n], y2[n]; + double vy0[n], vy1[n], vy2[n]; + for (i = 0; i < n; ++i) { + x[i] = i; + y0[i] = data[i][0].y; + y1[i] = data[i][1].y; + y2[i] = data[i][2].y; + vy0[i] = data[i][0].vy; + vy1[i] = data[i][1].vy; + vy2[i] = data[i][2].vy; + } + + auto h = new TH1F("h", "", n, x[0] - 0.5, x[n - 1] + 0.5); + h->SetTitle("Mean digit density per centrality class"); + h->GetYaxis()->SetTitleOffset(1.); + h->GetXaxis()->SetTitleOffset(1.); + h->GetYaxis()->SetTitle("digit density (cm^{-2})"); + h->GetXaxis()->SetTitle("centrality (%)"); + h->GetXaxis()->SetNdivisions(-10); + for (i = 1; i <= n; i++) + h->GetXaxis()->SetBinLabel(i, range[i - 1]); + h->SetMaximum(600); + h->SetMinimum(0); + h->SetStats(0); + h->Draw(""); + auto gr0 = new TGraphErrors(n, x, y0, nullptr, vy0); + gr0->SetMarkerStyle(4); + gr0->SetMarkerSize(0.5); + gr0->SetTitle("L0"); + auto gr1 = new TGraphErrors(n, x, y1, nullptr, vy1); + gr1->SetMarkerStyle(4); + gr1->SetMarkerSize(0.5); + gr1->SetTitle("L1"); + auto gr2 = new TGraphErrors(n, x, y2, nullptr, vy2); + gr2->SetMarkerStyle(4); + gr2->SetMarkerSize(0.5); + gr2->SetTitle("L2"); + auto mg = new TMultiGraph("mg", ""); + mg->Add(gr0); + mg->Add(gr1); + mg->Add(gr2); + mg->Draw("P pmc plc"); + auto leg = new TLegend(0.75, 0.75, 0.9, 0.9); + leg->AddEntry(gr0); + leg->AddEntry(gr1); + leg->AddEntry(gr2); + leg->Draw(); + + c1->SaveAs("its3DigitDensityCentrality.pdf"); +} diff --git a/Detectors/Upgrades/ITS3/macros/test/CheckHits.C b/Detectors/Upgrades/ITS3/macros/test/CheckHits.C new file mode 100644 index 0000000000000..bb1a8073fc646 --- /dev/null +++ b/Detectors/Upgrades/ITS3/macros/test/CheckHits.C @@ -0,0 +1,466 @@ +// Copyright 2020-2022 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CheckHits.C +/// \brief analyze its3 hits +/// \author felix.schlepper@cern.ch + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define ENABLE_UPGRADES +#include "CommonConstants/MathConstants.h" +#include "ITS3Base/SegmentationSuperAlpide.h" +#include "ITSMFTSimulation/Hit.h" +#include "SimulationDataFormat/MCTrack.h" +#endif + +using o2::itsmft::Hit; + +constexpr int nLayers = 3; +constexpr double interaction_rate = 50e3; // Hz +constexpr double integration_time = 10e-6; // s +constexpr double qedXSection = 34962.1; // barn +constexpr double hadXSection = 8.f; // barn +constexpr double qedRate = qedXSection / hadXSection * interaction_rate; // Hz +constexpr double qedFactor = qedRate * integration_time; // a.u. +static constexpr std::array radii{1.9, 2.52, 3.15, 999}; +static const o2::its3::SegmentationSuperAlpide ssAlpide(0, 22.e-4, 22.e-4, 66.e-4, 26., radii.data()); + +struct Maximum { + double y; + double vy; + Maximum(double y, double vy) : y{y}, vy{vy} {} +}; + +struct Data { + double max; + double maxE; + double mean; + double meanRMS; +}; + +void checkFile(const std::unique_ptr& file); +TH2D* makeMap(int layer, std::string n); + +std::array CheckHits(bool qed = false, std::string hitFileName = "o2sim_HitsIT3.root", + std::string kineFileName = "o2sim_Kine.root", + bool batch = true) +{ + gROOT->SetBatch(batch); + // Vars + const int nHemis = nLayers * 2; + + if (qed) { + printf("----\n"); + printf("QEDXSection=%f;HadronXSection=%f;QEDRate=%f;QEDFactor=%f\n", + qedXSection, hadXSection, qedRate, qedFactor); + } + + // Hits + std::unique_ptr hitFile(TFile::Open(hitFileName.data())); + checkFile(hitFile); + auto hitTree = hitFile->Get("o2sim"); + std::vector hitArray, *hitArrayPtr{&hitArray}; + hitTree->SetBranchAddress("IT3Hit", &hitArrayPtr); + + // Kine + std::unique_ptr kineFile(TFile::Open(kineFileName.data())); + checkFile(kineFile); + auto kineTree = kineFile->Get("o2sim"); + std::vector trackArray, *trackArrayPtr{&trackArray}; + kineTree->SetBranchAddress("MCTrack", &trackArrayPtr); + + // Hit Plots + auto hitsXY = + new TH2F("h_hitsXY", "Hits XY", 1600, -5.f, 5.f, 1600, -5.f, 5.f); + hitsXY->GetXaxis()->SetTitle("x (cm)"); + hitsXY->GetYaxis()->SetTitle("y (cm)"); + auto hitsZY = + new TH2F("h_hitsZY", "Hits ZY", 1600, -30.f, 30.f, 1600, -5.f, 5.f); + hitsZY->GetXaxis()->SetTitle("z (cm)"); + hitsZY->GetYaxis()->SetTitle("y (cm)"); + std::array avgHitMaps{}; + for (int i = 0; i < nLayers; ++i) { + avgHitMaps[i] = makeMap(i, ""); + } + std::array avgHitMapsProj{}; + auto densMG = new TMultiGraph("g_densMG", "Hit Density along z"); + std::vector> eventHitMaps; + std::vector> eventHitMapsProj; + std::array, nLayers> eventMaxes; + // Hits Loop + const auto nEvents = hitTree->GetEntriesFast(); + for (int iEntry = 0; hitTree->LoadTree(iEntry) >= 0; ++iEntry) { + if (!qed) { + std::array maps{}; + for (int i = 0; i < nLayers; ++i) { + maps[i] = makeMap(i, Form("_event_%d", iEntry)); + } + eventHitMaps.push_back(maps); + } + hitTree->GetEntry(iEntry); + + // Hits + for (const auto& hit : hitArray) { + if (hit.GetDetectorID() >= + nHemis) { // outside of Inner Barrel, e.g. Outer Barrel + continue; + } + hitsXY->Fill(hit.GetX(), hit.GetY()); + hitsZY->Fill(hit.GetZ(), hit.GetY()); + auto z = hit.GetZ(); + auto phi = std::atan(hit.GetX() / (hit.GetY())) + + o2::constants::math::PI / 2.f; + if (hit.GetDetectorID() == 0) { + auto rphi = phi * ssAlpide.mRadii[0]; + if (!qed) { + eventHitMaps.back()[0]->Fill(z, rphi); + } + avgHitMaps[0]->Fill(z, rphi); + } else if (hit.GetDetectorID() == 2) { + auto rphi = phi * ssAlpide.mRadii[1]; + if (!qed) { + eventHitMaps.back()[1]->Fill(z, rphi); + } + avgHitMaps[1]->Fill(z, rphi); + } else if (hit.GetDetectorID() == 4) { + auto rphi = phi * ssAlpide.mRadii[2]; + if (!qed) { + eventHitMaps.back()[2]->Fill(z, rphi); + } + avgHitMaps[2]->Fill(z, rphi); + } + } + + if (!qed) { + std::array projs{}; + for (int iLayer = 0; iLayer < nLayers; ++iLayer) { + double binArea = eventHitMaps.back()[iLayer]->GetXaxis()->GetBinWidth(1) * + eventHitMaps.back()[iLayer]->GetYaxis()->GetBinWidth(1); + eventHitMaps.back()[iLayer]->Scale(1.f / binArea); + projs[iLayer] = eventHitMaps.back()[iLayer]->ProjectionX("_px", 0, -1, "e"); + projs[iLayer]->Scale(1. / eventHitMaps.back()[iLayer]->GetNbinsY()); + projs[iLayer]->SetMarkerStyle(21); + projs[iLayer]->SetTitle(Form("L%d", iLayer)); + projs[iLayer]->GetXaxis()->SetTitle("z (cm)"); + projs[iLayer]->GetYaxis()->SetTitle("hit density (cm^{-2})"); + eventMaxes[iLayer].push_back(projs[iLayer]->GetMaximum()); + } + eventHitMapsProj.push_back(projs); + } + } + + // Kinematic Plots + auto kineN = + new TH1D("h_kineN", "Multiplicity Stable particles", 100, -5.f, 5.f); + kineN->GetXaxis()->SetTitle("#eta"); + kineN->GetYaxis()->SetTitle("#frac{dN}{d#eta}"); + auto kineN05 = new TH1D("h_kineN05", "#||{#eta}<0.5", 50, -0.5f, 0.5f); + kineN05->GetXaxis()->SetTitle("#eta"); + kineN05->GetYaxis()->SetTitle("#frac{dN}{d#eta}"); + + // Kinematics Loop + for (int iEntry = 0; kineTree->LoadTree(iEntry) >= 0; ++iEntry) { + kineTree->GetEntry(iEntry); + + for (const auto& track : trackArray) { // MCTrack + // primary particles + auto vx = track.Vx(); + auto vy = track.Vy(); + if (vx * vx + vy * vy > 0.01) { + continue; + } + auto id = TMath::Abs(track.GetPdgCode()); + if (id != 2212 && // proton + id != 211 && // pion + id != 321 // kaon + ) { + continue; + } + kineN->Fill(track.GetEta()); + if (TMath::Abs(track.GetEta()) < 0.5) { + kineN05->Fill(track.GetEta()); + } + } + } + kineN->Scale(1.f / (kineN->GetXaxis()->GetBinWidth(1) * nEvents)); + kineN05->Scale(1.f / (kineN05->GetXaxis()->GetBinWidth(1) * nEvents)); + printf("----\n"); + printf("Kinematics: Abs(eta)<0.5=%.2f\n", kineN05->Integral("width")); + + // Projections + for (int i = 0; i < nLayers; ++i) { + double binArea = avgHitMaps[i]->GetXaxis()->GetBinWidth(1) * + avgHitMaps[i]->GetYaxis()->GetBinWidth(1); + avgHitMaps[i]->Scale(1.f / (binArea * nEvents)); + if (qed) { + avgHitMaps[i]->Scale(qedFactor); + } + avgHitMapsProj[i] = avgHitMaps[i]->ProjectionX("_px", 0, -1, "e"); + avgHitMapsProj[i]->Scale(1. / avgHitMaps[i]->GetNbinsY()); + avgHitMapsProj[i]->SetMarkerStyle(21); + avgHitMapsProj[i]->SetTitle(Form("L%d", i)); + } + + std::vector hMaxes; + hMaxes.reserve(nLayers); + for (int i = 0; i < nLayers; ++i) { + hMaxes.emplace_back(Form("hMaxes_%d", i), Form("RMS in Layer %d", i), 600, 0, 150); + } + + std::array ret; + // Report maximum + printf("----\n"); + printf("Max local hit density:\n"); + for (int i = 0; i < nLayers; ++i) { + printf("L%i = %f +- %f\n", i, avgHitMapsProj[i]->GetMaximum(), avgHitMapsProj[i]->GetBinError(avgHitMapsProj[i]->GetMaximumBin())); + + if (!qed) { + for (const auto& max : eventMaxes[i]) { + hMaxes[i].Fill(max); + } + + printf("Per Event Mean=%f with RMS=%f\n", hMaxes[i].GetMean(), + hMaxes[i].GetRMS()); + } + + Data r{}; + r.max = avgHitMapsProj[i]->GetMaximum(); + r.maxE = avgHitMapsProj[i]->GetBinError(avgHitMapsProj[i]->GetMaximumBin()); + if (!qed) { + r.mean = hMaxes[i].GetMean(); + r.meanRMS = hMaxes[i].GetRMS(); + } + ret[i] = r; + } + + std::unique_ptr oFile(TFile::Open("checkHits.root", "RECREATE")); + checkFile(oFile); + auto canvXY = new TCanvas("canvHits", "", 1600, 800); + canvXY->Divide(2, 1); + canvXY->cd(1); + hitsXY->Draw("colz"); + canvXY->cd(2); + hitsZY->Draw("colz"); + canvXY->Write(); + for (int i = 0; i < nLayers; ++i) { + auto canvDens = + new TCanvas(Form("c%s", avgHitMaps[i]->GetName()), "", 1600, 800); + canvDens->Divide(2, 1); + canvDens->cd(1); + avgHitMaps[i]->Draw("colz"); + canvDens->cd(2); + avgHitMapsProj[i]->GetXaxis()->SetTitle("z (cm)"); + avgHitMapsProj[i]->GetYaxis()->SetTitle("hit density (cm^{-2})"); + avgHitMapsProj[i]->Draw("AP"); + canvDens->Write(); + } + + auto canvDensLayers = new TCanvas("canvDensLayers", "", 1000, 800); + canvDensLayers->cd(); + for (int i = 0; i < nLayers; ++i) { + auto g = new TGraphErrors(avgHitMapsProj[i]); + densMG->Add(g); + g->Write(); + } + densMG->GetXaxis()->SetTitle("z (cm)"); + densMG->GetYaxis()->SetTitle("hit density (cm^{-2})"); + densMG->Draw("AP pmc plc"); + canvDensLayers->BuildLegend(0.75, 0.75, 0.9, 0.9); + canvDensLayers->Write(); + canvDensLayers->SaveAs("cHitsDens.pdf"); + + auto canvKineN = new TCanvas("canvKineN", "", 2000, 800); + canvKineN->Divide(2, 1); + auto pKineN = canvKineN->cd(1); + pKineN->SetLeftMargin(0.12); + kineN->Draw("hist"); + pKineN = canvKineN->cd(2); + pKineN->SetLeftMargin(0.12); + kineN05->Draw("hist"); + canvKineN->Write(); + + for (auto& h : eventHitMaps) { + for (auto& pp : h) { + pp->Write(); + } + } + for (auto& h : hMaxes) { + h.Write(); + } + return ret; +} + +void checkFile(const std::unique_ptr& file) +{ + if (!file || file->IsZombie()) { + printf("Could not open %s!\n", file->GetName()); + std::exit(1); + } +} + +TH2D* makeMap(int layer, std::string n) +{ + const double half_length = ssAlpide.mLength / 2.f; + auto map = + new TH2D(Form("h_densityZL%d%s", layer, n.data()), "Local Hit Density", + static_cast(ssAlpide.mLength), -half_length, half_length, + static_cast(ssAlpide.mRadii[layer] * o2::constants::math::PI / + (ssAlpide.mPitchRow * 100)), + 0.f, ssAlpide.mRadii[layer] * o2::constants::math::PI); + map->GetXaxis()->SetTitle("z (cm)"); + map->GetYaxis()->SetTitle("r#varphi"); + return map; +} + +void Plot() +{ + std::vector centralities{ + "0.00", "1.57", "2.22", "2.71", "3.13", "3.50", "4.94", + "6.05", "6.98", "7.81", "8.55", "9.23", "9.88", "10.47", + "11.04", "11.58", "12.09", "12.58", "13.05", "13.52", "13.97", + "14.43", "14.96", "15.67", "20.00"}; + std::vector> data; + for (auto it = centralities.cbegin(); it != centralities.cend() - 1; ++it) { + auto path = "./" + *it + "_" + *(it + 1) + "/"; + gSystem->cd(path.c_str()); + gSystem->Exec("pwd"); + data.push_back(CheckHits()); + gSystem->cd(".."); + } + for (const auto& elem : data) { + std::cout << "+++++++++++++++++++++++++++++++++++++++++\n"; + for (int i = 0; i < 3; ++i) { + std::cout << "===\nLayer " << i << "\n"; + std::cout << elem[i].max << " +/- " << elem[i].maxE << "\n"; + std::cout << elem[i].mean << " +/- " << elem[i].meanRMS << "\n"; + } + std::cout << "-----------------------------------------" << std::endl; + } + const Int_t n = 24; + char const* range[n] = { + "0-1", "1-2", "2-3", "3-4", "4-5", "5-10", "10-15", "15-20", + "20-25", "25-30", "30-35", "35-40", "40-45", "45-50", "50-55", "55-60", + "60-65", "65-70", "70-75", "75-80", "80-85", "85-90", "90-95", "95-100"}; + int i; + double x[n]; + double y0[n], y1[n], y2[n]; + double vy0[n], vy1[n], vy2[n]; + double y0M[n], y1M[n], y2M[n]; + double vy0M[n], vy1M[n], vy2M[n]; + for (i = 0; i < n; ++i) { + x[i] = i; + y0[i] = data[i][0].max; + y1[i] = data[i][1].max; + y2[i] = data[i][2].max; + vy0[i] = data[i][0].maxE; + vy1[i] = data[i][1].maxE; + vy2[i] = data[i][2].maxE; + y0M[i] = data[i][0].mean; + y1M[i] = data[i][1].mean; + y2M[i] = data[i][2].mean; + vy0M[i] = data[i][0].meanRMS; + vy1M[i] = data[i][1].meanRMS; + vy2M[i] = data[i][2].meanRMS; + } + + auto c1 = new TCanvas("c1", "A Simple Graph Example", 200, 10, 700, 500); + auto h = new TH1F("h", "", n, x[0] - 0.5, x[n - 1] + 0.5); + h->SetTitle("Mean hit density per centrality class"); + h->GetYaxis()->SetTitleOffset(1.); + h->GetXaxis()->SetTitleOffset(1.); + h->GetYaxis()->SetTitle("hit density (cm^{-2})"); + h->GetXaxis()->SetTitle("centrality (%)"); + h->GetXaxis()->SetNdivisions(-10); + for (i = 1; i <= n; i++) + h->GetXaxis()->SetBinLabel(i, range[i - 1]); + h->SetMaximum(70); + h->SetMinimum(0); + h->SetStats(0); + h->Draw(""); + auto gr0 = new TGraphErrors(n, x, y0, nullptr, vy0); + gr0->SetMarkerStyle(4); + gr0->SetMarkerSize(0.5); + gr0->SetTitle("L0"); + auto gr1 = new TGraphErrors(n, x, y1, nullptr, vy1); + gr1->SetMarkerStyle(4); + gr1->SetMarkerSize(0.5); + gr1->SetTitle("L1"); + auto gr2 = new TGraphErrors(n, x, y2, nullptr, vy2); + gr2->SetMarkerStyle(4); + gr2->SetMarkerSize(0.5); + gr2->SetTitle("L2"); + auto mg = new TMultiGraph("mg", ""); + mg->Add(gr0); + mg->Add(gr1); + mg->Add(gr2); + mg->Draw("P pmc plc"); + auto leg = new TLegend(0.75, 0.75, 0.9, 0.9); + leg->AddEntry(gr0); + leg->AddEntry(gr1); + leg->AddEntry(gr2); + leg->Draw(); + c1->SaveAs("its3HitsCentralityMean.pdf"); + + c1 = new TCanvas("c1", "A Simple Graph Example", 200, 10, 700, 500); + auto hh = new TH1F("hh", "", n, x[0] - 0.5, x[n - 1] + 0.5); + hh->SetTitle("Maximum hit density per centrality class per event with RMS"); + hh->GetYaxis()->SetTitleOffset(1.); + hh->GetXaxis()->SetTitleOffset(1.); + hh->GetYaxis()->SetTitle("hit density (cm^{-2})"); + hh->GetXaxis()->SetTitle("centrality (%)"); + hh->GetXaxis()->SetNdivisions(-10); + for (i = 1; i <= n; i++) + hh->GetXaxis()->SetBinLabel(i, range[i - 1]); + hh->SetMaximum(130); + hh->SetMinimum(0); + hh->SetStats(false); + hh->Draw(""); + auto gr0M = new TGraphErrors(n, x, y0M, nullptr, vy0M); + gr0M->SetMarkerStyle(4); + gr0M->SetMarkerSize(0.5); + gr0M->SetTitle("L0"); + auto gr1M = new TGraphErrors(n, x, y1M, nullptr, vy1M); + gr1M->SetMarkerStyle(4); + gr1M->SetMarkerSize(0.5); + gr1M->SetTitle("L1"); + auto gr2M = new TGraphErrors(n, x, y2M, nullptr, vy2M); + gr2M->SetMarkerStyle(4); + gr2M->SetMarkerSize(0.5); + gr2M->SetTitle("L2"); + auto mgM = new TMultiGraph("mg", ""); + mgM->Add(gr0M); + mgM->Add(gr1M); + mgM->Add(gr2M); + mgM->Draw("P pmc plc"); + auto legM = new TLegend(0.75, 0.75, 0.9, 0.9); + legM->AddEntry(gr0M); + legM->AddEntry(gr1M); + legM->AddEntry(gr2M); + legM->Draw(); + c1->SaveAs("its3HitsCentralityMaximum.pdf"); +} diff --git a/Detectors/Upgrades/ITS3/macros/test/CompareClusterSize.C b/Detectors/Upgrades/ITS3/macros/test/CompareClusterSize.C new file mode 100755 index 0000000000000..c8a0826cc2435 --- /dev/null +++ b/Detectors/Upgrades/ITS3/macros/test/CompareClusterSize.C @@ -0,0 +1,122 @@ +// Copyright 2020-2022 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file CompareClusterSize.C +/// \brief compare ITS2 cluster size with ITS3 one +/// \dependencies CheckClusterSize.C +/// \author felix.schlepper@cern.ch + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#endif + +void CompareClusterSize(long timestamp = 0) +{ + gROOT->SetBatch(); + gStyle->SetOptStat(0); + + // Get cluster size from checkClusterSize.C output + std::unique_ptr its3ClusterFile(TFile::Open("checkClusterSize.root")); + std::unique_ptr its3Cluster(its3ClusterFile->Get("outerbarrel")); + its3Cluster->Sumw2(); + its3Cluster->SetDirectory(nullptr); + its3Cluster->Scale(1.0 / its3Cluster->Integral()); + its3Cluster->SetLineColor(kRed); + its3Cluster->SetLineWidth(2); + its3Cluster->SetFillColorAlpha(kRed + 2, 0.3); + + auto hITS = new TH1F("its", "", its3Cluster->GetNbinsX(), 0, + its3Cluster->GetNbinsX()); + + hITS->Sumw2(); + hITS->SetLineColor(kBlue); + hITS->SetDirectory(nullptr); + hITS->SetLineWidth(2); + hITS->SetFillColorAlpha(kBlue + 2, 0.3); + // get topology dict + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + mgr.setURL("http://alice-ccdb.cern.ch"); + mgr.setTimestamp(timestamp != 0 ? timestamp + : o2::ccdb::getCurrentTimestamp()); + const o2::itsmft::TopologyDictionary* dict = + mgr.get("ITS/Calib/ClusterDictionary"); + std::unique_ptr clusFile(TFile::Open("o2clus_its.root")); + auto clusTree = clusFile->Get("o2sim"); + std::vector clusArr, *clusArrP{&clusArr}; + clusTree->SetBranchAddress("ITSClusterComp", &clusArrP); + std::vector patterns; + std::vector* patternsPtr{&patterns}; + clusTree->SetBranchAddress("ITSClusterPatt", &patternsPtr); + std::vector rofRecVec, *rofRecVecP{&rofRecVec}; + clusTree->SetBranchAddress("ITSClustersROF", &rofRecVecP); + clusTree->GetEntry(0); + int nROFRec = (int)rofRecVec.size(); + auto pattIt = patternsPtr->cbegin(); + + for (int irof = 0; irof < nROFRec; irof++) { + const auto& rofRec = rofRecVec[irof]; + // rofRec.print(); + + for (int icl = 0; icl < rofRec.getNEntries(); icl++) { + int clEntry = rofRec.getFirstEntry() + icl; + const auto& cluster = clusArr[clEntry]; + // cluster.print(); + + auto pattId = cluster.getPatternID(); + int clusterSize = -1000; + if (pattId == o2::itsmft::CompCluster::InvalidPatternID || + dict->isGroup(pattId)) { + o2::itsmft::ClusterPattern patt(pattIt); + clusterSize = patt.getNPixels(); + } else { + clusterSize = dict->getNpixels(pattId); + } + hITS->Fill(clusterSize); + } + } + hITS->Scale(1.0 / hITS->Integral()); + + auto c = new TCanvas("c", "", 1200, 800); + c->SetLogy(); + hITS->GetYaxis()->SetRangeUser(1e-4, 1.); + hITS->GetXaxis()->SetTitle("cluster size"); + hITS->GetYaxis()->SetTitle("norm. counts"); + hITS->Draw("hist"); + its3Cluster->Draw("hist same"); + auto legend = new TLegend(0.6, 0.7, 0.9, 0.9); + legend->AddEntry( + hITS, Form("ITS2 data %.2f +/- %.2f", hITS->GetMean(), hITS->GetRMS()), + "f"); + legend->AddEntry(its3Cluster.get(), + Form("ITS3 MC %.2f +/- %.2f", its3Cluster->GetMean(), + its3Cluster->GetRMS()), + "f"); + legend->Draw(); + c->SaveAs("comp.pdf"); +} From 7ac84e515f4abddd8ac4e281eabe374fd807f2e0 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 4 Oct 2023 11:49:32 +0200 Subject: [PATCH 228/324] DPL: change ExpirationHandler::Creator to use services This allows us to easily have some state attached to the creation of new timeslices and in particular we can then use the DecongestionService to keep track of the next enumeration to be created. This comes handy when we have dummy iterations which we want to "rewind" to avoid messages about empty timeslices. --- .../include/Framework/ExpirationHandler.h | 2 +- Framework/Core/src/DataRelayer.cxx | 2 +- Framework/Core/src/DecongestionService.h | 3 ++ Framework/Core/src/LifetimeHelpers.cxx | 44 ++++++++++++------- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/Framework/Core/include/Framework/ExpirationHandler.h b/Framework/Core/include/Framework/ExpirationHandler.h index e4c6c8bff53e9..5c1b19331bfaf 100644 --- a/Framework/Core/include/Framework/ExpirationHandler.h +++ b/Framework/Core/include/Framework/ExpirationHandler.h @@ -30,7 +30,7 @@ struct TimesliceSlot; struct InputRecord; struct ExpirationHandler { - using Creator = std::function; + using Creator = std::function; /// Callback type to check if the record must be expired using Checker = std::function; /// Callback type to actually materialise a given record diff --git a/Framework/Core/src/DataRelayer.cxx b/Framework/Core/src/DataRelayer.cxx index cc2ec51508044..7dc6d28a1a11f 100644 --- a/Framework/Core/src/DataRelayer.cxx +++ b/Framework/Core/src/DataRelayer.cxx @@ -125,7 +125,7 @@ DataRelayer::ActivityStats DataRelayer::processDanglingInputs(std::vector TimesliceSlot { + return [](ServiceRegistryRef, ChannelIndex) -> TimesliceSlot { return {TimesliceSlot::ANY}; }; } ExpirationHandler::Creator LifetimeHelpers::enumDrivenCreation(size_t start, size_t end, size_t step, size_t inputTimeslice, size_t maxInputTimeslices, size_t maxRepetitions) { - auto last = std::make_shared(start + inputTimeslice * step); + size_t firstTimeslice = start + inputTimeslice * step; auto repetition = std::make_shared(0); - return [end, step, last, maxInputTimeslices, maxRepetitions, repetition](ChannelIndex channelIndex, TimesliceIndex& index) -> TimesliceSlot { + return [end, step, firstTimeslice, maxInputTimeslices, maxRepetitions, repetition](ServiceRegistryRef services, ChannelIndex channelIndex) -> TimesliceSlot { + auto& index = services.get(); + auto& decongestion = services.get(); + if (decongestion.nextEnumerationTimeslice == 0) { + decongestion.nextEnumerationTimeslice = firstTimeslice; + } + for (size_t si = 0; si < index.size(); si++) { - if (*last > end) { + if (decongestion.nextEnumerationTimeslice > end) { LOGP(debug, "Last greater than end"); return TimesliceSlot{TimesliceSlot::INVALID}; } auto slot = TimesliceSlot{si}; if (index.isValid(slot) == false) { - TimesliceId timestamp{*last}; + TimesliceId timestamp{decongestion.nextEnumerationTimeslice}; *repetition += 1; if (*repetition % maxRepetitions == 0) { - *last += step * maxInputTimeslices; + decongestion.nextEnumerationTimeslice += step * maxInputTimeslices; } LOGP(debug, "Associating timestamp {} to slot {}", timestamp.value, slot.index); index.associate(timestamp, slot); // We know that next association will bring in last // so we can state this will be the latest possible input for the channel // associated with this. - LOG(debug) << "Oldest possible input is " << *last; - auto newOldest = index.setOldestPossibleInput({*last}, channelIndex); + LOG(debug) << "Oldest possible input is " << decongestion.nextEnumerationTimeslice; + [[maybe_unused]] auto newOldest = index.setOldestPossibleInput({decongestion.nextEnumerationTimeslice}, channelIndex); index.updateOldestPossibleOutput(); return slot; } @@ -100,10 +107,9 @@ ExpirationHandler::Creator LifetimeHelpers::enumDrivenCreation(size_t start, siz ExpirationHandler::Creator LifetimeHelpers::timeDrivenCreation(std::vector periods, std::vector intervals, std::function hasTimerFired, std::function updateTimerPeriod) { - std::shared_ptr last = std::make_shared(0); std::shared_ptr stablePeriods = std::make_shared(false); // FIXME: should create timeslices when period expires.... - return [last, stablePeriods, periods, intervals, hasTimerFired, updateTimerPeriod](ChannelIndex channelIndex, TimesliceIndex& index) mutable -> TimesliceSlot { + return [stablePeriods, periods, intervals, hasTimerFired, updateTimerPeriod](ServiceRegistryRef services, ChannelIndex channelIndex) mutable -> TimesliceSlot { // We start with a random offset to avoid all the devices // send their first message at the same time, bring down // the QC machine. @@ -113,13 +119,16 @@ ExpirationHandler::Creator LifetimeHelpers::timeDrivenCreation(std::vector(); + auto& decongestion = services.get(); + bool timerHasFired = hasTimerFired(); - if (*last == 0ULL || (index.didReceiveData() == false && timerHasFired)) { + if (decongestion.nextEnumerationTimeslice == 0ULL || (index.didReceiveData() == false && timerHasFired)) { std::random_device r; std::default_random_engine e1(r()); std::uniform_int_distribution dist(0, periods.front().count() * 0.9); auto randomizedPeriodUs = static_cast(dist(e1) + periods.front().count() * 0.1); - *last = getCurrentTime() - randomizedPeriodUs; + decongestion.nextEnumerationTimeslice = getCurrentTime() - randomizedPeriodUs; updateTimerPeriod(randomizedPeriodUs / 1000, randomizedPeriodUs / 1000); *stablePeriods = false; LOG(debug) << "Timer updated to a randomized period of " << randomizedPeriodUs << "us"; @@ -130,7 +139,7 @@ ExpirationHandler::Creator LifetimeHelpers::timeDrivenCreation(std::vector TimesliceSlot { + return [requestedLoopReason, &state](ServiceRegistryRef services, ChannelIndex) -> TimesliceSlot { /// Not the expected loop reason, return an invalid slot. + auto& index = services.get(); if ((state.loopReason & requestedLoopReason) == 0) { LOGP(debug, "No expiration due to a loop event. Requested: {:b}, reported: {:b}, matching: {:b}", requestedLoopReason, From f855f6f9615dfe755b7b983c5e3f996ea997c19c Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Thu, 5 Oct 2023 11:38:37 +0200 Subject: [PATCH 229/324] [EMCAL-791] Require CCDB access for EMCAL by default Option inverted to disable CCDB access on request. --- Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx | 4 ++-- prodtests/full_system_test.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx b/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx index a059a40ddb1c3..79555249dd64c 100644 --- a/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx +++ b/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx @@ -195,7 +195,7 @@ void customize(std::vector& workflowOptions) workflowOptions.push_back(ConfigParamSpec{"use-ccdb-ft0", o2::framework::VariantType::Bool, false, {"enable access to ccdb ft0 calibration objects"}}); // option to use/not use CCDB for EMCAL - workflowOptions.push_back(ConfigParamSpec{"use-ccdb-emc", o2::framework::VariantType::Bool, false, {"enable access to ccdb EMCAL simulation objects"}}); + workflowOptions.push_back(ConfigParamSpec{"no-use-ccdb-emc", o2::framework::VariantType::Bool, false, {"Disable access to ccdb EMCAL simulation objects"}}); // option to use or not use the Trap Simulator after digitisation (debate of digitization or reconstruction is for others) workflowOptions.push_back(ConfigParamSpec{"disable-trd-trapsim", VariantType::Bool, false, {"disable the trap simulation of the TRD"}}); @@ -650,7 +650,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // the EMCal part if (isEnabled(o2::detectors::DetID::EMC)) { - auto useCCDB = configcontext.options().get("use-ccdb-emc"); + auto useCCDB = !configcontext.options().get("no-use-ccdb-emc"); detList.emplace_back(o2::detectors::DetID::EMC); // connect the EMCal digitization digitizerSpecs.emplace_back(o2::emcal::getEMCALDigitizerSpec(fanoutsize++, mctruth, useCCDB)); diff --git a/prodtests/full_system_test.sh b/prodtests/full_system_test.sh index 3497229bc480f..b8017172d929c 100755 --- a/prodtests/full_system_test.sh +++ b/prodtests/full_system_test.sh @@ -140,7 +140,7 @@ taskwrapper sim.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} --seed $O2SIMSEED if [[ $DO_EMBEDDING == 1 ]]; then taskwrapper embed.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} -j $NJOBS --run ${RUNNUMBER} -n $NEvents -g pythia8pp -e ${FST_MC_ENGINE} -o sig --configKeyValues ${FST_EMBEDDING_CONFIG} --embedIntoFile o2sim_Kine.root fi -taskwrapper digi.log o2-sim-digitizer-workflow -n $NEvents ${DIGIQED} ${NOMCLABELS} --sims ${SIM_SOURCES} --tpc-lanes $((NJOBS < 36 ? NJOBS : 36)) --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} ${DIGITOPT} --configKeyValues "\"${DIGITOPTKEY}\"" --interactionRate $FST_COLRATE --use-ccdb-emc +taskwrapper digi.log o2-sim-digitizer-workflow -n $NEvents ${DIGIQED} ${NOMCLABELS} --sims ${SIM_SOURCES} --tpc-lanes $((NJOBS < 36 ? NJOBS : 36)) --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} ${DIGITOPT} --configKeyValues "\"${DIGITOPTKEY}\"" --interactionRate $FST_COLRATE [[ $SPLITTRDDIGI == "1" ]] && taskwrapper digiTRD.log o2-sim-digitizer-workflow -n $NEvents ${NOMCLABELS} --onlyDet TRD --trd-digit-downscaling ${DIGITDOWNSCALINGTRD} --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} --incontext collisioncontext.root --configKeyValues "\"${DIGITOPTKEYTRD}\"" touch digiTRD.log_done From faf0f9095cc8d6fd1eabffe4f8849115a87a86e4 Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Fri, 6 Oct 2023 11:08:35 +0200 Subject: [PATCH 230/324] [EMCAL-791] Remove attic fields in the SimParams mTimeDelay, mTimeNoise and the switch to take it from OCDB 1-1 portings from AliRoot to O2 - no longer used as the time response is now simulated. --- .../EMCAL/simulation/include/EMCALSimulation/SimParam.h | 6 ------ Detectors/EMCAL/simulation/src/SimParam.cxx | 3 --- 2 files changed, 9 deletions(-) diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/SimParam.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/SimParam.h index 6a8bd3180bda1..4a59b7fc4db28 100644 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/SimParam.h +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/SimParam.h @@ -33,9 +33,6 @@ class SimParam : public o2::conf::ConfigurableParamHelper Int_t getDigitThreshold() const { return mDigitThreshold; } Float_t getPinNoise() const { return mPinNoise; } Float_t getPinNoiseLG() const { return mPinNoiseLG; } - Float_t getTimeNoise() const { return mTimeNoise; } - Float_t getTimeDelay() const { return mTimeDelay; } - Bool_t isTimeDelayFromOCDB() const { return mTimeDelayFromOCDB; } Float_t getTimeResolutionPar0() const { return mTimeResolutionPar0; } Float_t getTimeResolutionPar1() const { return mTimeResolutionPar1; } Double_t getTimeResolution(Double_t energy) const; @@ -74,9 +71,6 @@ class SimParam : public o2::conf::ConfigurableParamHelper Float_t mGainFluctuations{15.}; ///< correct fMeanPhotonElectron by the gain fluctuations Float_t mPinNoise{0.012}; ///< Electronics noise in EMC, APD Float_t mPinNoiseLG{0.1}; ///< Electronics noise in EMC, APD, Low Gain - Float_t mTimeNoise{1.28e-5}; ///< Electronics noise in EMC, time - Float_t mTimeDelay{600e-9}; ///< Simple time delay to mimick roughly delay in data - Bool_t mTimeDelayFromOCDB{false}; ///< Get time delay from OCDB Float_t mTimeResolutionPar0{0.26666}; ///< Time resolution of FEE electronics Float_t mTimeResolutionPar1{1.4586}; ///< Time resolution of FEE electronics Int_t mNADCEC{0x10000}; ///< number of channels in EC section ADC diff --git a/Detectors/EMCAL/simulation/src/SimParam.cxx b/Detectors/EMCAL/simulation/src/SimParam.cxx index 74af39125f4c3..77fcc1366f9ea 100644 --- a/Detectors/EMCAL/simulation/src/SimParam.cxx +++ b/Detectors/EMCAL/simulation/src/SimParam.cxx @@ -30,9 +30,6 @@ void SimParam::PrintStream(std::ostream& stream) const stream << "\nEMCal::SimParam.mGainFluctuations = " << mGainFluctuations; stream << "\nEMCal::SimParam.mPinNoise = " << mPinNoise; stream << "\nEMCal::SimParam.mPinNoiseLG = " << mPinNoiseLG; - stream << "\nEMCal::SimParam.mTimeNoise = " << mTimeNoise; - stream << "\nEMCal::SimParam.mTimeDelay = " << mTimeDelay; - stream << "\nEMCal::SimParam.mTimeDelayFromOCDB = " << ((mTimeDelayFromOCDB) ? "true" : "false"); stream << "\nEMCal::SimParam.mTimeResolutionPar0 = " << mTimeResolutionPar0; stream << "\nEMCal::SimParam.mTimeResolutionPar1 = " << mTimeResolutionPar1; stream << "\nEMCal::SimParam.mTimeResponseTau = " << mTimeResponseTau; From cea8ac1306c986afd5a4ca302ac2db6b7317c230 Mon Sep 17 00:00:00 2001 From: gvolpe Date: Mon, 2 Oct 2023 15:57:12 +0200 Subject: [PATCH 231/324] Adding aluminium absorbers in front to chambers 2 and 4 --- .../include/HMPIDSimulation/Detector.h | 1 + Detectors/HMPID/simulation/src/Detector.cxx | 121 +++++++++++------- 2 files changed, 75 insertions(+), 47 deletions(-) diff --git a/Detectors/HMPID/simulation/include/HMPIDSimulation/Detector.h b/Detectors/HMPID/simulation/include/HMPIDSimulation/Detector.h index b55ba3b6c7353..9e9a78914049e 100644 --- a/Detectors/HMPID/simulation/include/HMPIDSimulation/Detector.h +++ b/Detectors/HMPID/simulation/include/HMPIDSimulation/Detector.h @@ -55,6 +55,7 @@ class Detector : public o2::base::DetImpl void EndOfEvent() override { Reset(); } // for the geometry sub-parts + TGeoVolume* createAbsorber(float tickness); TGeoVolume* createChamber(int number); TGeoVolume* CreateCradle(); TGeoVolume* CradleBaseVolume(TGeoMedium* med, double l[7], const char* name); diff --git a/Detectors/HMPID/simulation/src/Detector.cxx b/Detectors/HMPID/simulation/src/Detector.cxx index 674bf7e85441d..83bab71e7177d 100644 --- a/Detectors/HMPID/simulation/src/Detector.cxx +++ b/Detectors/HMPID/simulation/src/Detector.cxx @@ -73,20 +73,20 @@ bool Detector::ProcessHits(FairVolume* v) Int_t volID = fMC->CurrentVolID(copy); auto stack = (o2::data::Stack*)fMC->GetStack(); - //Treat photons - //photon (Ckov or feedback) hits on module PC (Hpad) + // Treat photons + // photon (Ckov or feedback) hits on module PC (Hpad) if ((fMC->TrackPid() == 50000050 || fMC->TrackPid() == 50000051) && (volID == mHpad0VolID || volID == mHpad1VolID || volID == mHpad2VolID || volID == mHpad3VolID || volID == mHpad4VolID || volID == mHpad5VolID || volID == mHpad6VolID)) { - if (fMC->Edep() > 0) { //photon survided QE test i.e. produces electron + if (fMC->Edep() > 0) { // photon survided QE test i.e. produces electron if (IsLostByFresnel()) { fMC->StopTrack(); return false; - } //photon lost due to fersnel reflection on PC - Int_t tid = fMC->GetStack()->GetCurrentTrackNumber(); //take TID - Int_t pid = fMC->TrackPid(); //take PID - Float_t etot = fMC->Etot(); //total hpoton energy, [GeV] + } // photon lost due to fersnel reflection on PC + Int_t tid = fMC->GetStack()->GetCurrentTrackNumber(); // take TID + Int_t pid = fMC->TrackPid(); // take PID + Float_t etot = fMC->Etot(); // total hpoton energy, [GeV] Double_t x[3]; - fMC->TrackPosition(x[0], x[1], x[2]); //take MARS position at entrance to PC - Float_t hitTime = (Float_t)fMC->TrackTime(); //hit formation time + fMC->TrackPosition(x[0], x[1], x[2]); // take MARS position at entrance to PC + Float_t hitTime = (Float_t)fMC->TrackTime(); // hit formation time Int_t idch; // chamber number if (volID == mHpad0VolID) { idch = 0; @@ -104,20 +104,20 @@ bool Detector::ProcessHits(FairVolume* v) idch = 6; } Double_t xl, yl; - o2::hmpid::Param::instance()->mars2Lors(idch, x, xl, yl); //take LORS position - AddHit(x[0], x[1], x[2], hitTime, etot, tid, idch); //HIT for photon, position at P, etot will be set to Q - GenFee(etot); //generate feedback photons etot is modified in hit ctor to Q of hit + o2::hmpid::Param::instance()->mars2Lors(idch, x, xl, yl); // take LORS position + AddHit(x[0], x[1], x[2], hitTime, etot, tid, idch); // HIT for photon, position at P, etot will be set to Q + GenFee(etot); // generate feedback photons etot is modified in hit ctor to Q of hit stack->addHit(GetDetId()); - } //photon hit PC and DE >0 + } // photon hit PC and DE >0 return kTRUE; - } //photon hit PC + } // photon hit PC - //Treat charged particles - static Float_t eloss; //need to store mip parameters between different steps + // Treat charged particles + static Float_t eloss; // need to store mip parameters between different steps static Double_t in[3]; if (fMC->IsTrackEntering() && fMC->TrackCharge() && (volID == mHpad0VolID || volID == mHpad1VolID || volID == mHpad2VolID || volID == mHpad3VolID || volID == mHpad4VolID || volID == mHpad5VolID || volID == mHpad6VolID)) { - //Trackref stored when entering in the pad volume + // Trackref stored when entering in the pad volume o2::TrackReference tr(*fMC, GetDetId()); tr.setTrackID(stack->GetCurrentTrackNumber()); // tr.setUserId(lay); @@ -126,18 +126,18 @@ bool Detector::ProcessHits(FairVolume* v) if (fMC->TrackCharge() && (volID == mHcel0VolID || volID == mHcel1VolID || volID == mHcel2VolID || volID == mHcel3VolID || volID == mHcel4VolID || volID == mHcel5VolID || volID == mHcel6VolID)) { // charged particle in amplification gap (Hcel) - if (fMC->IsTrackEntering() || fMC->IsNewTrack()) { //entering or newly created - eloss = 0; //reset Eloss collector - fMC->TrackPosition(in[0], in[1], in[2]); //take position at the entrance - } else if (fMC->IsTrackExiting() || fMC->IsTrackStop() || fMC->IsTrackDisappeared()) { //exiting or disappeared - eloss += fMC->Edep(); //take into account last step Eloss - Int_t tid = fMC->GetStack()->GetCurrentTrackNumber(); //take TID - Int_t pid = fMC->TrackPid(); //take PID + if (fMC->IsTrackEntering() || fMC->IsNewTrack()) { // entering or newly created + eloss = 0; // reset Eloss collector + fMC->TrackPosition(in[0], in[1], in[2]); // take position at the entrance + } else if (fMC->IsTrackExiting() || fMC->IsTrackStop() || fMC->IsTrackDisappeared()) { // exiting or disappeared + eloss += fMC->Edep(); // take into account last step Eloss + Int_t tid = fMC->GetStack()->GetCurrentTrackNumber(); // take TID + Int_t pid = fMC->TrackPid(); // take PID Double_t out[3]; - fMC->TrackPosition(out[0], out[1], out[2]); //take MARS position at exit - Float_t hitTime = (Float_t)fMC->TrackTime(); //hit formation time + fMC->TrackPosition(out[0], out[1], out[2]); // take MARS position at exit + Float_t hitTime = (Float_t)fMC->TrackTime(); // hit formation time out[0] = 0.5 * (out[0] + in[0]); // - out[1] = 0.5 * (out[1] + in[1]); //take hit position at the anod plane + out[1] = 0.5 * (out[1] + in[1]); // take hit position at the anod plane out[2] = 0.5 * (out[2] + in[2]); Int_t idch; // chamber number if (volID == mHcel0VolID) { @@ -156,20 +156,20 @@ bool Detector::ProcessHits(FairVolume* v) idch = 6; } Double_t xl, yl; - o2::hmpid::Param::instance()->mars2Lors(idch, out, xl, yl); //take LORS position + o2::hmpid::Param::instance()->mars2Lors(idch, out, xl, yl); // take LORS position if (eloss > 0) { // HIT for MIP, position near anod plane, eloss will be set to Q AddHit(out[0], out[1], out[2], hitTime, eloss, tid, idch); - GenFee(eloss); //generate feedback photons + GenFee(eloss); // generate feedback photons stack->addHit(GetDetId()); eloss = 0; } } else { - //just going inside - eloss += fMC->Edep(); //collect this step eloss + // just going inside + eloss += fMC->Edep(); // collect this step eloss } return kTRUE; - } //MIP in GAP + } // MIP in GAP // later on return true if there was a hit! return false; @@ -187,14 +187,14 @@ void Detector::GenFee(Float_t qtot) // eloss=0 means photon so only pulse height distribution is to be analysed. TLorentzVector x4; fMC->TrackPosition(x4); - Int_t iNphotons = fMC->GetRandom()->Poisson(0.02 * qtot); //# of feedback photons is proportional to the charge of hit - //AliDebug(1,Form("N photons=%i",iNphotons)); + Int_t iNphotons = fMC->GetRandom()->Poisson(0.02 * qtot); // # of feedback photons is proportional to the charge of hit + // AliDebug(1,Form("N photons=%i",iNphotons)); Int_t j; Float_t cthf, phif, enfp = 0, sthf, e1[3], e2[3], e3[3], vmod, uswop, dir[3], phi, pol[3], mom[4]; - //Generate photons - for (Int_t i = 0; i < iNphotons; i++) { //feedbacks loop + // Generate photons + for (Int_t i = 0; i < iNphotons; i++) { // feedbacks loop Double_t ranf[2]; - fMC->GetRandom()->RndmArray(2, ranf); //Sample direction + fMC->GetRandom()->RndmArray(2, ranf); // Sample direction cthf = ranf[0] * 2 - 1.0; if (cthf < 0) { continue; @@ -276,8 +276,8 @@ void Detector::GenFee(Float_t qtot) } fMC->Gdtom(pol, pol, 2); Int_t outputNtracksStored; - } //feedbacks loop -} //GenerateFeedbacks() + } // feedbacks loop +} // GenerateFeedbacks() //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Bool_t Detector::IsLostByFresnel() { @@ -301,7 +301,7 @@ Bool_t Detector::IsLostByFresnel() } else { return kFALSE; } -} //IsLostByFresnel() +} // IsLostByFresnel() //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Float_t Detector::Fresnel(Float_t ene, Float_t pdoti, Bool_t pola) { @@ -325,8 +325,8 @@ Float_t Detector::Fresnel(Float_t ene, Float_t pdoti, Bool_t pola) Float_t cn = csin[j] + ((csin[j + 1] - csin[j]) / 0.1) * (xe - en[j]); Float_t ck = csik[j] + ((csik[j + 1] - csik[j]) / 0.1) * (xe - en[j]); - //FORMULAE FROM HANDBOOK OF OPTICS, 33.23 OR - //W.R. HUNTER, J.O.S.A. 54 (1964),15 , J.O.S.A. 55(1965),1197 + // FORMULAE FROM HANDBOOK OF OPTICS, 33.23 OR + // W.R. HUNTER, J.O.S.A. 54 (1964),15 , J.O.S.A. 55(1965),1197 Float_t sinin = TMath::Sqrt((1. - pdoti) * (1. + pdoti)); Float_t tanin = sinin / pdoti; @@ -340,8 +340,8 @@ Float_t Detector::Fresnel(Float_t ene, Float_t pdoti, Bool_t pola) Float_t rp = rs * ((aO - sinin * tanin) * (aO - sinin * tanin) + b2) / ((aO + sinin * tanin) * (aO + sinin * tanin) + b2); - //CORRECTION FACTOR FOR SURFACE ROUGHNESS - //B.J. STAGG APPLIED OPTICS, 30(1991),4113 + // CORRECTION FACTOR FOR SURFACE ROUGHNESS + // B.J. STAGG APPLIED OPTICS, 30(1991),4113 Float_t sigraf = 18.; Float_t lamb = 1240 / ene; @@ -351,7 +351,7 @@ Float_t Detector::Fresnel(Float_t ene, Float_t pdoti, Bool_t pola) (4 * TMath::Pi() * pdoti * sigraf / lamb)); if (pola) { - Float_t pdotr = 0.8; //DEGREE OF POLARIZATION : 1->P , -1->S + Float_t pdotr = 0.8; // DEGREE OF POLARIZATION : 1->P , -1->S fresn = 0.5 * (rp * (1 + pdotr) + rs * (1 - pdotr)); } else { fresn = 0.5 * (rp + rs); @@ -359,7 +359,7 @@ Float_t Detector::Fresnel(Float_t ene, Float_t pdoti, Bool_t pola) fresn = fresn * rO; return fresn; -} //Fresnel() +} // Fresnel() //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void Detector::Register() { FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, true); } @@ -537,7 +537,15 @@ void Detector::createMaterials() Material(++matId, "Ar", aAr, zAr, dAr, radAr, absAr); Medium(kAr, "Ar", matId, unsens, itgfld, maxfld, tmaxfd, stemax, deemax, epsil, stmin); } - +//************************************************************************************************** +TGeoVolume* Detector::createAbsorber(float tickness) +{ + double cm = 1, mm = 0.1 * cm, um = 0.001 * mm; // default is cm + auto& matmgr = o2::base::MaterialManager::Instance(); + TGeoMedium* al = matmgr.getTGeoMedium("HMP_Al"); + TGeoVolume* abs = gGeoManager->MakeBox("Habs", al, tickness * mm / 2, 1300.00 * mm / 2, 1300 * mm / 2); + return abs; +} //************************************************************************************************** TGeoVolume* Detector::createChamber(int number) @@ -1252,6 +1260,25 @@ void Detector::ConstructGeometry() TGeoVolume* hmpcradle = CreateCradle(); + TGeoVolume* hmpidabs_cham2 = createAbsorber(40.0); + TGeoVolume* hmpidabs_cham4 = createAbsorber(80.0); + + double theta = 33.5; + + TGeoHMatrix* pMatrixAbs2 = new TGeoHMatrix; + const double trans2[] = {435.5, 0., -155.}; + pMatrixAbs2->SetTranslation(trans2); + pMatrixAbs2->RotateZ(theta); + + gGeoManager->GetVolume("barrel")->AddNode(hmpidabs_cham2, 0, pMatrixAbs2); + + TGeoHMatrix* pMatrixAbs4 = new TGeoHMatrix; + const double trans4[] = {435., 0., 155.}; + pMatrixAbs4->SetTranslation(trans4); + pMatrixAbs4->RotateZ(theta); + + gGeoManager->GetVolume("barrel")->AddNode(hmpidabs_cham4, 0, pMatrixAbs4); + for (Int_t iCh = 0; iCh <= 6; iCh++) { // place 7 chambers TGeoVolume* hmpid = createChamber(iCh); TGeoHMatrix* pMatrix = new TGeoHMatrix; From 88914b820591e3c6735a7eeb54f947bb34754f5b Mon Sep 17 00:00:00 2001 From: Laurent Aphecetche Date: Tue, 19 Sep 2023 15:40:26 +0200 Subject: [PATCH 232/324] MCH: fix bad-channels-ccdb metadata default type and add Created metadata tag for default object. --- Detectors/MUON/MCH/Conditions/src/bad-channels-ccdb.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Detectors/MUON/MCH/Conditions/src/bad-channels-ccdb.cxx b/Detectors/MUON/MCH/Conditions/src/bad-channels-ccdb.cxx index e0ac76154b1ce..7a63792d53ce8 100644 --- a/Detectors/MUON/MCH/Conditions/src/bad-channels-ccdb.cxx +++ b/Detectors/MUON/MCH/Conditions/src/bad-channels-ccdb.cxx @@ -80,7 +80,8 @@ void uploadBadChannels(const std::string ccdbUrl, << dest << "\n"; if (makeDefault) { - md["default"] = true; + md["default"] = "true"; + md["Created"] = "1"; } api.storeAsTFileAny(&bv, dest, md, startTimestamp, endTimestamp); } From 9441d8250f6bc4fbf62223455cfa98dcd6ee2f34 Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 6 Oct 2023 14:52:00 +0200 Subject: [PATCH 233/324] Add tracks time to trackStudy output --- Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx index cbd25f790686d..ce2d53d71c385 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx @@ -175,7 +175,10 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) if (!prop->propagateToDCA(pv, trc, prop->getNominalBz(), 2., o2::base::PropagatorF::MatCorrType::USEMatCorrLUT, &dca)) { continue; } + float ttime = 0, ttimeE = 0; + recoData.getTrackTime(vid, ttime, ttimeE); (*mDBGOut) << "dca" + << "tfID=" << TFCount << "ttime=" << ttime << "ttimeE=" << ttimeE << "gid=" << vid << "pv=" << pv << "trc=" << trc << "pvCont=" << pvCont << "ambig=" << ambig << "dca=" << dca << "xmin=" << xmin << "\n"; } } From e330a3235cfb9b8d8c3b78a852fb4c19e14cc738 Mon Sep 17 00:00:00 2001 From: Michael Lettrich Date: Mon, 2 Oct 2023 21:12:47 +0200 Subject: [PATCH 234/324] [rANS] Enforce Consistent Histograms --- .../EncodedBlocks.h | 21 ++++++++++++++++++- .../rANS/internal/containers/DenseHistogram.h | 11 +++++++++- .../include/rANS/internal/transform/renorm.h | 2 +- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index 13cd7d2b122d5..16a659746e973 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -339,7 +339,10 @@ class EncodedBlocks using dictionaryType = std::variant, rans::RenormedDenseHistogram>; #endif - void setHeader(const H& h) { mHeader = h; } + void setHeader(const H& h) + { + mHeader = h; + } const H& getHeader() const { return mHeader; } H& getHeader() { return mHeader; } std::shared_ptr cloneHeader() const { return std::shared_ptr(new H(mHeader)); } // for dictionary creation @@ -371,6 +374,22 @@ class EncodedBlocks assert(static_cast(std::numeric_limits::min()) <= static_cast(metadata.max)); assert(static_cast(std::numeric_limits::max()) >= static_cast(metadata.min)); + // check consistency of metadata and type + [&]() { + const int64_t sourceMin = std::numeric_limits::min(); + const int64_t sourceMax = std::numeric_limits::max(); + + auto view = rans::trim(rans::HistogramView{block.getDict(), block.getDict() + block.getNDict(), metadata.min}); + const int64_t dictMin = view.getMin(); + const int64_t dictMax = view.getMax(); + assert(dictMin >= metadata.min); + assert(dictMax <= metadata.max); + + if ((dictMin < sourceMin) || (dictMax > sourceMax)) { + throw std::runtime_error(fmt::format("value range of dictionary and target datatype are incompatible: target type [{},{}] vs dictionary [{},{}]", sourceMin, sourceMax, dictMin, dictMax)); + } + }(); + if (ansVersion == ANSVersionCompat) { rans::DenseHistogram histogram{block.getDict(), block.getDict() + block.getNDict(), metadata.min}; return rans::compat::renorm(std::move(histogram), metadata.probabilityBits); diff --git a/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h b/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h index 354ee96b84f48..844e0c9695a32 100644 --- a/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h +++ b/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h @@ -586,7 +586,16 @@ auto DenseHistogram>::addFrequ addedHistogramView = trim(addedHistogramView); if constexpr (std::is_unsigned_v) { - LOG_IF(warning, addedHistogramView.getMin() < 0) << fmt::format("trying to add frequencies for a signed symbol to a DenseHistogram of an unsiged type."); + LOG_IF(warning, addedHistogramView.getMin() < 0) << fmt::format("trying to add frequencies of a signed symbol type to a DenseHistogram of an unsiged type."); + } + if constexpr (std::is_signed_v) { + const std::ptrdiff_t sourceTypeMax = std::numeric_limits::max(); + const bool isMinOutOfRange = addedHistogramView.getMin() > sourceTypeMax; + const bool isMaxOutOfRange = addedHistogramView.getMax() > sourceTypeMax; + + if (isMaxOutOfRange || isMinOutOfRange) { + LOGP(warning, "trying to add frequencies of an unsigned symbol type to a DenseHistogram of a signed type"); + } } const auto thisHistogramView = makeHistogramView(this->mContainer); diff --git a/Utilities/rANS/include/rANS/internal/transform/renorm.h b/Utilities/rANS/include/rANS/internal/transform/renorm.h index 5e3d7d551a665..5d55b3553ceca 100644 --- a/Utilities/rANS/include/rANS/internal/transform/renorm.h +++ b/Utilities/rANS/include/rANS/internal/transform/renorm.h @@ -143,7 +143,7 @@ decltype(auto) renorm(histogram_T histogram, Metrics Date: Tue, 3 Oct 2023 22:29:54 +0200 Subject: [PATCH 235/324] [rANS] Fix Compiler Warnings --- .../DetectorsCommonDataFormats/EncodedBlocks.h | 4 +--- .../internal/ExternalEntropyCoder.h | 2 +- .../internal/InplaceEntropyCoder.h | 1 - .../Detectors/Common/test/testCTFEntropyCoder.cxx | 4 ++-- Utilities/rANS/benchmarks/bench_ransHistogram.cxx | 4 ++-- .../rANS/internal/containers/DenseHistogram.h | 4 +--- .../internal/containers/ReverseSymbolLookupTable.h | 4 ++-- .../rANS/include/rANS/internal/containers/Symbol.h | 7 ++----- .../rANS/include/rANS/internal/encode/Encoder.h | 4 ++++ .../rANS/internal/encode/EncoderSymbolMapper.h | 4 ---- .../rANS/internal/encode/SingleStreamEncoderImpl.h | 2 -- .../rANS/internal/pack/DictionaryStreamReader.h | 2 +- .../include/rANS/internal/transform/algorithmImpl.h | 2 +- .../rANS/include/rANS/internal/transform/renorm.h | 1 - Utilities/rANS/run/bin-encode-decode.cxx | 2 +- Utilities/rANS/test/test_ransHistograms.cxx | 3 --- Utilities/rANS/test/test_ransMetrics.cxx | 1 - Utilities/rANS/test/test_ransPack.cxx | 3 +-- Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx | 12 +++++++----- Utilities/rANS/test/test_ransSparseVector.cxx | 2 -- Utilities/rANS/test/test_ransSymbolTables.cxx | 2 +- 21 files changed, 27 insertions(+), 43 deletions(-) diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index 16a659746e973..3ffdec9841cb4 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -838,7 +838,7 @@ auto EncodedBlocks::getImage(const void* newHead) // we don't modify newHead, but still need to remove constness for relocation interface relocate(image.mRegistry.head, const_cast(reinterpret_cast(newHead)), reinterpret_cast(&image)); - return std::move(image); + return image; } ///_____________________________________________________________________________ @@ -948,7 +948,6 @@ CTFIOSize EncodedBlocks::decodeCompatImpl(dst_IT dstBegin, int slot, co { // get references to the right data - const auto& ansVersion = getANSHeader(); const auto& block = mBlocks[slot]; const auto& md = mMetadata[slot]; @@ -987,7 +986,6 @@ CTFIOSize EncodedBlocks::decodeRansV1Impl(dst_IT dstBegin, int slot, co { // get references to the right data - const auto& ansVersion = getANSHeader(); const auto& block = mBlocks[slot]; const auto& md = mMetadata[slot]; diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h index 6a8be509c021c..5335514278e26 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/ExternalEntropyCoder.h @@ -79,7 +79,7 @@ template constexpr size_t Overhead = 10 * rans::utils::pow2(10); // 10KB overhead safety margin const double_t RelativeSafetyFactor = 2.0 * safetyFactor; const size_t messageSizeB = nElements * sizeof(source_type); - return rans::utils::nBytesTo(std::ceil(safetyFactor * messageSizeB) + Overhead); + return rans::utils::nBytesTo(std::ceil(RelativeSafetyFactor * messageSizeB) + Overhead); } template diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h index 54302d51d2666..8601469b34142 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/internal/InplaceEntropyCoder.h @@ -166,7 +166,6 @@ void InplaceEntropyCoder::makeEncoder() } const size_t rangeBits = rans::utils::getRangeBits(*mMetrics.getCoderProperties().min, *mMetrics.getCoderProperties().max); - const size_t nSamples = mMetrics.getDatasetProperties().numSamples; const size_t nUsedAlphabetSymbols = mMetrics.getDatasetProperties().nUsedAlphabetSymbols; if (rangeBits <= 18) { diff --git a/DataFormats/Detectors/Common/test/testCTFEntropyCoder.cxx b/DataFormats/Detectors/Common/test/testCTFEntropyCoder.cxx index 3471a6c9e4dff..6b688fcebc7f7 100644 --- a/DataFormats/Detectors/Common/test/testCTFEntropyCoder.cxx +++ b/DataFormats/Detectors/Common/test/testCTFEntropyCoder.cxx @@ -126,7 +126,7 @@ void encodeInplace(source_IT begin, source_IT end) std::vector dictBuffer(sizeEstimate.getCompressedDictionarySize(), 0); auto encoderEnd = entropyCoder.encode(begin, end, encodeBuffer.data(), encodeBuffer.data() + encodeBuffer.size()); - auto literalsEnd = entropyCoder.writeIncompressible(literalSymbolsBuffer.data(), literalSymbolsBuffer.data() + literalSymbolsBuffer.size()); + [[maybe_unused]] auto literalsEnd = entropyCoder.writeIncompressible(literalSymbolsBuffer.data(), literalSymbolsBuffer.data() + literalSymbolsBuffer.size()); auto dictEnd = entropyCoder.writeDictionary(dictBuffer.data(), dictBuffer.data() + dictBuffer.size()); // decode const auto& coderProperties = metrics.getCoderProperties(); @@ -303,7 +303,7 @@ void encodeExternal(source_IT begin, source_IT end) auto encoderEnd = entropyCoder.encode(begin, end, encodeBuffer.data(), encodeBuffer.data() + encodeBuffer.size()); std::vector literalSymbolsBuffer(entropyCoder.template computePackedIncompressibleSize(), 0); - auto literalsEnd = entropyCoder.writeIncompressible(literalSymbolsBuffer.data(), literalSymbolsBuffer.data() + literalSymbolsBuffer.size()); + [[maybe_unused]] auto literalsEnd = entropyCoder.writeIncompressible(literalSymbolsBuffer.data(), literalSymbolsBuffer.data() + literalSymbolsBuffer.size()); // decode auto decoder = ExternalEncoders.getDecoder(); diff --git a/Utilities/rANS/benchmarks/bench_ransHistogram.cxx b/Utilities/rANS/benchmarks/bench_ransHistogram.cxx index 9c32117ba914b..084d4b8fca1bc 100644 --- a/Utilities/rANS/benchmarks/bench_ransHistogram.cxx +++ b/Utilities/rANS/benchmarks/bench_ransHistogram.cxx @@ -137,7 +137,7 @@ void ransMakeHistogramBenchmark(benchmark::State& st, Args&&... args) histogram_type hist{}; hist.addSamples(gsl::span(inputData)); - for (std::ptrdiff_t symbol = histogram.getOffset(); symbol != histogram.getOffset() + histogram.size(); ++symbol) { + for (std::ptrdiff_t symbol = histogram.getOffset(); symbol != histogram.getOffset() + static_cast(histogram.size()); ++symbol) { if (histogram[symbol] > 0) { LOG_IF(info, histogram[symbol] != hist[symbol]) << fmt::format("[{}]: {} != {}", symbol, hist[symbol], histogram[symbol]); isSame = isSame && (histogram[symbol] == hist[symbol]); @@ -190,7 +190,7 @@ void ransAccessHistogramBenchmark(benchmark::State& st, Args&&... args) #endif bool isSame = true; - for (std::ptrdiff_t symbol = histogram.getOffset(); symbol != histogram.getOffset() + histogram.size(); ++symbol) { + for (std::ptrdiff_t symbol = histogram.getOffset(); symbol != histogram.getOffset() + static_cast(histogram.size()); ++symbol) { if (histogram[symbol] > 0) { LOG_IF(info, histogram[symbol] != hist[symbol]) << fmt::format("[{}]: {} != {}", symbol, hist[symbol], histogram[symbol]); isSame = isSame && (histogram[symbol] == hist[symbol]); diff --git a/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h b/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h index 844e0c9695a32..177245ef7bec6 100644 --- a/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h +++ b/Utilities/rANS/include/rANS/internal/containers/DenseHistogram.h @@ -184,7 +184,7 @@ inline bool DenseHistogram>::i ret = false; } } - if (max - min > this->MaxSize) { + if (max - min > static_cast(this->MaxSize)) { LOGP(warning, "DenseHistogram exceeds {} elements threshold", this->MaxSize); ret = false; } @@ -233,8 +233,6 @@ inline auto DenseHistogram>::a constexpr size_t nUnroll = 4 * ElemsPerQWord; auto iter = begin; - const source_type offset = this->getOffset(); - if (getRangeBits(min, max) <= 17) { container_type histogram{this->mContainer.size(), this->mContainer.getOffset()}; diff --git a/Utilities/rANS/include/rANS/internal/containers/ReverseSymbolLookupTable.h b/Utilities/rANS/include/rANS/internal/containers/ReverseSymbolLookupTable.h index 506aaaf53fa40..3a79619b2338d 100644 --- a/Utilities/rANS/include/rANS/internal/containers/ReverseSymbolLookupTable.h +++ b/Utilities/rANS/include/rANS/internal/containers/ReverseSymbolLookupTable.h @@ -71,8 +71,8 @@ class ReverseSymbolLookupTable return mLut[cumul]; }; - inline const iterator_type begin() const noexcept { return mLut.data(); }; - inline const iterator_type end() const noexcept { return mLut.data() + size(); }; + inline iterator_type begin() const noexcept { return mLut.data(); }; + inline iterator_type end() const noexcept { return mLut.data() + size(); }; container_type mLut{}; }; diff --git a/Utilities/rANS/include/rANS/internal/containers/Symbol.h b/Utilities/rANS/include/rANS/internal/containers/Symbol.h index 0c00c46e1a627..5269447e22344 100644 --- a/Utilities/rANS/include/rANS/internal/containers/Symbol.h +++ b/Utilities/rANS/include/rANS/internal/containers/Symbol.h @@ -37,11 +37,8 @@ class Symbol // TODO(milettri): fix once ROOT cling respects the standard http://wg21.link/p1286r2 constexpr Symbol() noexcept {}; // NOLINT - constexpr Symbol(value_type frequency, value_type cumulative, size_t symbolTablePrecision = 0) - : mSymbol{frequency, cumulative} - { - (void)symbolTablePrecision; // silence compiler warnings - }; + constexpr Symbol(value_type frequency, value_type cumulative, [[maybe_unused]] size_t symbolTablePrecision = 0) + : mSymbol{frequency, cumulative} {}; [[nodiscard]] inline constexpr value_type getFrequency() const noexcept { return mSymbol[0]; }; [[nodiscard]] inline constexpr value_type getCumulative() const noexcept { return mSymbol[1]; }; [[nodiscard]] inline constexpr const value_type* data() const noexcept { return mSymbol.data(); }; diff --git a/Utilities/rANS/include/rANS/internal/encode/Encoder.h b/Utilities/rANS/include/rANS/internal/encode/Encoder.h index ef097992ac9cd..fb6015b7aa021 100644 --- a/Utilities/rANS/include/rANS/internal/encode/Encoder.h +++ b/Utilities/rANS/include/rANS/internal/encode/Encoder.h @@ -143,7 +143,11 @@ decltype(auto) Encoder::process(source_IT EncoderSymbolMapper symbolMapper{this->mSymbolTable, literalsBegin}; typename coder_type::symbol_type encoderSymbols[2]{}; + // one past the end. Will not be dereferenced, thus safe. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" coder_type* codersREnd = advanceIter(coders.data(), -1); +#pragma GCC diagnostic pop coder_type* activeCoder = codersREnd + nPartialCoderIterations; // we are encoding backwards! diff --git a/Utilities/rANS/include/rANS/internal/encode/EncoderSymbolMapper.h b/Utilities/rANS/include/rANS/internal/encode/EncoderSymbolMapper.h index 083dad90f81c6..8925dfb6b34cf 100644 --- a/Utilities/rANS/include/rANS/internal/encode/EncoderSymbolMapper.h +++ b/Utilities/rANS/include/rANS/internal/encode/EncoderSymbolMapper.h @@ -254,8 +254,6 @@ class EncoderSymbolMapper frequencies; @@ -330,8 +328,6 @@ class EncoderSymbolMapper frequencies; diff --git a/Utilities/rANS/include/rANS/internal/encode/SingleStreamEncoderImpl.h b/Utilities/rANS/include/rANS/internal/encode/SingleStreamEncoderImpl.h index 580df53fc64bd..ff7d6535365e0 100644 --- a/Utilities/rANS/include/rANS/internal/encode/SingleStreamEncoderImpl.h +++ b/Utilities/rANS/include/rANS/internal/encode/SingleStreamEncoderImpl.h @@ -145,8 +145,6 @@ class SingleStreamEncoderImpl : public SingleStreamEncoderImplBasegetFrequency() != 0); - const state_type old = this->mState; - const auto [newState, streamPosition] = this->renorm(this->mState, outputIter, symbol->getFrequency()); // coding function state_type quotient = static_cast((static_cast(newState) * symbol->getReciprocalFrequency()) >> 64); diff --git a/Utilities/rANS/include/rANS/internal/pack/DictionaryStreamReader.h b/Utilities/rANS/include/rANS/internal/pack/DictionaryStreamReader.h index f84eaebf25fb9..0109abe102fc3 100644 --- a/Utilities/rANS/include/rANS/internal/pack/DictionaryStreamReader.h +++ b/Utilities/rANS/include/rANS/internal/pack/DictionaryStreamReader.h @@ -84,7 +84,7 @@ class DictionaryStreamParser template template -DictionaryStreamParser::DictionaryStreamParser(buffer_IT begin, buffer_IT end, source_type max) : mEnd{begin}, mPos{end}, mIndex(max) +DictionaryStreamParser::DictionaryStreamParser(buffer_IT begin, buffer_IT end, source_type max) : mPos{end}, mEnd{begin}, mIndex(max) { static_assert(std::is_pointer_v, "can only deserialize from raw pointers"); diff --git a/Utilities/rANS/include/rANS/internal/transform/algorithmImpl.h b/Utilities/rANS/include/rANS/internal/transform/algorithmImpl.h index 84dff9609a574..382f116d5ca04 100644 --- a/Utilities/rANS/include/rANS/internal/transform/algorithmImpl.h +++ b/Utilities/rANS/include/rANS/internal/transform/algorithmImpl.h @@ -161,7 +161,7 @@ inline void forEachIndexValue(container_T&& container, IT begin, IT end, F funct using container_type = removeCVRef_t; typename container_type::source_type index = container.getOffset() + std::distance(container.begin(), begin); - for (size_t i = 0; i < std::distance(begin, end); ++i) { + for (std::ptrdiff_t i = 0; i < std::distance(begin, end); ++i) { functor(index++, begin[i]); } } diff --git a/Utilities/rANS/include/rANS/internal/transform/renorm.h b/Utilities/rANS/include/rANS/internal/transform/renorm.h index 5d55b3553ceca..8d8ab238aaa91 100644 --- a/Utilities/rANS/include/rANS/internal/transform/renorm.h +++ b/Utilities/rANS/include/rANS/internal/transform/renorm.h @@ -74,7 +74,6 @@ decltype(auto) renorm(histogram_T histogram, Metrics(5), 5}, }; - const size_t fixedSizeOffset = std::numeric_limits::min(); - histogram_T histogram{}; histogram.addFrequencies(frequencies.begin(), frequencies.end(), 0); @@ -389,7 +387,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_addFrequenciesSignChange, histogram_T, histog const std::ptrdiff_t offset = utils::pow2(utils::toBits() - 1); if constexpr (std::is_same_v>) { - const std::ptrdiff_t largeOffset = utils::toBits() - 1; BOOST_CHECK_THROW(histogram.addFrequencies(frequencies2.begin(), frequencies2.end(), offset), HistogramError); BOOST_CHECK_THROW(histogram2.addFrequencies(gsl::make_span(frequencies2), offset), HistogramError); } else { diff --git a/Utilities/rANS/test/test_ransMetrics.cxx b/Utilities/rANS/test/test_ransMetrics.cxx index 42dcf7519f664..4370194306f1d 100644 --- a/Utilities/rANS/test/test_ransMetrics.cxx +++ b/Utilities/rANS/test/test_ransMetrics.cxx @@ -238,7 +238,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_singleElementMetrics, histogram_T, histogram_ std::vector frequencies{5}; histogram_T histogram{frequencies.begin(), frequencies.end(), 2}; const auto [min, max] = getMinMax(histogram); - const float eps = 1e-2; const size_t nUsedAlphabetSymbols = countNUsedAlphabetSymbols(histogram); const Metrics metrics{histogram}; diff --git a/Utilities/rANS/test/test_ransPack.cxx b/Utilities/rANS/test/test_ransPack.cxx index bc63ad04cdf96..e6aaaffa79ebf 100644 --- a/Utilities/rANS/test/test_ransPack.cxx +++ b/Utilities/rANS/test/test_ransPack.cxx @@ -56,7 +56,6 @@ using source_types = boost::mp11::mp_list BOOST_AUTO_TEST_CASE_TEMPLATE(test_computePackingBufferSize, buffer_T, buffer_types) { - size_t nElems{}; size_t packingWidth = utils::toBits() - 3; BOOST_CHECK_EQUAL(0, (computePackingBufferSize(0, packingWidth))); @@ -132,7 +131,7 @@ BOOST_AUTO_TEST_CASE(test_packUnpackStream) source_type min = *std::min_element(source.begin(), source.end()); - auto packingBufferEnd = pack(source.data(), source.size(), packingBuffer.data(), packingWidth, min); + [[maybe_unused]] auto packingBufferEnd = pack(source.data(), source.size(), packingBuffer.data(), packingWidth, min); std::vector unpackBuffer(source.size(), 0); unpack(packingBuffer.data(), source.size(), unpackBuffer.data(), packingWidth, min); diff --git a/Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx b/Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx index 12f65a6c610b6..ea099fd2238f7 100644 --- a/Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx +++ b/Utilities/rANS/test/test_ransSIMDEncoderKernels.cxx @@ -120,7 +120,9 @@ struct AosToSoaFixture { uint32_t counter = 0; for (size_t i = 0; i < nElems; ++i) { - Symbol symbol{counter++, counter++, 0}; + const auto freq = counter++; + const auto cumul = counter++; + Symbol symbol{freq, cumul, 0}; mFrequencies(i) = symbol.getFrequency(); mCumulative(i) = symbol.getCumulative(); @@ -228,10 +230,10 @@ struct SSERenormFixture { statesVec[0] = load(states[0]); statesVec[1] = load(states[1]); - stream_iterator newstreamOutIter = ransRenorm(statesVec, - frequenciesVec, - SymbolTablePrecisionBits, - streamOutBuffer.begin(), newStatesVec); + [[maybe_unused]] stream_iterator newstreamOutIter = ransRenorm(statesVec, + frequenciesVec, + SymbolTablePrecisionBits, + streamOutBuffer.begin(), newStatesVec); epi64_t newStates(0); store(newStatesVec[0], newStates[0]); diff --git a/Utilities/rANS/test/test_ransSparseVector.cxx b/Utilities/rANS/test/test_ransSparseVector.cxx index fab69aa5750ad..fc1a2980e3226 100644 --- a/Utilities/rANS/test/test_ransSparseVector.cxx +++ b/Utilities/rANS/test/test_ransSparseVector.cxx @@ -47,8 +47,6 @@ BOOST_AUTO_TEST_CASE(test_write) { sparseVector_type vec{}; - const size_t fixedSizeOffset = std::numeric_limits::min(); - std::vector samples{-5, -2, 1, 3, 5, 8, -5, 5, 1, 1, 1, 14, 8, 8, 8, 8, 8, 8, 8, 8, utils::pow2(18) + 1}; std::unordered_map results{{-5, 2}, {-2, 1}, {-1, 0}, {0, 0}, {1, 4}, {2, 0}, {3, 1}, {4, 0}, {5, 2}, {8, 9}, {14, 1}, {utils::pow2(18) + 1, 1}}; diff --git a/Utilities/rANS/test/test_ransSymbolTables.cxx b/Utilities/rANS/test/test_ransSymbolTables.cxx index 5384607b2b0c4..bbadb8c8c46a0 100644 --- a/Utilities/rANS/test/test_ransSymbolTables.cxx +++ b/Utilities/rANS/test/test_ransSymbolTables.cxx @@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_symbolTable, histogram_T, histogram_t) BOOST_CHECK_EQUAL(symbolTable.getPrecision(), scaleBits); - for (source_type index = 0; index < rescaledFrequencies.size(); ++index) { + for (source_type index = 0; index < static_cast(rescaledFrequencies.size()); ++index) { auto symbol = symbolTable[index + 6]; BOOST_CHECK_EQUAL(symbol.getFrequency(), rescaledFrequencies[index]); BOOST_CHECK_EQUAL(symbol.getCumulative(), cumulativeFrequencies[index]); From a06788f1084c8859b9d0b883fcd3489abd665dc0 Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 6 Oct 2023 20:03:01 +0200 Subject: [PATCH 236/324] Fix in the Close method --- Common/Utils/src/TreeStreamRedirector.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Common/Utils/src/TreeStreamRedirector.cxx b/Common/Utils/src/TreeStreamRedirector.cxx index 86e0eb5a37552..4c21fcd602543 100644 --- a/Common/Utils/src/TreeStreamRedirector.cxx +++ b/Common/Utils/src/TreeStreamRedirector.cxx @@ -111,7 +111,9 @@ TreeStream& TreeStreamRedirector::operator<<(const char* name) void TreeStreamRedirector::Close() { // flush and close - + if (!mDirectory) { + return; + } TDirectory* backup = gDirectory; mDirectory->cd(); for (auto& layout : mDataLayouts) { From 40020ff86e529132fd51fc70fdc5284f4a4c76ec Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 6 Oct 2023 20:03:05 +0200 Subject: [PATCH 237/324] Store TFIDInfo TTree together with the vector --- .../src/tfidinfo-writer-workflow.cxx | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/Detectors/GlobalTrackingWorkflow/src/tfidinfo-writer-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/tfidinfo-writer-workflow.cxx index 624e2602fda42..8843570fc3b52 100644 --- a/Detectors/GlobalTrackingWorkflow/src/tfidinfo-writer-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/tfidinfo-writer-workflow.cxx @@ -26,9 +26,7 @@ void customize(std::vector& policies) void customize(std::vector& workflowOptions) { // option allowing to set parameters - std::vector options{ - ConfigParamSpec{"dataspec", VariantType::String, "tfidinfo:FLP/DISTSUBTIMEFRAME/0xccdb", {"spec from which the TFIDInfo will be extracted"}}, - ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + std::vector options{ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; std::swap(workflowOptions, options); } @@ -37,7 +35,10 @@ void customize(std::vector& workflowOptions) #include "Framework/DataProcessingHeader.h" #include "Framework/Task.h" #include "CommonDataFormat/TFIDInfo.h" +#include "CommonUtils/TreeStreamRedirector.h" #include "CommonUtils/NameConf.h" +#include "CommonConstants/LHCConstants.h" +#include "Framework/CCDBParamSpec.h" #include #include @@ -53,17 +54,31 @@ class TFIDInfoWriter : public o2::framework::Task void run(o2::framework::ProcessingContext& pc) final { + const auto& tinfo = pc.services().get(); + if (tinfo.globalRunNumberChanged) { // new run is starting + auto v = pc.inputs().get*>("orbitReset"); + mOrbitReset = (*v)[0]; + } o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mData.emplace_back()); } void endOfStream(EndOfStreamContext& ec) final { + o2::utils::TreeStreamRedirector pcstream; TFile fl(mOutFileName.c_str(), "recreate"); fl.WriteObjectAny(&mData, "std::vector", "tfidinfo"); - LOGP(info, "Wrote TFIDInfo vector with {} entries to {}", mData.size(), fl.GetName()); + pcstream.SetFile(&fl); + for (const auto& info : mData) { + long ts = (mOrbitReset + long(info.firstTForbit * o2::constants::lhc::LHCOrbitMUS)) / 1000; + pcstream << "tfidTree" + << "tfidinfo=" << info << "ts=" << ts << "\n"; + } + pcstream.Close(); + LOGP(info, "Wrote tfidinfo vector and tfidTree with {} entries to {}", mData.size(), fl.GetName()); } private: + long mOrbitReset = 0; std::string mOutFileName{}; std::vector mData; }; @@ -72,8 +87,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { WorkflowSpec wf; o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(DataProcessorSpec{"tfid-info-writer", o2::framework::select(cfgc.options().get("dataspec").c_str()), - std::vector{}, AlgorithmSpec{adaptFromTask()}, + wf.emplace_back(DataProcessorSpec{"tfid-info-writer", + {{"orbitReset", "CTP", "ORBITRESET", 0, Lifetime::Condition, ccdbParamSpec("CTP/Calib/OrbitReset")}}, + std::vector{}, + AlgorithmSpec{adaptFromTask()}, Options{{"tfidinfo-file-name", VariantType::String, o2::base::NameConf::getTFIDInfoFileName(), {"output file for TFIDInfo"}}}}); return wf; } From 639459541c6b0a9cab998e0f19269be334f8ab44 Mon Sep 17 00:00:00 2001 From: Francesco Noferini Date: Sat, 7 Oct 2023 16:11:47 +0200 Subject: [PATCH 238/324] TOF: add flag to compressor to skip large payloads (#12040) --- .../include/TOFCompression/CompressorTask.h | 3 ++- .../TOFCompression/CompressorTaskOld.h | 3 ++- .../TOF/compression/src/CompressorTask.cxx | 11 ++++++++++- .../TOF/compression/src/CompressorTaskOld.cxx | 11 ++++++++++- .../TOF/compression/src/tof-compressor.cxx | 19 +++++++++++-------- 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/Detectors/TOF/compression/include/TOFCompression/CompressorTask.h b/Detectors/TOF/compression/include/TOFCompression/CompressorTask.h index e18cde9d3dc4e..cd3823857677d 100644 --- a/Detectors/TOF/compression/include/TOFCompression/CompressorTask.h +++ b/Detectors/TOF/compression/include/TOFCompression/CompressorTask.h @@ -33,7 +33,7 @@ template class CompressorTask : public Task { public: - CompressorTask() = default; + CompressorTask(long payloadLim = -1) : mPayloadLimit(payloadLim) {} ~CompressorTask() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -41,6 +41,7 @@ class CompressorTask : public Task private: Compressor mCompressor; int mOutputBufferSize; + long mPayloadLimit = -1; }; } // namespace tof diff --git a/Detectors/TOF/compression/include/TOFCompression/CompressorTaskOld.h b/Detectors/TOF/compression/include/TOFCompression/CompressorTaskOld.h index 12beead1087ba..ed78dd88caa64 100644 --- a/Detectors/TOF/compression/include/TOFCompression/CompressorTaskOld.h +++ b/Detectors/TOF/compression/include/TOFCompression/CompressorTaskOld.h @@ -33,7 +33,7 @@ template class CompressorTaskOld : public Task { public: - CompressorTaskOld() = default; + CompressorTaskOld(long payloadLim = -1) : mPayloadLimit(payloadLim) {} ~CompressorTaskOld() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -41,6 +41,7 @@ class CompressorTaskOld : public Task private: Compressor mCompressor; int mOutputBufferSize; + long mPayloadLimit = -1; }; } // namespace tof diff --git a/Detectors/TOF/compression/src/CompressorTask.cxx b/Detectors/TOF/compression/src/CompressorTask.cxx index 90235c86f40cf..cad61e9ed0576 100644 --- a/Detectors/TOF/compression/src/CompressorTask.cxx +++ b/Detectors/TOF/compression/src/CompressorTask.cxx @@ -30,7 +30,11 @@ namespace o2::tof template void CompressorTask::init(InitContext& ic) { - LOG(info) << "Compressor init"; + if (mPayloadLimit < 0) { + LOG(info) << "Compressor init"; + } else { + LOG(info) << "Compressor init with Payload limit at " << mPayloadLimit; + } auto decoderCONET = ic.options().get("tof-compressor-conet-mode"); auto decoderVerbose = ic.options().get("tof-compressor-decoder-verbose"); @@ -137,6 +141,11 @@ void CompressorTask::run(ProcessingContext& pc) auto payloadIn = ref.payload; auto payloadInSize = DataRefUtils::getPayloadSize(ref); + if (mPayloadLimit > -1 && payloadInSize > mPayloadLimit) { + LOG(error) << "Payload larger than limit (" << mPayloadLimit << "), payload = " << payloadInSize; + continue; + } + /** prepare compressor **/ mCompressor.setDecoderBuffer(payloadIn); mCompressor.setDecoderBufferSize(payloadInSize); diff --git a/Detectors/TOF/compression/src/CompressorTaskOld.cxx b/Detectors/TOF/compression/src/CompressorTaskOld.cxx index 333b79865de2d..1a4e28393a8c3 100644 --- a/Detectors/TOF/compression/src/CompressorTaskOld.cxx +++ b/Detectors/TOF/compression/src/CompressorTaskOld.cxx @@ -36,7 +36,11 @@ namespace tof template void CompressorTaskOld::init(InitContext& ic) { - LOG(info) << "Compressor init"; + if (mPayloadLimit < 0) { + LOG(info) << "Compressor init"; + } else { + LOG(info) << "Compressor init with Payload limit at " << mPayloadLimit; + } auto decoderCONET = ic.options().get("tof-compressor-conet-mode"); auto decoderVerbose = ic.options().get("tof-compressor-decoder-verbose"); @@ -166,6 +170,11 @@ void CompressorTaskOld::run(ProcessingContext& pc) auto payloadIn = ref.payload; auto payloadInSize = DataRefUtils::getPayloadSize(ref); + if (mPayloadLimit > -1 && payloadInSize > mPayloadLimit) { + LOG(error) << "Payload larger than limit (" << mPayloadLimit << "), payload = " << payloadInSize; + continue; + } + /** prepare compressor **/ mCompressor.setDecoderBuffer(payloadIn); mCompressor.setDecoderBufferSize(payloadInSize); diff --git a/Detectors/TOF/compression/src/tof-compressor.cxx b/Detectors/TOF/compression/src/tof-compressor.cxx index 9d248fcaf8db2..604609e1080d6 100644 --- a/Detectors/TOF/compression/src/tof-compressor.cxx +++ b/Detectors/TOF/compression/src/tof-compressor.cxx @@ -36,6 +36,7 @@ void customize(std::vector& workflowOptions) auto verbose = ConfigParamSpec{"tof-compressor-verbose", VariantType::Bool, false, {"Enable verbose compressor"}}; auto paranoid = ConfigParamSpec{"tof-compressor-paranoid", VariantType::Bool, false, {"Enable paranoid compressor"}}; auto ignoreStf = ConfigParamSpec{"ignore-dist-stf", VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}; + auto payloadlim = ConfigParamSpec{"payload-limit", VariantType::Int64, -1ll, {"Payload limit in Byte (-1 -> no limits)"}}; workflowOptions.push_back(config); workflowOptions.push_back(outputDesc); @@ -43,6 +44,7 @@ void customize(std::vector& workflowOptions) workflowOptions.push_back(verbose); workflowOptions.push_back(paranoid); workflowOptions.push_back(ignoreStf); + workflowOptions.push_back(payloadlim); workflowOptions.emplace_back(ConfigParamSpec{"old", VariantType::Bool, false, {"use the non-DPL version of the compressor"}}); workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}); } @@ -60,6 +62,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) auto paranoid = cfgc.options().get("tof-compressor-paranoid"); auto ignoreStf = cfgc.options().get("ignore-dist-stf"); auto old = cfgc.options().get("old"); + auto payloadLim = cfgc.options().get("payload-limit"); std::vector outputs; outputs.emplace_back(OutputSpec(ConcreteDataTypeMatcher{"TOF", "CRAWDATA"})); @@ -68,30 +71,30 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) if (rdhVersion == o2::raw::RDHUtils::getVersion()) { if (!verbose && !paranoid) { if (old) { - algoSpec = AlgorithmSpec{adaptFromTask>()}; + algoSpec = AlgorithmSpec{adaptFromTask>(payloadLim)}; } else { - algoSpec = AlgorithmSpec{adaptFromTask>()}; + algoSpec = AlgorithmSpec{adaptFromTask>(payloadLim)}; } } if (!verbose && paranoid) { if (old) { - algoSpec = AlgorithmSpec{adaptFromTask>()}; + algoSpec = AlgorithmSpec{adaptFromTask>(payloadLim)}; } else { - algoSpec = AlgorithmSpec{adaptFromTask>()}; + algoSpec = AlgorithmSpec{adaptFromTask>(payloadLim)}; } } if (verbose && !paranoid) { if (old) { - algoSpec = AlgorithmSpec{adaptFromTask>()}; + algoSpec = AlgorithmSpec{adaptFromTask>(payloadLim)}; } else { - algoSpec = AlgorithmSpec{adaptFromTask>()}; + algoSpec = AlgorithmSpec{adaptFromTask>(payloadLim)}; } } if (verbose && paranoid) { if (old) { - algoSpec = AlgorithmSpec{adaptFromTask>()}; + algoSpec = AlgorithmSpec{adaptFromTask>(payloadLim)}; } else { - algoSpec = AlgorithmSpec{adaptFromTask>()}; + algoSpec = AlgorithmSpec{adaptFromTask>(payloadLim)}; } } } From 6cb31bd7de1ba16866fe7595e117517707f6095a Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Fri, 6 Oct 2023 14:06:29 +0200 Subject: [PATCH 239/324] TRD raw reader update --- .../include/DataFormatsTRD/HelperMethods.h | 13 +++++-- .../include/TRDReconstruction/CruRawReader.h | 6 ++-- .../TRD/reconstruction/src/CruRawReader.cxx | 34 +++++++++++++------ 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/HelperMethods.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/HelperMethods.h index 4468528865d3b..ecab7f49b92a2 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/HelperMethods.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/HelperMethods.h @@ -14,6 +14,8 @@ #include "DataFormatsTRD/Constants.h" #include +#include +#include namespace o2 { @@ -54,12 +56,17 @@ struct HelperMethods { printf("%02i_%i_%i\n", det / constants::NCHAMBERPERSEC, (det % constants::NCHAMBERPERSEC) / constants::NLAYER, det % constants::NLAYER); } - static void printSectorStackLayerSide(int hcid) + static std::string getSectorStackLayerSide(int hcid) { - // for a given half-chamber number prints SECTOR_STACK_LAYER_side int det = hcid / 2; std::string side = (hcid % 2 == 0) ? "A" : "B"; - printf("%02i_%i_%i%s\n", det / constants::NCHAMBERPERSEC, (det % constants::NCHAMBERPERSEC) / constants::NLAYER, det % constants::NLAYER, side.c_str()); + return fmt::format("{}_{}_{}{}", getSector(det), getStack(det), getLayer(det), side); + } + + static void printSectorStackLayerSide(int hcid) + { + // for a given half-chamber number prints SECTOR_STACK_LAYER_side + printf("%s\n", getSectorStackLayerSide(hcid).c_str()); } static int getPadColFromADC(int irob, int imcm, int iadc) diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/CruRawReader.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/CruRawReader.h index 871160f3dfd7e..14a4af07f66f3 100644 --- a/Detectors/TRD/reconstruction/include/TRDReconstruction/CruRawReader.h +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/CruRawReader.h @@ -119,8 +119,10 @@ class CruRawReader // given the total link size and the hcid from the RDH // parse the tracklet data. Overwrite hcid from TrackletHCHeader if mismatch is detected // trackletWordsRejected: count the number of words which were skipped (subset of words read) - // returns total number of words read (no matter if parsed successfully or not) - int parseTrackletLinkData(int linkSize32, int& hcid, int& trackletWordsRejected); + // trackletWordsReadOK: count the number of words which could be read consecutively w/o errors + // numberOfTrackletsFound: count the number of tracklets found + // returns total number of words read (no matter if parsed successfully or not) or -1 in case of failure + int parseTrackletLinkData(int linkSize32, int& hcid, int& trackletWordsRejected, int& trackletWordsReadOK, int& numberOfTrackletsFound); // the parsing begins after the DigitHCHeaders have been parsed already // maxWords32 is the remaining number of words for the given link diff --git a/Detectors/TRD/reconstruction/src/CruRawReader.cxx b/Detectors/TRD/reconstruction/src/CruRawReader.cxx index eff2597b481a8..b2370dfc46b1b 100644 --- a/Detectors/TRD/reconstruction/src/CruRawReader.cxx +++ b/Detectors/TRD/reconstruction/src/CruRawReader.cxx @@ -500,7 +500,9 @@ bool CruRawReader::processHalfCRU(int iteration) mEventRecords.incLinkWords(halfChamberId, mCurrentHalfCRULinkLengths[currentlinkindex]); uint32_t currentlinksize32 = mCurrentHalfCRULinkLengths[currentlinkindex] * 8; // x8 to go from 256 bits to 32 bit; uint32_t endOfCurrentLink = mHBFoffset32 + currentlinksize32; - + if (mOptions[TRDVerboseBit] && currentlinksize32 > 0) { + LOGP(info, "Reading {} (link ID {}, HCID {}) with {} 32-bit words", HelperMethods::getSectorStackLayerSide(halfChamberId), linkIdxGlobal, halfChamberId, currentlinksize32); + } linksizeAccum32 += currentlinksize32; if (currentlinksize32 == 0) { mEventRecords.incLinkNoData(halfChamberId); @@ -521,8 +523,13 @@ bool CruRawReader::processHalfCRU(int iteration) LOGF(info, "Tracklet parser starting at offset %u and processing up to %u words", mHBFoffset32, currentlinksize32); } int trackletWordsRejected = 0; - int trackletWordsRead = parseTrackletLinkData(currentlinksize32, halfChamberId, trackletWordsRejected); + int trackletWordsReadOK = 0; + int numberOfTrackletsFound = 0; // count the number of found tracklets for this link + int trackletWordsRead = parseTrackletLinkData(currentlinksize32, halfChamberId, trackletWordsRejected, trackletWordsReadOK, numberOfTrackletsFound); std::chrono::duration trackletparsingtime = std::chrono::high_resolution_clock::now() - trackletparsingstart; + if (mOptions[TRDVerboseBit]) { + LOGP(info, "Could read {} 32-bit words w/o errors, found {} tracklets, rejected {} 32-bit words for {}. Parsing OK? {}", trackletWordsReadOK, numberOfTrackletsFound, trackletWordsRejected, HelperMethods::getSectorStackLayerSide(halfChamberId), (trackletWordsRead != -1 && trackletWordsRejected == 0)); + } if (trackletWordsRead == -1) { // something went wrong bailout of here. mHBFoffset32 = hbfOffsetTmp + linksizeAccum32; @@ -544,7 +551,7 @@ bool CruRawReader::processHalfCRU(int iteration) } mEventRecords.getCurrentEventRecord().incTrackletTime(trackletparsingtime.count()); if (mOptions[TRDVerboseBit]) { - LOGF(info, "Read %i tracklet words and rejected %i words", trackletWordsRead, trackletWordsRejected); + LOGF(debug, "Read %i tracklet words and rejected %i words", trackletWordsRead, trackletWordsRejected); } mTrackletWordsRejected += trackletWordsRejected; mTrackletWordsRead += trackletWordsRead; @@ -836,10 +843,9 @@ int CruRawReader::parseDigitLinkData(int maxWords32, int hcid, int& wordsRejecte } // Returns number of words read (>=0) or error state (<0) -int CruRawReader::parseTrackletLinkData(int linkSize32, int& hcid, int& wordsRejected) +int CruRawReader::parseTrackletLinkData(int linkSize32, int& hcid, int& wordsRejected, int& wordsReadOK, int& trackletsFound) { int wordsRead = 0; // count the number of words which were parsed (both successful and not successful) - int numberOfTrackletsFound = 0; // count the number of found tracklets for this link int state = StateTrackletHCHeader; // we expect to always see a TrackletHCHeader at the beginning of the link // tracklet data for one link is expected to arrive ordered // first MCM in row=0, column=0, then row=0, column=1, ... row=1, column=0, ... @@ -865,6 +871,7 @@ int CruRawReader::parseTrackletLinkData(int linkSize32, int& hcid, int& wordsRej // either the TrackletHCHeader is corrupt or we have only digits on this link return 0; } + ++wordsReadOK; state = StateTrackletMCMHeader; // we do expect tracklets following } else { // we always expect a TrackletHCHeader as first word for a link (default) @@ -876,12 +883,14 @@ int CruRawReader::parseTrackletLinkData(int linkSize32, int& hcid, int& wordsRej ++wordsRejected; continue; } + ++wordsReadOK; state = StateTrackletMCMHeader; // we might have tracklets following or tracklet end markers } } // StateTrackletHCHeader else if (state == StateTrackletMCMHeader) { if (currWord == TRACKLETENDMARKER) { + ++wordsReadOK; state = StateSecondEndmarker; // we expect a second tracklet end marker to follow } else { mcmHeader.word = currWord; @@ -912,6 +921,7 @@ int CruRawReader::parseTrackletLinkData(int linkSize32, int& hcid, int& wordsRej previousColumn = mcmHeader.col; previousRow = mcmHeader.padrow; } + ++wordsReadOK; state = StateTrackletMCMData; // tracklet words must be following, unless the HC header format indicates sending of empty MCM headers } ++wordsRead; @@ -935,20 +945,23 @@ int CruRawReader::parseTrackletLinkData(int linkSize32, int& hcid, int& wordsRej break; } if ((currWord & 0x1) == 0x1) { - // the reserved bit of the trackler MCM data is set + // the reserved bit of the tracklet MCM data is set, we don't create a tracklet from this word incrementErrors(TrackletMCMDataFailure, hcid, fmt::format("Invalid word {:#010x} for the expected TrackletMCMData", currWord)); ++wordsRejected; + ++wordsRead; + continue; } TrackletMCMData mcmData; mcmData.word = currWord; mEventRecords.getCurrentEventRecord().addTracklet(assembleTracklet64(hcHeader.format, mcmHeader, mcmData, iCpu, hcid)); - ++numberOfTrackletsFound; + ++trackletsFound; ++mTrackletsFound; addedTracklet = true; ++wordsRead; + ++wordsReadOK; if (wordsRead == linkSize32) { incrementErrors(TrackletNoTrackletEndMarker, hcid, fmt::format("After reading the word {:#010x} we are at the end of the link data", currWord)); - return wordsRead; + return -1; } currWord = mHBFPayload[mHBFoffset32 + wordsRead]; } @@ -978,9 +991,10 @@ int CruRawReader::parseTrackletLinkData(int linkSize32, int& hcid, int& wordsRej else if (state == StateSecondEndmarker) { ++wordsRead; if (currWord != TRACKLETENDMARKER) { - incrementErrors(TrackletNoSecondEndMarker, hcid, fmt::format("Expected second tracklet end marker, but found {:#010x} instead", currWord)); + incrementErrors(TrackletNoSecondEndMarker, hcid, fmt::format("Invalid word {:#010x} for the expected second end marker", currWord)); return -1; } + ++wordsReadOK; state = StateFinished; } // StateSecondEndmarker @@ -1001,7 +1015,7 @@ int CruRawReader::parseTrackletLinkData(int linkSize32, int& hcid, int& wordsRej } // end of state machine - if (mTrackletHCHeaderState == 1 && numberOfTrackletsFound == 0) { + if (mTrackletHCHeaderState == 1 && trackletsFound == 0) { if (mMaxErrsPrinted > 0) { LOG(error) << "We found a TrackletHCHeader in mode 1, but did not add any tracklets"; checkNoErr(); From 90a155892e3a4a59ff502a1404978828d978e048 Mon Sep 17 00:00:00 2001 From: Chiara Zampolli Date: Sat, 7 Oct 2023 21:57:40 +0200 Subject: [PATCH 240/324] Fix condition to trigger FATAL in ITSTPC matching QC --- Detectors/GlobalTracking/src/MatchITSTPCQC.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx b/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx index ff0cfae2df5e8..ffabdfb906690 100644 --- a/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx +++ b/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx @@ -423,9 +423,6 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) if (trk.getRefTPC().getIndex() >= mTPCTracks.size()) { LOG(fatal) << "******************** ATTENTION! for TPC track associated to matched track: idx = " << trk.getRefTPC().getIndex() << ", size of container = " << mTPCTracks.size() << " in TF " << evCount; } - if (trk.getRefITS().getIndex() >= mITSTracks.size()) { - LOG(fatal) << "******************** ATTENTION! for ITS track associated to matched track: idx = " << trk.getRefITS().getIndex() << ", size of container = " << mITSTracks.size() << " in TF " << evCount; - } std::array title{"TPC", "ITS"}; for (int i = 0; i < matchType::SIZE; ++i) { o2::track::TrackParCov trkRef; @@ -440,14 +437,17 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) ++mNITSTPCSelectedTracks[i]; } } else { - trkRef = mITSTracks[trk.getRefITS()]; idxTrkRef = trk.getRefITS().getIndex(); - LOG(debug) << "Checking track (ITS) with id " << idxTrkRef << " for ITSTPC track " << iITSTPC << " and pt = " << trkRef.getPt(); if (trk.getRefITS().getSource() == GID::ITSAB) { // do not use afterburner tracks LOG(debug) << "Track (ITS) with id " << idxTrkRef << " for ITSTPC track " << iITSTPC << " is from afterburner"; continue; } + if (idxTrkRef >= mITSTracks.size()) { + LOG(fatal) << "******************** ATTENTION! for ITS track associated to matched track (NOT from AB): idx = " << trk.getRefITS().getIndex() << ", size of container = " << mITSTracks.size() << " in TF " << evCount; + } + trkRef = mITSTracks[trk.getRefITS()]; + LOG(debug) << "Checking track (ITS) with id " << idxTrkRef << " for ITSTPC track " << iITSTPC << " and pt = " << trkRef.getPt(); if (isITSTrackSelectedEntry[idxTrkRef] == true) { LOG(debug) << "Track was selected (ITS), with id " << idxTrkRef << " for ITSTPC track " << iITSTPC << " , we keep it in the numerator, pt = " << trkRef.getPt(); fillHisto = true; From f832a9c9be7543bf1547882d3e90ea31e18ef92c Mon Sep 17 00:00:00 2001 From: shahoian Date: Sun, 8 Oct 2023 18:29:15 +0200 Subject: [PATCH 241/324] Make sure the ROF IR is decoded, otherwise abort link data --- .../include/ITSMFTReconstruction/GBTLink.h | 9 ++++++++- .../common/reconstruction/src/GBTLink.cxx | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.h index 93205b90506d0..32c5a9b28a70c 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.h @@ -39,7 +39,7 @@ } \ if ((errRes)&uint8_t(Abort)) { \ discardData(); \ - return AbortedOnError; \ + return (status = AbortedOnError); \ } namespace o2 @@ -187,6 +187,8 @@ struct GBTLink { uint8_t checkErrorsDiagnosticWord(const GBTDiagnostic* gbtD) const { return NoError; } uint8_t checkErrorsCalibrationWord(const GBTCalibration* gbtCal) const { return NoError; } uint8_t checkErrorsCableID(const GBTData* gbtD, uint8_t cableSW) const { return NoError; } + uint8_t checkErrorsIRNotExtracted() const { return NoError; } + #else uint8_t checkErrorsAlignmentPadding(); uint8_t checkErrorsRDH(const RDH& rdh); @@ -203,6 +205,8 @@ struct GBTLink { uint8_t checkErrorsDiagnosticWord(const GBTDiagnostic* gbtD); uint8_t checkErrorsCalibrationWord(const GBTCalibration* gbtCal); uint8_t checkErrorsCableID(const GBTData* gbtD, uint8_t cableSW); + uint8_t checkErrorsIRNotExtracted(); + #endif uint8_t checkErrorsGBTDataID(const GBTData* dbtD); @@ -339,7 +343,10 @@ GBTLink::CollectedDataStatus GBTLink::collectROFCableData(const Mapping& chmap) } continue; } + // trigger is supposed to be seen + GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsIRNotExtracted()); } + auto gbtD = reinterpret_cast(&currRawPiece->data[dataOffset]); expectPacketDone = true; diff --git a/Detectors/ITSMFT/common/reconstruction/src/GBTLink.cxx b/Detectors/ITSMFT/common/reconstruction/src/GBTLink.cxx index d47d951edb526..af4c8de5caf39 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/GBTLink.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/GBTLink.cxx @@ -510,6 +510,23 @@ uint8_t GBTLink::checkErrorsCableID(const GBTData* gbtD, uint8_t cableSW) return err; } +///_________________________________________________________________ +/// Check that the IR was extracted from the trigger +uint8_t GBTLink::checkErrorsIRNotExtracted() +{ + uint8_t err = uint8_t(NoError); + if (ir.isDummy()) { + statistics.errorCounts[GBTLinkDecodingStat::ErrMissingGBTTrigger]++; + gbtErrStatUpadated = true; + if (needToPrintError(statistics.errorCounts[GBTLinkDecodingStat::ErrMissingGBTTrigger])) { + LOG(info) << describe() << " IR_RDH " << irHBF << " IR_ROF " << ir << ". " << statistics.ErrNames[GBTLinkDecodingStat::ErrMissingGBTTrigger]; + } + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrMissingGBTTrigger); + err |= uint8_t(Abort); + } + return err; +} + ///_________________________________________________________________ /// Account link recovery RDH flag void GBTLink::accountLinkRecovery(o2::InteractionRecord ir) From 453604e6a89a932ddbcbd325ebe2c3aa3673948c Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Sun, 1 Oct 2023 17:16:49 +0200 Subject: [PATCH 242/324] TPC: adding material type for dedx calibration as parameter --- .../TPC/calibration/include/TPCCalibration/CalibdEdx.h | 8 +++++++- .../calibration/include/TPCCalibration/CalibratordEdx.h | 5 ++++- Detectors/TPC/calibration/src/CalibdEdx.cxx | 3 +-- Detectors/TPC/calibration/src/CalibratordEdx.cxx | 1 + Detectors/TPC/workflow/src/CalibdEdxSpec.cxx | 7 +++++-- Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx | 8 ++++++-- 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h index d8b0634736240..54b9d6f98ee35 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h @@ -26,6 +26,7 @@ #include "DataFormatsTPC/TrackCuts.h" #include "DataFormatsTPC/Defs.h" #include "DataFormatsTPC/CalibdEdxCorrection.h" +#include "DetectorsBase/Propagator.h" // boost includes #include @@ -97,6 +98,9 @@ class CalibdEdx mFitLowCutFactor = lowCutFactor; } + /// setting the material type for track propagation + void setMaterialType(o2::base::Propagator::MatCorrType materialType) { mMatType = materialType; } + /// Fill histograms using tracks data. void fill(const TrackTPC& tracks); void fill(const gsl::span); @@ -152,7 +156,9 @@ class CalibdEdx Hist mHist; ///< dEdx multidimensional histogram CalibdEdxCorrection mCalib{}; ///< Calibration output - ClassDefNV(CalibdEdx, 2); + o2::base::Propagator::MatCorrType mMatType{}; ///< material type for track propagation + + ClassDefNV(CalibdEdx, 3); }; } // namespace o2::tpc diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibratordEdx.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibratordEdx.h index 3119d575b1723..1b90e525cf6dc 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibratordEdx.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibratordEdx.h @@ -29,6 +29,7 @@ #include "DetectorsCalibration/TimeSlot.h" #include "TPCCalibration/CalibdEdx.h" #include "CommonUtils/TreeStreamRedirector.h" +#include "DetectorsBase/Propagator.h" namespace o2::tpc { @@ -58,6 +59,7 @@ class CalibratordEdx final : public o2::calibration::TimeSlotCalibration values) { mElectronCut = values; } + void setMaterialType(o2::base::Propagator::MatCorrType materialType) { mMatType = materialType; } /// \brief Check if there are enough data to compute the calibration. /// \return false if any of the histograms has less entries than mMinEntries @@ -104,6 +106,7 @@ class CalibratordEdx final : public o2::calibration::TimeSlotCalibration mElectronCut{}; ///< Values passed to CalibdEdx::setElectronCut TrackCuts mCuts; ///< Cut object + o2::base::Propagator::MatCorrType mMatType{}; ///< material type for track propagation TFinterval mTFIntervals; ///< start and end time frame IDs of each calibration time slots TimeInterval mTimeIntervals; ///< start and end times of each calibration time slots @@ -111,7 +114,7 @@ class CalibratordEdx final : public o2::calibration::TimeSlotCalibration mDebugOutputStreamer; ///< Debug output streamer - ClassDefOverride(CalibratordEdx, 1); + ClassDefOverride(CalibratordEdx, 2); }; } // namespace o2::tpc diff --git a/Detectors/TPC/calibration/src/CalibdEdx.cxx b/Detectors/TPC/calibration/src/CalibdEdx.cxx index f8e138d166ae7..c012a4a2b3ec9 100644 --- a/Detectors/TPC/calibration/src/CalibdEdx.cxx +++ b/Detectors/TPC/calibration/src/CalibdEdx.cxx @@ -29,7 +29,6 @@ #include "DataFormatsTPC/TrackCuts.h" #include "Framework/Logger.h" #include "TPCBase/ParameterGas.h" -#include "DetectorsBase/Propagator.h" // root includes #include "TFile.h" @@ -82,7 +81,7 @@ void CalibdEdx::fill(const TrackTPC& track) constexpr std::array xks{108.475f, 151.7f, 188.8f, 227.65f}; // propagate track - const bool okProp = o2::base::Propagator::Instance()->PropagateToXBxByBz(cpTrack, xks[roc], 0.9f, 2., o2::base::Propagator::MatCorrType::USEMatCorrNONE); + const bool okProp = o2::base::Propagator::Instance()->PropagateToXBxByBz(cpTrack, xks[roc], 0.9f, 2., mMatType); if (!okProp) { continue; } diff --git a/Detectors/TPC/calibration/src/CalibratordEdx.cxx b/Detectors/TPC/calibration/src/CalibratordEdx.cxx index 32d138e28b153..f16fb6f19ebdf 100644 --- a/Detectors/TPC/calibration/src/CalibratordEdx.cxx +++ b/Detectors/TPC/calibration/src/CalibratordEdx.cxx @@ -76,6 +76,7 @@ CalibratordEdx::Slot& CalibratordEdx::emplaceNewSlot(bool front, TFType tstart, container->set2DFitThreshold(mFitThreshold[2]); const auto [cut, iterations, cutLowFactor] = mElectronCut; container->setElectronCut(cut, iterations, cutLowFactor); + container->setMaterialType(mMatType); slot.setContainer(std::move(container)); return slot; diff --git a/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx b/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx index 6fa676f7a34a4..bd02f620de7ea 100644 --- a/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx +++ b/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx @@ -55,6 +55,7 @@ class CalibdEdxDevice : public Task const auto maxdEdx = ic.options().get("max-dedx"); const auto angularBins = ic.options().get("angularbins"); const auto fitSnp = ic.options().get("fit-snp"); + auto materialType = static_cast(ic.options().get("material-type")); mDumpToFile = ic.options().get("file-dump"); @@ -64,6 +65,7 @@ class CalibdEdxDevice : public Task mCalib->set1DFitThreshold(minEntries1D); mCalib->set2DFitThreshold(minEntries2D); mCalib->setElectronCut(fitThreshold, fitPasses, fitThresholdLowFactor); + mCalib->setMaterialType(materialType); } void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final @@ -131,7 +133,7 @@ DataProcessorSpec getCalibdEdxSpec() false, // GRPECS=true false, // GRPLHCIF true, // GRPMagField - false, // askMatLUT + true, // askMatLUT o2::base::GRPGeomRequest::None, // geometry inputs, true, @@ -156,7 +158,8 @@ DataProcessorSpec getCalibdEdxSpec() {"angularbins", VariantType::Int, 36, {"number of angular bins: Tgl and Snp"}}, {"fit-snp", VariantType::Bool, false, {"enable Snp correction"}}, - {"file-dump", VariantType::Int, 0, {"directly dump calibration to file"}}}}; + {"file-dump", VariantType::Int, 0, {"directly dump calibration to file"}}, + {"material-type", VariantType::Int, 2, {"Type for the material buget during track propagation: 0=None, 1=Geo, 2=LUT"}}}}; } } // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx b/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx index e3aba703e945f..b4f10d0317824 100644 --- a/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx +++ b/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx @@ -32,6 +32,7 @@ #include "TPCWorkflow/ProcessingHelpers.h" #include "DetectorsBase/GRPGeomHelper.h" #include "TPCBase/CDBInterface.h" +#include "DetectorsBase/Propagator.h" using namespace o2::framework; @@ -63,6 +64,7 @@ class CalibratordEdxDevice : public Task const auto fitSnp = ic.options().get("fit-snp"); const auto dumpData = ic.options().get("file-dump"); + auto materialType = static_cast(ic.options().get("material-type")); mCalibrator = std::make_unique(); mCalibrator->setHistParams(dEdxBins, mindEdx, maxdEdx, angularBins, fitSnp); @@ -72,6 +74,7 @@ class CalibratordEdxDevice : public Task mCalibrator->setSlotLength(slotLength); mCalibrator->setMaxSlotsDelay(maxDelay); mCalibrator->setElectronCut({fitThreshold, fitPasses, fitThresholdLowFactor}); + mCalibrator->setMaterialType(materialType); if (dumpData) { mCalibrator->enableDebugOutput("calibratordEdx.root"); @@ -141,7 +144,7 @@ DataProcessorSpec getCalibratordEdxSpec() true, // GRPECS=true false, // GRPLHCIF true, // GRPMagField - false, // askMatLUT + true, // askMatLUT o2::base::GRPGeomRequest::None, // geometry inputs, true, @@ -169,7 +172,8 @@ DataProcessorSpec getCalibratordEdxSpec() {"angularbins", VariantType::Int, 36, {"number of angular bins: Tgl and Snp"}}, {"fit-snp", VariantType::Bool, false, {"enable Snp correction"}}, - {"file-dump", VariantType::Bool, false, {"directly dump calibration to file"}}}}; + {"file-dump", VariantType::Bool, false, {"directly dump calibration to file"}}, + {"material-type", VariantType::Int, 2, {"Type for the material buget during track propagation: 0=None, 1=Geo, 2=LUT"}}}}; } } // namespace o2::tpc From eb498a54c1500ec24dd5fe75956dec80d64bdbdb Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Wed, 4 Oct 2023 11:55:37 +0200 Subject: [PATCH 243/324] Enable fetching matLUT only if needed --- .../include/TPCWorkflow/CalibdEdxSpec.h | 3 ++- .../include/TPCWorkflow/CalibratordEdxSpec.h | 3 ++- Detectors/TPC/workflow/src/CalibdEdxSpec.cxx | 16 ++++++++-------- .../TPC/workflow/src/CalibratordEdxSpec.cxx | 17 ++++++++--------- Detectors/TPC/workflow/src/tpc-calib-dEdx.cxx | 4 +++- .../TPC/workflow/src/tpc-calibrator-dEdx.cxx | 4 +++- 6 files changed, 26 insertions(+), 21 deletions(-) diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CalibdEdxSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/CalibdEdxSpec.h index 290bfbc558f8f..bafad0ef5a20c 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/CalibdEdxSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CalibdEdxSpec.h @@ -17,6 +17,7 @@ #define O2_TPC_TPCCALIBDEDXSPEC_H_ #include "Framework/DataProcessorSpec.h" +#include "DetectorsBase/Propagator.h" using namespace o2::framework; @@ -24,7 +25,7 @@ namespace o2::tpc { /// create a processor spec -o2::framework::DataProcessorSpec getCalibdEdxSpec(); +o2::framework::DataProcessorSpec getCalibdEdxSpec(const o2::base::Propagator::MatCorrType matType); } // namespace o2::tpc diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CalibratordEdxSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/CalibratordEdxSpec.h index dd8ebd7d3e62d..b34c877879269 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/CalibratordEdxSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CalibratordEdxSpec.h @@ -17,6 +17,7 @@ #define O2_TPC_TPCCALIBRATORDEDXSPEC_H_ #include "Framework/DataProcessorSpec.h" +#include "DetectorsBase/Propagator.h" using namespace o2::framework; @@ -24,7 +25,7 @@ namespace o2::tpc { /// create a processor spec -o2::framework::DataProcessorSpec getCalibratordEdxSpec(); +o2::framework::DataProcessorSpec getCalibratordEdxSpec(const o2::base::Propagator::MatCorrType matType); } // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx b/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx index bd02f620de7ea..8491fe6c772b6 100644 --- a/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx +++ b/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx @@ -38,7 +38,7 @@ namespace o2::tpc class CalibdEdxDevice : public Task { public: - CalibdEdxDevice(std::shared_ptr req) : mCCDBRequest(req) {} + CalibdEdxDevice(std::shared_ptr req, const o2::base::Propagator::MatCorrType matType) : mCCDBRequest(req), mMatType(matType) {} void init(framework::InitContext& ic) final { @@ -55,7 +55,6 @@ class CalibdEdxDevice : public Task const auto maxdEdx = ic.options().get("max-dedx"); const auto angularBins = ic.options().get("angularbins"); const auto fitSnp = ic.options().get("fit-snp"); - auto materialType = static_cast(ic.options().get("material-type")); mDumpToFile = ic.options().get("file-dump"); @@ -65,7 +64,7 @@ class CalibdEdxDevice : public Task mCalib->set1DFitThreshold(minEntries1D); mCalib->set2DFitThreshold(minEntries2D); mCalib->setElectronCut(fitThreshold, fitPasses, fitThresholdLowFactor); - mCalib->setMaterialType(materialType); + mCalib->setMaterialType(mMatType); } void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final @@ -117,14 +116,16 @@ class CalibdEdxDevice : public Task } std::shared_ptr mCCDBRequest; + const o2::base::Propagator::MatCorrType mMatType{}; int mDumpToFile{}; uint64_t mRunNumber{0}; ///< processed run number uint64_t mTimeStampStart{0}; ///< time stamp for first TF for CCDB output std::unique_ptr mCalib; }; -DataProcessorSpec getCalibdEdxSpec() +DataProcessorSpec getCalibdEdxSpec(const o2::base::Propagator::MatCorrType matType) { + const bool enableAskMatLUT = matType == o2::base::Propagator::MatCorrType::USEMatCorrLUT; std::vector outputs; outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TPC_CalibdEdx"}, Lifetime::Sporadic); outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TPC_CalibdEdx"}, Lifetime::Sporadic); @@ -133,7 +134,7 @@ DataProcessorSpec getCalibdEdxSpec() false, // GRPECS=true false, // GRPLHCIF true, // GRPMagField - true, // askMatLUT + enableAskMatLUT, // askMatLUT o2::base::GRPGeomRequest::None, // geometry inputs, true, @@ -143,7 +144,7 @@ DataProcessorSpec getCalibdEdxSpec() "tpc-calib-dEdx", inputs, outputs, - adaptFromTask(ccdbRequest), + adaptFromTask(ccdbRequest, matType), Options{ {"min-entries-sector", VariantType::Int, 1000, {"min entries per GEM stack to enable sector by sector correction. Below this value we only perform one fit per ROC type (IROC, OROC1, ...; no side nor sector information)."}}, {"min-entries-1d", VariantType::Int, 10000, {"minimum entries per stack to fit 1D correction"}}, @@ -158,8 +159,7 @@ DataProcessorSpec getCalibdEdxSpec() {"angularbins", VariantType::Int, 36, {"number of angular bins: Tgl and Snp"}}, {"fit-snp", VariantType::Bool, false, {"enable Snp correction"}}, - {"file-dump", VariantType::Int, 0, {"directly dump calibration to file"}}, - {"material-type", VariantType::Int, 2, {"Type for the material buget during track propagation: 0=None, 1=Geo, 2=LUT"}}}}; + {"file-dump", VariantType::Int, 0, {"directly dump calibration to file"}}}}; } } // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx b/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx index b4f10d0317824..fe931d70742b7 100644 --- a/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx +++ b/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx @@ -32,7 +32,6 @@ #include "TPCWorkflow/ProcessingHelpers.h" #include "DetectorsBase/GRPGeomHelper.h" #include "TPCBase/CDBInterface.h" -#include "DetectorsBase/Propagator.h" using namespace o2::framework; @@ -42,7 +41,7 @@ namespace o2::tpc class CalibratordEdxDevice : public Task { public: - CalibratordEdxDevice(std::shared_ptr req) : mCCDBRequest(req) {} + CalibratordEdxDevice(std::shared_ptr req, const o2::base::Propagator::MatCorrType matType) : mCCDBRequest(req), mMatType(matType) {} void init(framework::InitContext& ic) final { o2::base::GRPGeomHelper::instance().setRequest(mCCDBRequest); @@ -64,7 +63,6 @@ class CalibratordEdxDevice : public Task const auto fitSnp = ic.options().get("fit-snp"); const auto dumpData = ic.options().get("file-dump"); - auto materialType = static_cast(ic.options().get("material-type")); mCalibrator = std::make_unique(); mCalibrator->setHistParams(dEdxBins, mindEdx, maxdEdx, angularBins, fitSnp); @@ -74,7 +72,7 @@ class CalibratordEdxDevice : public Task mCalibrator->setSlotLength(slotLength); mCalibrator->setMaxSlotsDelay(maxDelay); mCalibrator->setElectronCut({fitThreshold, fitPasses, fitThresholdLowFactor}); - mCalibrator->setMaterialType(materialType); + mCalibrator->setMaterialType(mMatType); if (dumpData) { mCalibrator->enableDebugOutput("calibratordEdx.root"); @@ -130,12 +128,14 @@ class CalibratordEdxDevice : public Task } std::unique_ptr mCalibrator; + const o2::base::Propagator::MatCorrType mMatType{}; std::shared_ptr mCCDBRequest; uint64_t mRunNumber{0}; ///< processed run number }; -DataProcessorSpec getCalibratordEdxSpec() +DataProcessorSpec getCalibratordEdxSpec(const o2::base::Propagator::MatCorrType matType) { + const bool enableAskMatLUT = matType == o2::base::Propagator::MatCorrType::USEMatCorrLUT; std::vector outputs; outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TPC_CalibdEdx"}, Lifetime::Sporadic); outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TPC_CalibdEdx"}, Lifetime::Sporadic); @@ -144,7 +144,7 @@ DataProcessorSpec getCalibratordEdxSpec() true, // GRPECS=true false, // GRPLHCIF true, // GRPMagField - true, // askMatLUT + enableAskMatLUT, // askMatLUT o2::base::GRPGeomRequest::None, // geometry inputs, true, @@ -153,7 +153,7 @@ DataProcessorSpec getCalibratordEdxSpec() "tpc-calibrator-dEdx", inputs, outputs, - adaptFromTask(ccdbRequest), + adaptFromTask(ccdbRequest, matType), Options{ {"tf-per-slot", VariantType::UInt32, 6000u, {"number of TFs per calibration time slot"}}, {"max-delay", VariantType::UInt32, 10u, {"number of slots in past to consider"}}, @@ -172,8 +172,7 @@ DataProcessorSpec getCalibratordEdxSpec() {"angularbins", VariantType::Int, 36, {"number of angular bins: Tgl and Snp"}}, {"fit-snp", VariantType::Bool, false, {"enable Snp correction"}}, - {"file-dump", VariantType::Bool, false, {"directly dump calibration to file"}}, - {"material-type", VariantType::Int, 2, {"Type for the material buget during track propagation: 0=None, 1=Geo, 2=LUT"}}}}; + {"file-dump", VariantType::Bool, false, {"directly dump calibration to file"}}}}; } } // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/tpc-calib-dEdx.cxx b/Detectors/TPC/workflow/src/tpc-calib-dEdx.cxx index 93e790f4cd414..ea25e04e14528 100644 --- a/Detectors/TPC/workflow/src/tpc-calib-dEdx.cxx +++ b/Detectors/TPC/workflow/src/tpc-calib-dEdx.cxx @@ -19,6 +19,7 @@ void customize(std::vector& workflowOptions) std::vector options{ {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCCalibPedestal.FirstTimeBin=10;...')"}}, {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, + {"material-type", VariantType::Int, 2, {"Type for the material budget during track propagation: 0=None, 1=Geo, 2=LUT"}}, }; std::swap(workflowOptions, options); @@ -33,7 +34,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) o2::conf::ConfigurableParam::updateFromFile(config.options().get("configFile")); o2::conf::ConfigurableParam::updateFromString(config.options().get("configKeyValues")); o2::conf::ConfigurableParam::writeINI("o2tpccalibration_configuration.ini"); + auto materialType = static_cast(config.options().get("material-type")); using namespace o2::tpc; - return WorkflowSpec{getCalibdEdxSpec()}; + return WorkflowSpec{getCalibdEdxSpec(materialType)}; } diff --git a/Detectors/TPC/workflow/src/tpc-calibrator-dEdx.cxx b/Detectors/TPC/workflow/src/tpc-calibrator-dEdx.cxx index 5ff36f695bba9..54fcc4621bef3 100644 --- a/Detectors/TPC/workflow/src/tpc-calibrator-dEdx.cxx +++ b/Detectors/TPC/workflow/src/tpc-calibrator-dEdx.cxx @@ -19,6 +19,7 @@ void customize(std::vector& workflowOptions) std::vector options{ {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCCalibPedestal.FirstTimeBin=10;...')"}}, {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, + {"material-type", VariantType::Int, 2, {"Type for the material budget during track propagation: 0=None, 1=Geo, 2=LUT"}}, }; std::swap(workflowOptions, options); @@ -33,7 +34,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) o2::conf::ConfigurableParam::updateFromFile(config.options().get("configFile")); o2::conf::ConfigurableParam::updateFromString(config.options().get("configKeyValues")); o2::conf::ConfigurableParam::writeINI("o2tpccalibration_configuration.ini"); + auto materialType = static_cast(config.options().get("material-type")); using namespace o2::tpc; - return WorkflowSpec{getCalibratordEdxSpec()}; + return WorkflowSpec{getCalibratordEdxSpec(materialType)}; } From 84f1e1dc44fd260fd44856906c79cf66c123dc41 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 9 Oct 2023 21:45:29 +0200 Subject: [PATCH 244/324] FST: should use new CTF coding scheme --- prodtests/full-system-test/start_tmux.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/prodtests/full-system-test/start_tmux.sh b/prodtests/full-system-test/start_tmux.sh index c4564f4863421..f45a8a83841ec 100755 --- a/prodtests/full-system-test/start_tmux.sh +++ b/prodtests/full-system-test/start_tmux.sh @@ -53,6 +53,7 @@ export SYNCMODE=1 export SHMTHROW=0 export IS_SIMULATED_DATA=1 export DATADIST_NEW_DPL_CHAN=1 +export RANS_OPT="--ans-version 1.0 --ctf-dict none" # Use new RANS coding scheme without dictionary [[ -z $GEN_TOPO_MYDIR ]] && GEN_TOPO_MYDIR="$(dirname $(realpath $0))" source $GEN_TOPO_MYDIR/setenv.sh || { echo "setenv.sh failed" 1>&2 && exit 1; } From 6aa56c0568695b1a9562ac23796308e3cd1d8894 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 9 Oct 2023 22:21:10 +0200 Subject: [PATCH 245/324] Rewind input proxy (#12015) * DPL: change ExpirationHandler::Creator to use services This allows us to easily have some state attached to the creation of new timeslices and in particular we can then use the DecongestionService to keep track of the next enumeration to be created. This comes handy when we have dummy iterations which we want to "rewind" to avoid messages about empty timeslices. * DPL: handle empty input proxy iterations --- .../CTP/workflowScalers/src/ctp-proxy.cxx | 3 +- .../CTP/workflowScalers/src/ctp-qc-proxy.cxx | 8 +++-- .../DCS/testWorkflow/src/DCStoDPLconverter.h | 13 ++++---- .../DCS/testWorkflow/src/dcs-config-proxy.cxx | 18 ++++++----- .../Framework/ExternalFairMQDeviceProxy.h | 2 +- .../Core/src/ExternalFairMQDeviceProxy.cxx | 31 +++++++++++++------ .../benchmark_ExternalFairMQDeviceProxies.cxx | 7 +++-- .../test_ExternalFairMQDeviceWorkflow.cxx | 7 +++-- .../src/DataSamplingReadoutAdapter.cxx | 7 +++-- run/o2sim_mctracks_proxy.cxx | 14 +++++---- 10 files changed, 67 insertions(+), 43 deletions(-) diff --git a/Detectors/CTP/workflowScalers/src/ctp-proxy.cxx b/Detectors/CTP/workflowScalers/src/ctp-proxy.cxx index fef2bd9e4deab..449cd0903c882 100644 --- a/Detectors/CTP/workflowScalers/src/ctp-proxy.cxx +++ b/Detectors/CTP/workflowScalers/src/ctp-proxy.cxx @@ -29,6 +29,7 @@ #include "Framework/WorkflowSpec.h" #include "Framework/DataProcessorSpec.h" #include "Framework/DataSpecUtils.h" +#include "Framework/RawDeviceService.h" #include "Framework/ControlService.h" #include "Framework/Logger.h" #include "Framework/Lifetime.h" @@ -51,7 +52,7 @@ InjectorFunction dcs2dpl(std::string& ccdbhost) auto runMgr = std::make_shared(); runMgr->setCCDBHost(ccdbhost); runMgr->init(); - return [runMgr](TimingInfo&, fair::mq::Device& device, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { + return [runMgr](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { // FIXME: Why isn't this function using the timeslice index? // make sure just 2 messages received // if (parts.Size() != 2) { diff --git a/Detectors/CTP/workflowScalers/src/ctp-qc-proxy.cxx b/Detectors/CTP/workflowScalers/src/ctp-qc-proxy.cxx index 28f5a416ef8ad..0502bbae86493 100644 --- a/Detectors/CTP/workflowScalers/src/ctp-qc-proxy.cxx +++ b/Detectors/CTP/workflowScalers/src/ctp-qc-proxy.cxx @@ -28,6 +28,7 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/DataSpecUtils.h" #include "Framework/ControlService.h" +#include "Framework/RawDeviceService.h" #include "Framework/Logger.h" #include "Framework/Lifetime.h" #include "Framework/ConfigParamSpec.h" @@ -45,7 +46,8 @@ using DetID = o2::detectors::DetID; InjectorFunction dcs2dpl() // InjectorFunction dcs2dpl() { - return [](TimingInfo&, fair::mq::Device& device, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + return [](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + auto *device = services.get().device(); std::string messageHeader{static_cast(parts.At(0)->GetData()), parts.At(0)->GetSize()}; size_t dataSize = parts.At(1)->GetSize(); std::string messageData{static_cast(parts.At(1)->GetData()), parts.At(1)->GetSize()}; @@ -64,7 +66,7 @@ InjectorFunction dcs2dpl() hdrF.payloadSize = parts.At(0)->GetSize() + parts.At(1)->GetSize() + 1; hdrF.firstTForbit = 0; // this should be irrelevant for Counters ? Orbit is in payload - auto fmqFactory = device.GetChannel(channel).Transport(); + auto fmqFactory = device->GetChannel(channel).Transport(); o2::header::Stack headerStackF{hdrF, DataProcessingHeader{newTimesliceId, 1}}; auto hdMessageF = fmqFactory->CreateMessage(headerStackF.size(), fair::mq::Alignment{64}); @@ -87,7 +89,7 @@ InjectorFunction dcs2dpl() fair::mq::Parts outParts; outParts.AddPart(std::move(hdMessageF)); outParts.AddPart(std::move(plMessageF)); - sendOnChannel(device, outParts, channel, newTimesliceId); + sendOnChannel(*device, outParts, channel, newTimesliceId); LOG(info) << "Sent CTP counters DPL message" << std::flush; }; } diff --git a/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h b/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h index 2cf97e55e8c7c..dab2fd730b360 100644 --- a/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h +++ b/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h @@ -14,6 +14,7 @@ #include "Framework/DataSpecUtils.h" #include "Framework/ExternalFairMQDeviceProxy.h" +#include "Framework/RawDeviceService.h" #include #include #include "DetectorsDCS/DataPointIdentifier.h" @@ -40,9 +41,7 @@ struct hash { }; } // namespace std -namespace o2 -{ -namespace dcs +namespace o2::dcs { using DPID = o2::dcs::DataPointIdentifier; using DPVAL = o2::dcs::DataPointValue; @@ -54,7 +53,8 @@ using DPCOM = o2::dcs::DataPointCompositeObject; o2f::InjectorFunction dcs2dpl(std::unordered_map& dpid2group, bool fbiFirst, bool verbose = false, int FBIPerInterval = 1) { - return [dpid2group, fbiFirst, verbose, FBIPerInterval](o2::framework::TimingInfo& tinfo, fair::mq::Device& device, fair::mq::Parts& parts, o2f::ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { + return [dpid2group, fbiFirst, verbose, FBIPerInterval](o2::framework::TimingInfo& tinfo, framework::ServiceRegistryRef const& services, fair::mq::Parts& parts, o2f::ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { + auto *device = services.get().device(); static std::unordered_map cache; // will keep only the latest measurement in the 1-second wide window for each DPID static std::unordered_map sentToChannel; static auto timer = std::chrono::high_resolution_clock::now(); @@ -158,7 +158,7 @@ o2f::InjectorFunction dcs2dpl(std::unordered_map& dp hdr.payloadSize = it.second.size() * sizeof(DPCOM); hdr.firstTForbit = 0; // this should be irrelevant for DCS o2h::Stack headerStack{hdr, o2::framework::DataProcessingHeader{tinfo.timeslice, 1, creation}}; - auto fmqFactory = device.GetChannel(channel).Transport(); + auto fmqFactory = device->GetChannel(channel).Transport(); auto hdMessage = fmqFactory->CreateMessage(headerStack.size(), fair::mq::Alignment{64}); auto plMessage = fmqFactory->CreateMessage(hdr.payloadSize, fair::mq::Alignment{64}); memcpy(hdMessage->GetData(), headerStack.data(), headerStack.size()); @@ -181,7 +181,7 @@ o2f::InjectorFunction dcs2dpl(std::unordered_map& dp if (verbose) { LOG(info) << "Sending " << msgIt.second->Size() / 2 << " parts to channel " << msgIt.first; } - o2f::sendOnChannel(device, *msgIt.second.get(), msgIt.first, tinfo.timeslice); + o2f::sendOnChannel(*device, *msgIt.second.get(), msgIt.first, tinfo.timeslice); sentToChannel[msgIt.first]++; } timer = timerNow; @@ -203,7 +203,6 @@ o2f::InjectorFunction dcs2dpl(std::unordered_map& dp }; } -} // namespace dcs } // namespace o2 #endif /* O2_DCS_TO_DPL_CONVERTER_H */ diff --git a/Detectors/DCS/testWorkflow/src/dcs-config-proxy.cxx b/Detectors/DCS/testWorkflow/src/dcs-config-proxy.cxx index cd94bb61b87d3..936ceebf1e0f2 100644 --- a/Detectors/DCS/testWorkflow/src/dcs-config-proxy.cxx +++ b/Detectors/DCS/testWorkflow/src/dcs-config-proxy.cxx @@ -17,6 +17,7 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/DataSpecUtils.h" #include "Framework/ControlService.h" +#include "Framework/RawDeviceService.h" #include "Framework/Logger.h" #include "Framework/Lifetime.h" #include "Framework/ConfigParamSpec.h" @@ -66,7 +67,8 @@ auto getDataOriginFromFilename(const std::string& filename) InjectorFunction dcs2dpl(const std::string& acknowledge) { - return [acknowledge](TimingInfo&, fair::mq::Device& device, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + return [acknowledge](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + auto *device = services.get().device(); if (parts.Size() == 0) { // received at ^c, ignore LOG(info) << "ignoring empty message"; return; @@ -74,7 +76,7 @@ InjectorFunction dcs2dpl(const std::string& acknowledge) // make sure just 2 messages received if (parts.Size() != 2) { LOG(error) << "received " << parts.Size() << " instead of 2 expected"; - sendAnswer("error0: wrong number of messages", acknowledge, device); + sendAnswer("error0: wrong number of messages", acknowledge, *device); return; } std::string filename{static_cast(parts.At(0)->GetData()), parts.At(0)->GetSize()}; @@ -83,7 +85,7 @@ InjectorFunction dcs2dpl(const std::string& acknowledge) o2::header::DataOrigin dataOrigin = getDataOriginFromFilename(filename); if (dataOrigin == o2::header::gDataOriginInvalid) { LOG(error) << "unknown detector for " << filename; - sendAnswer(fmt::format("{}:error1: unrecognized filename", filename), acknowledge, device); + sendAnswer(fmt::format("{}:error1: unrecognized filename", filename), acknowledge, *device); return; } @@ -93,7 +95,7 @@ InjectorFunction dcs2dpl(const std::string& acknowledge) auto channel = channelRetriever(outsp, newTimesliceId); if (channel.empty()) { LOG(error) << "No output channel found for OutputSpec " << outsp; - sendAnswer(fmt::format("{}:error2: no channel to send", filename), acknowledge, device); + sendAnswer(fmt::format("{}:error2: no channel to send", filename), acknowledge, *device); return; } @@ -111,7 +113,7 @@ InjectorFunction dcs2dpl(const std::string& acknowledge) hdrN.payloadSize = parts.At(0)->GetSize(); hdrN.firstTForbit = 0; // this should be irrelevant for DCS - auto fmqFactory = device.GetChannel(channel).Transport(); + auto fmqFactory = device->GetChannel(channel).Transport(); std::uint64_t creation = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); o2::header::Stack headerStackF{hdrF, DataProcessingHeader{newTimesliceId, 1, creation}}; @@ -129,14 +131,14 @@ InjectorFunction dcs2dpl(const std::string& acknowledge) fair::mq::Parts outPartsF; outPartsF.AddPart(std::move(hdMessageF)); outPartsF.AddPart(std::move(plMessageF)); - sendOnChannel(device, outPartsF, channel, (size_t)-1); + sendOnChannel(*device, outPartsF, channel, (size_t)-1); fair::mq::Parts outPartsN; outPartsN.AddPart(std::move(hdMessageN)); outPartsN.AddPart(std::move(plMessageN)); - sendOnChannel(device, outPartsN, channel, newTimesliceId); + sendOnChannel(*device, outPartsN, channel, newTimesliceId); - sendAnswer(fmt::format("{}:ok", filename), acknowledge, device); + sendAnswer(fmt::format("{}:ok", filename), acknowledge, *device); LOG(info) << "Sent DPL message and acknowledgment for file " << filename; }; } diff --git a/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h b/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h index b75ef6a9815eb..cfa05cd07d1d2 100644 --- a/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h +++ b/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h @@ -23,7 +23,7 @@ namespace o2::framework /// A callback function to retrieve the fair::mq::Channel name to be used for sending /// messages of the specified OutputSpec using ChannelRetriever = std::function; -using InjectorFunction = std::function; +using InjectorFunction = std::function; using ChannelSelector = std::function>& channels)>; struct InputChannelSpec; diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 5568848405fb1..4a6e73706c1a9 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -31,6 +31,7 @@ #include "Framework/Monitoring.h" #include "Headers/DataHeader.h" #include "Headers/Stack.h" +#include "DecongestionService.h" #include "CommonConstants/LHCConstants.h" #include "./DeviceSpecHelpers.h" @@ -203,13 +204,14 @@ void appendForSending(fair::mq::Device& device, o2::header::Stack&& headerStack, InjectorFunction o2DataModelAdaptor(OutputSpec const& spec, uint64_t startTime, uint64_t /*step*/) { - return [spec](TimingInfo&, fair::mq::Device& device, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { + return [spec](TimingInfo&, ServiceRegistryRef const& ref, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { + auto* device = ref.get().device(); for (int i = 0; i < parts.Size() / 2; ++i) { auto dh = o2::header::get(parts.At(i * 2)->GetData()); DataProcessingHeader dph{newTimesliceId, 0}; o2::header::Stack headerStack{*dh, dph}; - sendOnChannel(device, std::move(headerStack), std::move(parts.At(i * 2 + 1)), spec, channelRetriever); + sendOnChannel(*device, std::move(headerStack), std::move(parts.At(i * 2 + 1)), spec, channelRetriever); } }; } @@ -449,10 +451,11 @@ InjectorFunction dplModelAdaptor(std::vector const& filterSpecs, DPL std::string descriptions; }; - return [filterSpecs = std::move(filterSpecs), throwOnUnmatchedInputs, droppedDataSpecs = std::make_shared()](TimingInfo& timingInfo, fair::mq::Device& device, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { + return [filterSpecs = std::move(filterSpecs), throwOnUnmatchedInputs, droppedDataSpecs = std::make_shared()](TimingInfo& timingInfo, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { // FIXME: this in not thread safe, but better than an alloc of a map per message... std::unordered_map outputs; std::vector unmatchedDescriptions; + auto* device = services.get().device(); static bool override_creation_env = getenv("DPL_RAWPROXY_OVERRIDE_ORBITRESET"); bool override_creation = false; @@ -462,7 +465,7 @@ InjectorFunction dplModelAdaptor(std::vector const& filterSpecs, DPL creationVal = creationValBase; override_creation = true; } else { - auto orbitResetTimeUrl = device.fConfig->GetProperty("orbit-reset-time", "ccdb://CTP/Calib/OrbitResetTime"); + auto orbitResetTimeUrl = device->fConfig->GetProperty("orbit-reset-time", "ccdb://CTP/Calib/OrbitResetTime"); char* err = nullptr; creationVal = std::strtoll(orbitResetTimeUrl.c_str(), &err, 10); if (err && *err == 0 && creationVal) { @@ -550,11 +553,19 @@ InjectorFunction dplModelAdaptor(std::vector const& filterSpecs, DPL } } // end of loop over parts + bool didSendParts = false; for (auto& [channelName, channelParts] : outputs) { if (channelParts.Size() == 0) { continue; } - sendOnChannel(device, channelParts, channelName, newTimesliceId); + didSendParts = true; + sendOnChannel(*device, channelParts, channelName, newTimesliceId); + } + // In case we did not send any part at all, we need to rewind by one + // to avoid creating extra timeslices at the end of the run. + if (didSendParts == false) { + auto& decongestion = services.get(); + decongestion.nextEnumerationTimeslice -= 1; } if (not unmatchedDescriptions.empty()) { if (throwOnUnmatchedInputs) { @@ -585,7 +596,8 @@ InjectorFunction dplModelAdaptor(std::vector const& filterSpecs, DPL InjectorFunction incrementalConverter(OutputSpec const& spec, o2::header::SerializationMethod method, uint64_t startTime, uint64_t step) { auto timesliceId = std::make_shared(startTime); - return [timesliceId, spec, step, method](TimingInfo&, fair::mq::Device& device, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + return [timesliceId, spec, step, method](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + auto* device = services.get().device(); // We iterate on all the parts and we send them two by two, // adding the appropriate O2 header. for (int i = 0; i < parts.Size(); ++i) { @@ -607,7 +619,7 @@ InjectorFunction incrementalConverter(OutputSpec const& spec, o2::header::Serial // we have to move the incoming data o2::header::Stack headerStack{dh, dph}; - sendOnChannel(device, std::move(headerStack), std::move(parts.At(i)), spec, channelRetriever); + sendOnChannel(*device, std::move(headerStack), std::move(parts.At(i)), spec, channelRetriever); } }; } @@ -755,12 +767,13 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, return count; }; - auto dataHandler = [device, converter, doInjectMissingData, doPrintSizes, + auto dataHandler = [ref = ctx.services(), converter, doInjectMissingData, doPrintSizes, outputRoutes = std::move(outputRoutes), control = &ctx.services().get(), deviceState = &ctx.services().get(), timesliceIndex = &ctx.services().get(), outputChannels = std::move(outputChannels)](TimingInfo& timingInfo, fair::mq::Parts& inputs, int, size_t ci, bool newRun) { + auto* device = ref.get().device(); // pass a copy of the outputRoutes auto channelRetriever = [&outputRoutes](OutputSpec const& query, DataProcessingHeader::StartTime timeslice) -> std::string { for (auto& route : outputRoutes) { @@ -788,7 +801,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, if (doInjectMissingData) { injectMissingData(*device, inputs, outputRoutes, doInjectMissingData, doPrintSizes); } - converter(timingInfo, *device, inputs, channelRetriever, timesliceIndex->getOldestPossibleOutput().timeslice.value, shouldstop); + converter(timingInfo, ref, inputs, channelRetriever, timesliceIndex->getOldestPossibleOutput().timeslice.value, shouldstop); // If we have enough EoS messages, we can stop the device // Notice that this has a number of failure modes: diff --git a/Framework/Core/test/benchmark_ExternalFairMQDeviceProxies.cxx b/Framework/Core/test/benchmark_ExternalFairMQDeviceProxies.cxx index 839c19874ea21..55e0b4cec89db 100644 --- a/Framework/Core/test/benchmark_ExternalFairMQDeviceProxies.cxx +++ b/Framework/Core/test/benchmark_ExternalFairMQDeviceProxies.cxx @@ -469,7 +469,8 @@ std::vector defineDataProcessing(ConfigContext const& config) // reads the messages from the output proxy via the out-of-band channel // converter callback for the external FairMQ device proxy ProcessorSpec generator - auto converter = [](TimingInfo&, fair::mq::Device& device, fair::mq::Parts& inputs, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + auto converter = [](TimingInfo&, ServiceRegistryRef const& ref, fair::mq::Parts& inputs, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + auto* device = ref.get().device(); ASSERT_ERROR(inputs.Size() >= 2); if (inputs.Size() < 2) { return; @@ -499,7 +500,7 @@ std::vector defineDataProcessing(ConfigContext const& config) return; } // make a copy of the header message, get the data header and change origin - auto outHeaderMessage = device.NewMessageFor(channelName, 0, inputs.At(msgidx)->GetSize()); + auto outHeaderMessage = device->NewMessageFor(channelName, 0, inputs.At(msgidx)->GetSize()); memcpy(outHeaderMessage->GetData(), inputs.At(msgidx)->GetData(), inputs.At(msgidx)->GetSize()); // this we obviously need to fix in the get API, const'ness of the returned header pointer // should depend on const'ness of the buffer @@ -509,7 +510,7 @@ std::vector defineDataProcessing(ConfigContext const& config) output.AddPart(std::move(outHeaderMessage)); output.AddPart(std::move(inputs.At(msgidx + 1))); LOG(debug) << "sending " << DataSpecUtils::describe(OutputSpec{odh->dataOrigin, odh->dataDescription, odh->subSpecification}); - o2::framework::sendOnChannel(device, output, channelName, (size_t)-1); + o2::framework::sendOnChannel(*device, output, channelName, (size_t)-1); }; // we use the same spec to build the configuration string, ideally we would have some helpers diff --git a/Framework/Core/test/test_ExternalFairMQDeviceWorkflow.cxx b/Framework/Core/test/test_ExternalFairMQDeviceWorkflow.cxx index bc65094ff5696..98f3139fe7b86 100644 --- a/Framework/Core/test/test_ExternalFairMQDeviceWorkflow.cxx +++ b/Framework/Core/test/test_ExternalFairMQDeviceWorkflow.cxx @@ -349,7 +349,8 @@ std::vector defineDataProcessing(ConfigContext const& config) // reads the messages from the output proxy via the out-of-band channel // converter callback for the external FairMQ device proxy ProcessorSpec generator - auto converter = [](TimingInfo&, fair::mq::Device& device, fair::mq::Parts& inputs, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + auto converter = [](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& inputs, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + auto* device = services.get().device(); ASSERT_ERROR(inputs.Size() >= 2); if (inputs.Size() < 2) { return; @@ -389,7 +390,7 @@ std::vector defineDataProcessing(ConfigContext const& config) dh->splitPayloadParts, dh->splitPayloadIndex); // make a copy of the header message, get the data header and change origin - auto outHeaderMessage = device.NewMessageFor(channelName, 0, inputs.At(msgidx)->GetSize()); + auto outHeaderMessage = device->NewMessageFor(channelName, 0, inputs.At(msgidx)->GetSize()); memcpy(outHeaderMessage->GetData(), inputs.At(msgidx)->GetData(), inputs.At(msgidx)->GetSize()); // this we obviously need to fix in the get API, const'ness of the returned header pointer // should depend on const'ness of the buffer @@ -400,7 +401,7 @@ std::vector defineDataProcessing(ConfigContext const& config) output.AddPart(std::move(inputs.At(msgidx))); } } - o2::framework::sendOnChannel(device, output, channelName, (size_t)-1); + o2::framework::sendOnChannel(*device, output, channelName, (size_t)-1); return; }; diff --git a/Utilities/DataSampling/src/DataSamplingReadoutAdapter.cxx b/Utilities/DataSampling/src/DataSamplingReadoutAdapter.cxx index 69add6139aed6..745c0cddbf835 100644 --- a/Utilities/DataSampling/src/DataSamplingReadoutAdapter.cxx +++ b/Utilities/DataSampling/src/DataSamplingReadoutAdapter.cxx @@ -10,6 +10,7 @@ // or submit itself to any jurisdiction. #include "DataSampling/DataSamplingReadoutAdapter.h" #include "Framework/DataProcessingHeader.h" +#include "Framework/RawDeviceService.h" #include "Headers/DataHeader.h" #include "Framework/DataSpecUtils.h" #include @@ -23,7 +24,9 @@ using DataHeader = o2::header::DataHeader; InjectorFunction dataSamplingReadoutAdapter(OutputSpec const& spec) { - return [spec](TimingInfo&, fair::mq::Device& device, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { + return [spec](TimingInfo&, ServiceRegistryRef const& ref, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { + auto *device = ref.get().device(); + for (size_t i = 0; i < parts.Size(); ++i) { DataHeader dh; @@ -36,7 +39,7 @@ InjectorFunction dataSamplingReadoutAdapter(OutputSpec const& spec) DataProcessingHeader dph{newTimesliceId, 0}; o2::header::Stack headerStack{dh, dph}; - sendOnChannel(device, std::move(headerStack), std::move(parts.At(i)), spec, channelRetriever); + sendOnChannel(*device, std::move(headerStack), std::move(parts.At(i)), spec, channelRetriever); } }; } diff --git a/run/o2sim_mctracks_proxy.cxx b/run/o2sim_mctracks_proxy.cxx index 8bd37a11bb44d..cd032dd35c4fa 100644 --- a/run/o2sim_mctracks_proxy.cxx +++ b/run/o2sim_mctracks_proxy.cxx @@ -15,6 +15,7 @@ #include "Framework/WorkflowSpec.h" #include "Framework/ConfigParamSpec.h" #include "Framework/ExternalFairMQDeviceProxy.h" +#include "Framework/RawDeviceService.h" #include "Framework/Task.h" #include "Framework/DataRef.h" #include "Framework/InputRecordWalker.h" @@ -92,7 +93,8 @@ InjectorFunction o2simKinematicsConverter(std::vector const& specs, auto MCTracksMessageCache = std::make_shared(); auto Nparts = std::make_shared(nPerTF); - return [timesliceId, specs, step, nevents, nPerTF, totalEventCounter, eventCounter, TFcounter, Nparts, MCHeadersMessageCache = MCHeadersMessageCache, MCTracksMessageCache = MCTracksMessageCache](TimingInfo& ti, fair::mq::Device& device, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) mutable { + return [timesliceId, specs, step, nevents, nPerTF, totalEventCounter, eventCounter, TFcounter, Nparts, MCHeadersMessageCache = MCHeadersMessageCache, MCTracksMessageCache = MCTracksMessageCache](TimingInfo& ti, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) mutable { + auto*device = services.get().device(); if (nPerTF < 0) { // if no aggregation requested, forward each message with the DPL header if (*timesliceId != newTimesliceId) { @@ -105,7 +107,7 @@ InjectorFunction o2simKinematicsConverter(std::vector const& specs, DataProcessingHeader dph{newTimesliceId, 0}; // we have to move the incoming data o2::header::Stack headerStack{dh, dph}; - sendOnChannel(device, std::move(headerStack), std::move(parts.At(i)), specs[i], channelRetriever); + sendOnChannel(*device, std::move(headerStack), std::move(parts.At(i)), specs[i], channelRetriever); } *timesliceId += step; } else { @@ -127,8 +129,8 @@ InjectorFunction o2simKinematicsConverter(std::vector const& specs, DataHeader tracksDH = headerFromSpec(specs[1], tracksSize, gSerializationMethodROOT, *Nparts, *eventCounter); o2::header::Stack ths{tracksDH, tdph}; - appendForSending(device, std::move(hhs), *TFcounter, std::move(parts.At(0)), specs[0], *MCHeadersMessageCache.get(), channelRetriever); - appendForSending(device, std::move(ths), *TFcounter, std::move(parts.At(1)), specs[1], *MCTracksMessageCache.get(), channelRetriever); + appendForSending(*device, std::move(hhs), *TFcounter, std::move(parts.At(0)), specs[0], *MCHeadersMessageCache.get(), channelRetriever); + appendForSending(*device, std::move(ths), *TFcounter, std::move(parts.At(1)), specs[1], *MCTracksMessageCache.get(), channelRetriever); ++(*eventCounter); } @@ -137,8 +139,8 @@ InjectorFunction o2simKinematicsConverter(std::vector const& specs, // send the events when the timeframe is accumulated LOGP(info, ">> Events: {}; TF counter: {}", *eventCounter, *TFcounter); *eventCounter = 0; - sendOnChannel(device, *MCHeadersMessageCache.get(), channelRetriever(specs[0], *TFcounter), *TFcounter); - sendOnChannel(device, *MCTracksMessageCache.get(), channelRetriever(specs[1], *TFcounter), *TFcounter); + sendOnChannel(*device, *MCHeadersMessageCache.get(), channelRetriever(specs[0], *TFcounter), *TFcounter); + sendOnChannel(*device, *MCTracksMessageCache.get(), channelRetriever(specs[1], *TFcounter), *TFcounter); ++(*TFcounter); MCHeadersMessageCache->Clear(); MCTracksMessageCache->Clear(); From 0a7db9e65c6a48445ee0ae71b892925d82bf92f9 Mon Sep 17 00:00:00 2001 From: iravasen Date: Mon, 9 Oct 2023 13:57:08 +0200 Subject: [PATCH 246/324] added a wait time of 30s between consecutive pushes to ccdb --- .../workflow/include/ITSWorkflow/DCSAdaposParserSpec.h | 4 ++++ .../ITSMFT/ITS/workflow/src/DCSAdaposParserSpec.cxx | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/DCSAdaposParserSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/DCSAdaposParserSpec.h index cd9be3afc4c95..bcc19ff15b85d 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/DCSAdaposParserSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/DCSAdaposParserSpec.h @@ -85,6 +85,10 @@ class ITSDCSAdaposParser : public Task std::string mCcdbFetchUrl = "http://ccdb-test.cern.ch:8080"; o2::ccdb::BasicCCDBManager& mMgr = o2::ccdb::BasicCCDBManager::instance(); long int startTime; + + // to avoid several pushes to CCDB + long int pushTime = 0; + long int lastPushTime = 0; }; // Create a processor spec diff --git a/Detectors/ITSMFT/ITS/workflow/src/DCSAdaposParserSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/DCSAdaposParserSpec.cxx index 3d14778053529..05bf3cf9b99bb 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/DCSAdaposParserSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/DCSAdaposParserSpec.cxx @@ -111,7 +111,12 @@ void ITSDCSAdaposParser::process(const gsl::span dps) } if (mapel->second.payload_pt1 + 8 != mCcdbAlpideParam->roFrameLengthInBC) { mStrobeToUpload = mapel->second.payload_pt1; - doStrobeUpload = true; + pushTime = o2::ccdb::getCurrentTimestamp(); + if (pushTime - lastPushTime > 30000) { // push to CCDB only if at least 30s passed from the last push + doStrobeUpload = true; + } else { + doStrobeUpload = false; + } } else { doStrobeUpload = false; } @@ -196,6 +201,9 @@ void ITSDCSAdaposParser::pushToCCDB(ProcessingContext& pc) info.getMetaData(), info.getStartValidityTimestamp(), info.getEndValidityTimestamp()); } + // uptade lastPushTime + lastPushTime = o2::ccdb::getCurrentTimestamp(); + return; } From a41a0d00a1359ce33fe77cc2ccc092427d0bb2a7 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Tue, 10 Oct 2023 09:47:11 +0200 Subject: [PATCH 247/324] DPL: When enumeration timeframe was rewinded, don't send a newer oldestPossible (#12048) --- Framework/Core/src/CommonServices.cxx | 5 +++++ Framework/Core/src/DecongestionService.h | 3 +++ Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Framework/Core/src/CommonServices.cxx b/Framework/Core/src/CommonServices.cxx index d6e62ce10e16d..81b1216c90c9c 100644 --- a/Framework/Core/src/CommonServices.cxx +++ b/Framework/Core/src/CommonServices.cxx @@ -466,6 +466,11 @@ o2::framework::ServiceSpec CommonServices::decongestionSpec() timesliceIndex.updateOldestPossibleOutput(); auto& proxy = ctx.services().get(); auto oldestPossibleOutput = relayer.getOldestPossibleOutput(); + if (decongestion->nextEnumerationTimesliceRewinded && decongestion->nextEnumerationTimeslice < oldestPossibleOutput.timeslice.value) { + LOGP(detail, "Not sending oldestPossible if nextEnumerationTimeslice was rewinded"); + return; + } + if (decongestion->lastTimeslice && oldestPossibleOutput.timeslice.value == decongestion->lastTimeslice) { LOGP(debug, "Not sending already sent value"); return; diff --git a/Framework/Core/src/DecongestionService.h b/Framework/Core/src/DecongestionService.h index c4b8ed80e6cf5..c45e9a36217ec 100644 --- a/Framework/Core/src/DecongestionService.h +++ b/Framework/Core/src/DecongestionService.h @@ -21,6 +21,9 @@ struct DecongestionService { /// The last timeslice which the ExpirationHandler::Creator callback /// created. This can be used to skip dummy iterations. size_t nextEnumerationTimeslice = 0; + /// Flag to indicate that we rewinded the nextExnumerationTimeslice. + /// The rewinded value must be checked when sending the oldestPossible. + bool nextEnumerationTimesliceRewinded = false; /// Last timeslice we communicated. Notice this should never go backwards. int64_t lastTimeslice = 0; /// The next timeslice we should consume, when running in order, diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 4a6e73706c1a9..dff5a75e6c755 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -563,8 +563,9 @@ InjectorFunction dplModelAdaptor(std::vector const& filterSpecs, DPL } // In case we did not send any part at all, we need to rewind by one // to avoid creating extra timeslices at the end of the run. + auto& decongestion = services.get(); + decongestion.nextEnumerationTimesliceRewinded = !didSendParts; if (didSendParts == false) { - auto& decongestion = services.get(); decongestion.nextEnumerationTimeslice -= 1; } if (not unmatchedDescriptions.empty()) { From 1260cdca65b1f352d29042c0f3782026cb1dee2e Mon Sep 17 00:00:00 2001 From: shahoian Date: Tue, 10 Oct 2023 01:53:45 +0200 Subject: [PATCH 248/324] Warn about CTF/rawTF readers waiting for remote data to be copied --- Detectors/CTF/workflow/src/CTFReaderSpec.cxx | 22 ++++++++++++-- Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx | 29 +++++++++++++++---- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx index 9eddb2e9b32c9..681547f9a814c 100644 --- a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx @@ -100,6 +100,8 @@ class CTFReaderSpec : public o2::framework::Task int mNFailedFiles = 0; int mFilesRead = 0; int mTFLength = 128; + int mNWaits = 0; + long mTotalWaitTime = 0; long mLastSendTime = 0L; long mCurrTreeEntry = 0L; long mImposeRunStartMS = 0L; @@ -127,8 +129,8 @@ void CTFReaderSpec::stopReader() return; } LOGP(info, "CTFReader stops processing, {} files read, {} files failed", mFilesRead - mNFailedFiles, mNFailedFiles); - LOGP(info, "CTF reading total timing: Cpu: {:.3f} Real: {:.3f} s for {} TFs in {} loops", - mTimer.CpuTime(), mTimer.RealTime(), mCTFCounter, mFileFetcher->getNLoops()); + LOGP(info, "CTF reading total timing: Cpu: {:.3f} Real: {:.3f} s for {} TFs in {} loops, spent {:.2} s in {} data waiting states", + mTimer.CpuTime(), mTimer.RealTime(), mCTFCounter, mFileFetcher->getNLoops(), 1e-6 * mTotalWaitTime, mNWaits); mRunning = false; mFileFetcher->stop(); mFileFetcher.reset(); @@ -195,6 +197,8 @@ void CTFReaderSpec::run(ProcessingContext& pc) mInput.tfRateLimit = std::stoi(pc.services().get().device()->fConfig->GetValue("timeframes-rate-limit")); } std::string tfFileName; + bool waitAcknowledged = false; + long startWait = 0; while (mRunning) { if (mCTFTree) { // there is a tree open with multiple CTF @@ -218,15 +222,27 @@ void CTFReaderSpec::run(ProcessingContext& pc) mRunning = false; break; } + if (!waitAcknowledged) { + startWait = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); + waitAcknowledged = true; + } pc.services().get().waitFor(5); continue; } + if (waitAcknowledged) { + long waitTime = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count() - startWait; + mTotalWaitTime += waitTime; + if (++mNWaits > 1) { + LOGP(warn, "Resuming reading after waiting for data {:.2} s (accumulated {:.2} s delay in {} waits)", 1e-6 * waitTime, 1e-6 * mTotalWaitTime, mNWaits); + } + waitAcknowledged = false; + } LOG(info) << "Reading CTF input " << ' ' << tfFileName; openCTFFile(tfFileName); } if (mCTFCounter >= mInput.maxTFs || (!mInput.ctfIDs.empty() && mSelIDEntry >= mInput.ctfIDs.size())) { // done - LOG(info) << "All CTFs from selected range were injected, stopping"; + LOGP(info, "All CTFs from selected range were injected, stopping"); mRunning = false; } else if (mRunning && !mCTFTree && mFileFetcher->getNextFileInQueue().empty() && !mFileFetcher->isRunning()) { // previous tree was done, can we read more? mRunning = false; diff --git a/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx b/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx index 32ba967ffd102..245dc07082024 100644 --- a/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx +++ b/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx @@ -78,6 +78,8 @@ class TFReaderSpec : public o2f::Task std::unordered_map mSeenOutputMap; int mTFCounter = 0; int mTFBuilderCounter = 0; + int mNWaits = 0; + long mTotalWaitTime = 0; size_t mSelIDEntry = 0; // next TFID to select from the mInput.tfIDs (if non-empty) bool mRunning = false; TFReaderInp mInput; // command line inputs @@ -230,10 +232,6 @@ void TFReaderSpec::run(o2f::ProcessingContext& ctx) }; while (1) { - if (mTFCounter >= mInput.maxTFs) { // done - stopProcessing(ctx); - break; - } if (mTFQueue.size()) { static o2f::RateLimiter limiter; limiter.check(ctx, mInput.tfRateLimit, mInput.minSHM); @@ -283,6 +281,9 @@ void TFReaderSpec::run(o2f::ProcessingContext& ctx) } usleep(5000); // wait 5ms for new TF to be built } + if (mTFCounter >= mInput.maxTFs) { // done + stopProcessing(ctx); + } } //____________________________________________________________ @@ -300,7 +301,7 @@ void TFReaderSpec::endOfStream(o2f::EndOfStreamContext& ec) //___________________________________________________________ void TFReaderSpec::stopProcessing(o2f::ProcessingContext& ctx) { - LOG(info) << mTFCounter << " TFs in " << mFileFetcher->getNLoops() << " loops were sent"; + LOGP(info, "{} TFs in {} loops were sent, spent {:.2} s in {} data waiting states", mTFCounter, mFileFetcher->getNLoops(), 1e-6 * mTotalWaitTime, mNWaits); mRunning = false; mFileFetcher->stop(); mFileFetcher.reset(); @@ -333,6 +334,8 @@ void TFReaderSpec::TFBuilder() // build TFs and add to the queue std::string tfFileName; auto sleepTime = std::chrono::microseconds(mInput.delay_us > 10000 ? mInput.delay_us : 10000); + bool waitAcknowledged = false; + long startWait = 0; while (mRunning && mDevice) { if (mTFQueue.size() >= size_t(mInput.maxTFCache)) { std::this_thread::sleep_for(sleepTime); @@ -352,9 +355,23 @@ void TFReaderSpec::TFBuilder() break; } if (tfFileName.empty()) { - std::this_thread::sleep_for(10ms); // fait for the files cache to be filled + if (!waitAcknowledged) { + startWait = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); + waitAcknowledged = true; + } + std::this_thread::sleep_for(10ms); // wait for the files cache to be filled continue; } + if (waitAcknowledged) { + long waitTime = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count() - startWait; + mTotalWaitTime += waitTime; + if (++mNWaits > 1) { + LOGP(warn, "Resuming reading after waiting for data {:.2} s (accumulated {:.2} s delay in {} waits)", 1e-6 * waitTime, 1e-6 * mTotalWaitTime, mNWaits); + } + waitAcknowledged = false; + startWait = 0; + } + LOG(info) << "Processing file " << tfFileName; SubTimeFrameFileReader reader(tfFileName, mInput.detMask); size_t locID = 0; From 7fe850406b354aa3a3ac96b29e97138d1be3ffae Mon Sep 17 00:00:00 2001 From: shahoian Date: Tue, 10 Oct 2023 02:50:33 +0200 Subject: [PATCH 249/324] Relax type check for old dictionaries in compat mode, warn only. Initially some CTF blocks were declared unsigned to store incremenets of ordered data but in some cases ordering was broken. To not inflate dynamic range due to the neagative -> unsigned cast we changed these types to signed but in a few old dictionaries we still have data min/max which does not fit to the signed range. For these old dictionaries we have no other way but to not throw exception on the failed type check. The (de)coding does not suffer since if done consistently with the same data type defined, even if it does not match to the data range. --- .../include/DetectorsCommonDataFormats/EncodedBlocks.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h index 3ffdec9841cb4..a0853b8f14c73 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/EncodedBlocks.h @@ -386,7 +386,11 @@ class EncodedBlocks assert(dictMax <= metadata.max); if ((dictMin < sourceMin) || (dictMax > sourceMax)) { - throw std::runtime_error(fmt::format("value range of dictionary and target datatype are incompatible: target type [{},{}] vs dictionary [{},{}]", sourceMin, sourceMax, dictMin, dictMax)); + if (ansVersion == ANSVersionCompat && mHeader.majorVersion == 1 && mHeader.minorVersion == 0 && mHeader.dictTimeStamp < 1653192000000) { + LOGP(warn, "value range of dictionary and target datatype are incompatible: target type [{},{}] vs dictionary [{},{}], tolerate in compat mode for old dictionaries", sourceMin, sourceMax, dictMin, dictMax); + } else { + throw std::runtime_error(fmt::format("value range of dictionary and target datatype are incompatible: target type [{},{}] vs dictionary [{},{}]", sourceMin, sourceMax, dictMin, dictMax)); + } } }(); From 22b89a39f698a2cc6f24f24a208982ceb6a60d0a Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 6 Oct 2023 16:14:01 +0200 Subject: [PATCH 250/324] Flag if propation has failed in DCAFitterN --- .../DCAFitter/include/DCAFitter/DCAFitterN.h | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/Common/DCAFitter/include/DCAFitter/DCAFitterN.h b/Common/DCAFitter/include/DCAFitter/DCAFitterN.h index 00b5230390cd9..c7f6631de5abe 100644 --- a/Common/DCAFitter/include/DCAFitter/DCAFitterN.h +++ b/Common/DCAFitter/include/DCAFitter/DCAFitterN.h @@ -125,6 +125,9 @@ class DCAFitterN ///< check if propagation of tracks to candidate vertex was done bool isPropagateTracksToVertexDone(int cand = 0) const { return mTrPropDone[mOrder[cand]]; } + ///< check if propagation of tracks to candidate vertex was done + bool isPropagationFailure(int cand = 0) const { return mPropFailed[mOrder[cand]]; } + ///< track param propagated to V0 candidate (no check for the candidate validity) /// propagateTracksToVertex must be called in advance Track& getTrack(int i, int cand = 0) @@ -150,7 +153,7 @@ class DCAFitterN o2::track::TrackPar createParentTrackPar(int cand = 0, bool sectorAlpha = true) const; ///< calculate on the fly track param (no cov mat) at candidate, check isValid to make sure propagation was successful - o2::track::TrackPar getTrackParamAtPCA(int i, int cand = 0) const; + o2::track::TrackPar getTrackParamAtPCA(int i, int cand = 0); ///< recalculate PCA as a cov-matrix weighted mean, even if absDCA method was used bool recalculatePCAWithErrors(int cand = 0); @@ -232,8 +235,8 @@ class DCAFitterN bool minimizeChi2NoErr(); bool roughDZCut() const; bool closerToAlternative() const; - bool propagateToX(o2::track::TrackParCov& t, float x) const; - bool propagateParamToX(o2::track::TrackPar& t, float x) const; + bool propagateToX(o2::track::TrackParCov& t, float x); + bool propagateParamToX(o2::track::TrackPar& t, float x); static double getAbsMax(const VecND& v); ///< track param positions at V0 candidate (no check for the candidate validity) @@ -308,7 +311,8 @@ class DCAFitterN std::array mPCA; // PCA for each vertex candidate std::array mChi2 = {0}; // Chi2 at PCA candidate std::array mNIters; // number of iterations for each seed - std::array mTrPropDone; // Flag that the tracks are fully propagated to PCA + std::array mTrPropDone{}; // Flag that the tracks are fully propagated to PCA + std::array mPropFailed{}; // Flag that some propagation failed for this PCA candidate MatSym3D mWeightInv; // inverse weight of single track, [sum{M^T E M}]^-1 in EQ.T std::array mOrder{0}; int mCurHyp = 0; @@ -354,6 +358,9 @@ int DCAFitterN::process(const Tr&... args) if (!mCrossings.set(mTrAux[0], *mOrigTrPtr[0], mTrAux[1], *mOrigTrPtr[1], mMaxDXYIni)) { // even for N>2 it should be enough to test just 1 loop return 0; // no crossing } + for (int ih = 0; ih < MAXHYP; ih++) { + mPropFailed[ih] = false; + } if (mUseAbsDCA) { calcRMatrices(); // needed for fast residuals derivatives calculation in case of abs. distance minimization } @@ -825,7 +832,7 @@ bool DCAFitterN::propagateTracksToVertex(int icand) //___________________________________________________________________ template -inline o2::track::TrackPar DCAFitterN::getTrackParamAtPCA(int i, int icand) const +inline o2::track::TrackPar DCAFitterN::getTrackParamAtPCA(int i, int icand) { // propagate tracks param only to current vertex (if not already done) int ord = mOrder[icand]; @@ -1058,24 +1065,34 @@ o2::track::TrackPar DCAFitterN::createParentTrackPar(int cand, bool //___________________________________________________________________ template -inline bool DCAFitterN::propagateParamToX(o2::track::TrackPar& t, float x) const +inline bool DCAFitterN::propagateParamToX(o2::track::TrackPar& t, float x) { + bool res = true; if (mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) { - return o2::base::Propagator::Instance()->PropagateToXBxByBz(t, x, mMaxSnp, mMaxStep, mMatCorr); + res = o2::base::Propagator::Instance()->PropagateToXBxByBz(t, x, mMaxSnp, mMaxStep, mMatCorr); } else { - return t.propagateParamTo(x, mBz); + res = t.propagateParamTo(x, mBz); } + if (!res) { + mPropFailed[mCurHyp] = true; + } + return res; } //___________________________________________________________________ template -inline bool DCAFitterN::propagateToX(o2::track::TrackParCov& t, float x) const +inline bool DCAFitterN::propagateToX(o2::track::TrackParCov& t, float x) { + bool res = true; if (mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) { - return o2::base::Propagator::Instance()->PropagateToXBxByBz(t, x, mMaxSnp, mMaxStep, mMatCorr); + res = o2::base::Propagator::Instance()->PropagateToXBxByBz(t, x, mMaxSnp, mMaxStep, mMatCorr); } else { - return t.propagateTo(x, mBz); + res = t.propagateTo(x, mBz); + } + if (!res) { + mPropFailed[mCurHyp] = true; } + return res; } using DCAFitter2 = DCAFitterN<2, o2::track::TrackParCov>; From 0e722d0c68d2a980cfa02107a42194dcbd4a2e09 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 10 Oct 2023 11:13:51 +0200 Subject: [PATCH 251/324] Reduce peak memory usage of TrackerTraits::findTracks (#12046) --- .../ITSMFT/ITS/tracking/src/TrackerTraits.cxx | 27 +++++-------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx index f6f34cae67422..ff4642a99f7c3 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx @@ -486,11 +486,9 @@ void TrackerTraits::findRoads(const int iteration) void TrackerTraits::findTracks() { - std::vector> tracks(mNThreads); - for (auto& tracksV : tracks) { - tracksV.reserve(mTimeFrame->getRoads().size() / mNThreads); - } + std::vector tracks(mTimeFrame->getRoads().size()); + std::atomic trackIndex{0}; #pragma omp parallel for num_threads(mNThreads) for (size_t ri = 0; ri < mTimeFrame->getRoads().size(); ++ri) { auto& road = mTimeFrame->getRoads()[ri]; @@ -555,12 +553,6 @@ void TrackerTraits::findTracks() } } - /// Track seed preparation. Clusters are numbered progressively from the innermost going outward. - const auto& cluster1_glo = mTimeFrame->getUnsortedClusters()[lastCellLevel].at(clusters[lastCellLevel]); - const auto& cluster2_glo = mTimeFrame->getUnsortedClusters()[lastCellLevel + 1].at(clusters[lastCellLevel + 1]); - const auto& cluster3_glo = mTimeFrame->getUnsortedClusters()[lastCellLevel + 2].at(clusters[lastCellLevel + 2]); - const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(lastCellLevel + 2).at(clusters[lastCellLevel + 2]); - TrackITSExt temporaryTrack{mTimeFrame->getCellSeeds()[lastCellLevel][lastCellIndex]}; temporaryTrack.setChi2(mTimeFrame->getCellSeedsChi2()[lastCellLevel][lastCellIndex]); for (size_t iC = 0; iC < clusters.size(); ++iC) { @@ -586,25 +578,18 @@ void TrackerTraits::findTracks() continue; } // temporaryTrack.setROFrame(rof); -#ifdef WITH_OPENMP - int iThread = omp_get_thread_num(); -#else - int iThread = 0; -#endif - tracks[iThread].emplace_back(temporaryTrack); + tracks[trackIndex++] = temporaryTrack; } - for (int iV{1}; iV < mNThreads; ++iV) { - tracks[0].insert(tracks[0].end(), tracks[iV].begin(), tracks[iV].end()); - } + tracks.resize(trackIndex); if (mApplySmoothing) { // Smoothing tracks } - std::sort(tracks[0].begin(), tracks[0].end(), + std::sort(tracks.begin(), tracks.end(), [](TrackITSExt& track1, TrackITSExt& track2) { return track1.isBetter(track2, 1.e6f); }); - for (auto& track : tracks[0]) { + for (auto& track : tracks) { int nShared = 0; for (int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) { if (track.getClusterIndex(iLayer) == constants::its::UnusedIndex) { From cb41d67a7e52ac7a58e51926e9582f4ef88e236f Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Tue, 10 Oct 2023 13:49:35 +0200 Subject: [PATCH 252/324] MatLUT: Option for fast layer lookup (#12009) * MatLUT: Option for fast layer lookup Profile analysis has shown that material budget calculations used in tracking, spent most time in (a) determination of a cylindrical layer (b) determination of a phi sector in a layer This commit proposes an improvement for (a). Instead of determining the layer id via binary search, we can use a simple lookup structure working on regular R-intervals. The commit offers a 5-8% speed improvement for ITS reconstruction and should be beneficial for other things such as strangeness tracking, or any algorithm using MatLUT. Relates to https://alice.its.cern.ch/jira/browse/O2-4170 * Make compile on GPU * Update MatLayerCylSet.cxx --- .../include/DetectorsBase/MatLayerCylSet.h | 14 +++++ Detectors/Base/src/MatLayerCylSet.cxx | 61 ++++++++++++++++--- 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/Detectors/Base/include/DetectorsBase/MatLayerCylSet.h b/Detectors/Base/include/DetectorsBase/MatLayerCylSet.h index c88b1dd9e4947..3ffa7424ee61e 100644 --- a/Detectors/Base/include/DetectorsBase/MatLayerCylSet.h +++ b/Detectors/Base/include/DetectorsBase/MatLayerCylSet.h @@ -79,6 +79,9 @@ class MatLayerCylSet : public o2::gpu::FlatObject static MatLayerCylSet* loadFromFile(const std::string& inpFName = "matbud.root"); static MatLayerCylSet* rectifyPtrFromFile(MatLayerCylSet* ptr); + // initializes internal voxel lookup + void initLayerVoxelLU(); + void flatten(); MatLayerCyl& getLayer(int i) { return get()->mLayers[i]; } @@ -98,6 +101,9 @@ class MatLayerCylSet : public o2::gpu::FlatObject GPUd() int searchSegment(float val, int low = -1, int high = -1) const; + /// searches a layer based on r2 input, using a lookup table + GPUd() int searchLayerFast(float r2, int low = -1, int high = -1) const; + #ifndef GPUCA_GPUCODE //----------------------------------------------------------- std::size_t estimateFlatBufferSize() const; @@ -118,6 +124,14 @@ class MatLayerCylSet : public o2::gpu::FlatObject static constexpr size_t getBufferAlignmentBytes() { return 8; } #endif // !GPUCA_GPUCODE + static constexpr float LayerRMax = 500; // maximum value of R lookup (corresponds to last layer of MatLUT) + static constexpr float VoxelRDelta = 0.05; // voxel spacing for layer lookup; seems a natural choice - corresponding ~ to smallest spacing + static constexpr float InvVoxelRDelta = 1.f / VoxelRDelta; + static constexpr int NumVoxels = int(LayerRMax / VoxelRDelta); + + uint16_t mLayerVoxelLU[2 * NumVoxels]; //! helper structure to lookup a layer based on known radius (static dimension for easy copy to GPU) + bool mInitializedLayerVoxelLU = false; //! if the voxels have been initialized + ClassDefNV(MatLayerCylSet, 1); }; diff --git a/Detectors/Base/src/MatLayerCylSet.cxx b/Detectors/Base/src/MatLayerCylSet.cxx index a0f8e60708de5..fb2e720427016 100644 --- a/Detectors/Base/src/MatLayerCylSet.cxx +++ b/Detectors/Base/src/MatLayerCylSet.cxx @@ -8,7 +8,6 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. - /// \file MatLayerCylSet.cxx /// \brief Implementation of the wrapper for the set of cylindrical material layers @@ -16,7 +15,6 @@ #include "CommonConstants/MathConstants.h" #ifndef GPUCA_ALIGPUCODE // this part is unvisible on GPU version - #include "GPUCommonLogger.h" #include #include "CommonUtils/TreeStreamRedirector.h" @@ -177,6 +175,29 @@ void MatLayerCylSet::writeToFile(const std::string& outFName) outf.Close(); } +void MatLayerCylSet::initLayerVoxelLU() +{ + if (mInitializedLayerVoxelLU) { + LOG(info) << "Layer voxel already initialized; Aborting"; + return; + } + LOG(info) << "Initializing voxel layer lookup"; + // do some check if voxels are dimensioned correctly + if (LayerRMax < get()->mRMax) { + LOG(fatal) << "Cannot initialized layer voxel lookup due to dimension problem (fix constants in MatLayerCylSet.h)"; + } + for (int voxel = 0; voxel < NumVoxels; ++voxel) { + // check the 2 extremes of this voxel "covering" + const auto lowerR = voxel * VoxelRDelta; + const auto upperR = lowerR + VoxelRDelta; + const auto lowerSegment = searchSegment(lowerR * lowerR); + const auto upperSegment = searchSegment(upperR * upperR); + mLayerVoxelLU[2 * voxel] = lowerSegment; + mLayerVoxelLU[2 * voxel + 1] = upperSegment; + } + mInitializedLayerVoxelLU = true; +} + //________________________________________________________________________________ MatLayerCylSet* MatLayerCylSet::loadFromFile(const std::string& inpFName) { @@ -190,7 +211,8 @@ MatLayerCylSet* MatLayerCylSet::loadFromFile(const std::string& inpFName) LOG(error) << "Failed to load mat.LUT from " << inpFName; return nullptr; } - return rectifyPtrFromFile(mb); + auto rptr = rectifyPtrFromFile(mb); + return rptr; } //________________________________________________________________________________ @@ -200,6 +222,7 @@ MatLayerCylSet* MatLayerCylSet::rectifyPtrFromFile(MatLayerCylSet* ptr) if (ptr && !ptr->get()) { ptr->fixPointers(); } + ptr->initLayerVoxelLU(); return ptr; } @@ -267,10 +290,11 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa while (lrID >= lmin) { // go from outside to inside const auto& lr = getLayer(lrID); int nphiSlices = lr.getNPhiSlices(); - int nc = ray.crossLayer(lr); + int nc = ray.crossLayer(lr); // determines how many crossings this ray has with this tubular layer for (int ic = nc; ic--;) { float cross1, cross2; ray.getCrossParams(ic, cross1, cross2); // tmax,tmin of crossing the layer + auto phi0 = ray.getPhi(cross1), phi1 = ray.getPhi(cross2), dPhi = phi0 - phi1; auto phiID = lr.getPhiSliceID(phi0), phiIDLast = lr.getPhiSliceID(phi1); // account for eventual wrapping around 0 @@ -283,6 +307,7 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa phiID += nphiSlices; } } + int stepPhiID = phiID > phiIDLast ? -1 : 1; bool checkMorePhi = true; auto tStartPhi = cross1, tEndPhi = 0.f; @@ -390,21 +415,40 @@ GPUd() bool MatLayerCylSet::getLayersRange(const Ray& ray, short& lmin, short& l return false; } int lmxInt, lmnInt; - lmxInt = rmax2 < getRMax2() ? searchSegment(rmax2, 0) : get()->mNRIntervals - 2; - lmnInt = rmin2 >= getRMin2() ? searchSegment(rmin2, 0, lmxInt + 1) : 0; + if (!mInitializedLayerVoxelLU) { + lmxInt = rmax2 < getRMax2() ? searchSegment(rmax2, 0) : get()->mNRIntervals - 2; + lmnInt = rmin2 >= getRMin2() ? searchSegment(rmin2, 0, lmxInt + 1) : 0; + } else { + lmxInt = rmax2 < getRMax2() ? searchLayerFast(rmax2, 0) : get()->mNRIntervals - 2; + lmnInt = rmin2 >= getRMin2() ? searchLayerFast(rmin2, 0, lmxInt + 1) : 0; + } + const auto* interval2LrID = get()->mInterval2LrID; lmax = interval2LrID[lmxInt]; lmin = interval2LrID[lmnInt]; // make sure lmnInt and/or lmxInt are not in the gap if (lmax < 0) { - lmax = interval2LrID[--lmxInt]; // rmax2 is in the gap, take highest layer below rmax2 + lmax = interval2LrID[lmxInt - 1]; // rmax2 is in the gap, take highest layer below rmax2 } if (lmin < 0) { - lmin = interval2LrID[++lmnInt]; // rmin2 is in the gap, take lowest layer above rmin2 + lmin = interval2LrID[lmnInt + 1]; // rmin2 is in the gap, take lowest layer above rmin2 } return lmin <= lmax; // valid if both are not in the same gap } +GPUd() int MatLayerCylSet::searchLayerFast(float r2, int low, int high) const +{ + // we can avoid the sqrt .. at the cost of more memory in the lookup + const auto index = 2 * int(o2::gpu::CAMath::Sqrt(r2) * InvVoxelRDelta); + const auto layersfirst = mLayerVoxelLU[index]; + const auto layerslast = mLayerVoxelLU[index + 1]; + if (layersfirst != layerslast) { + // this means the voxel is undecided and we revert to search + return searchSegment(r2, layersfirst, layerslast + 1); + } + return layersfirst; +} + GPUd() int MatLayerCylSet::searchSegment(float val, int low, int high) const { ///< search segment val belongs to. The val MUST be within the boundaries @@ -424,6 +468,7 @@ GPUd() int MatLayerCylSet::searchSegment(float val, int low, int high) const } mid = (low + high) >> 1; } + return mid; } From 00a6e175fd4fbcf06b543305aa8dde1992add3f3 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Tue, 10 Oct 2023 10:07:18 +0200 Subject: [PATCH 253/324] EMCAL: Downscale raw parser error messages --- Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx index 06778a40166c4..e53b18fafcbb0 100644 --- a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx +++ b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx @@ -365,7 +365,10 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) if (bcfreqFound != bcFreq.end()) { const auto& activelinks = bcfreqFound->second; if (activelinks != bitSetActiveLinks) { - LOG(error) << "Not all EMC active links contributed in global BCid=" << interaction.toLong() << ": mask=" << (activelinks ^ bitSetActiveLinks); + static int nErrors = 0; + if (nErrors++ < 3) { + LOG(error) << "Not all EMC active links contributed in global BCid=" << interaction.toLong() << ": mask=" << (activelinks ^ bitSetActiveLinks) << (nErrors == 3 ? " (not reporting further errors to avoid spamming)" : ""); + } if (mCreateRawDataErrors) { for (std::size_t ilink = 0; ilink < bitSetActiveLinks.size(); ilink++) { if (!bitSetActiveLinks.test(ilink)) { From 9f22c6b31ca219085b430bad1c0ddef1ba97cfb9 Mon Sep 17 00:00:00 2001 From: Matthias Kleiner <48915672+matthias-kleiner@users.noreply.github.com> Date: Wed, 11 Oct 2023 07:36:56 +0200 Subject: [PATCH 254/324] TPC: Adding workflow for integrated DCAs for corrections and QC (#11984) * TPC: Adding workflow for integrated DCAs for corrections and QC - DCAs are integrated in phi bins over all tgl and in tgl bins integrated over phi - DCA integrated per side is also stored - RMS and number of tracks are stored per bin - Multithreading for DCA calculation of tracks - Additional information with per track DCAs can be written with debug streamer - Adding start time as meta data to integrated currents - Adding DCAs for ITS-TPC matched tracks - Adding collision vertex - Adding nearest vertex to tracks which have no vertex assigned - Adding DCAz from time bin delta Adding ITS-TPC matching efficiency Adding: sqrt(chi2Match), MIP/dedx, sqrt(chi2), nCl * Adding time information, fixing bug when creating tree * Adding ITS-TPC standalone and afterburner efficiencies * Speed up track propagation * Fixing range check of bins --- .../Utils/include/CommonUtils/DebugStreamer.h | 3 +- .../IntegratedClusterCalibrator.h | 279 +++++- .../src/DetectorsCalibrationLinkDef.h | 8 + .../src/IntegratedClusterCalibrator.cxx | 217 ++++ .../TPC/base/include/TPCBase/CDBInterface.h | 4 + .../include/TPCCalibration/RobustAverage.h | 16 +- .../TPC/calibration/src/RobustAverage.cxx | 88 +- Detectors/TPC/workflow/CMakeLists.txt | 19 + .../TPCWorkflow/TPCMergeTimeSeriesSpec.h | 27 + .../TPCWorkflow/TPCTimeSeriesReaderSpec.h | 27 + .../include/TPCWorkflow/TPCTimeSeriesSpec.h | 30 + .../TPCWorkflow/TPCTimeSeriesWriterSpec.h | 27 + .../workflow/src/TPCMergeTimeSeriesSpec.cxx | 190 ++++ .../workflow/src/TPCTimeSeriesReaderSpec.cxx | 160 +++ .../TPC/workflow/src/TPCTimeSeriesSpec.cxx | 923 ++++++++++++++++++ .../workflow/src/TPCTimeSeriesWriterSpec.cxx | 41 + .../src/time-series-merge-integrator.cxx | 34 + .../TPC/workflow/src/time-series-reader.cxx | 25 + .../TPC/workflow/src/tpc-time-series.cxx | 48 + 19 files changed, 2149 insertions(+), 17 deletions(-) create mode 100644 Detectors/TPC/workflow/include/TPCWorkflow/TPCMergeTimeSeriesSpec.h create mode 100644 Detectors/TPC/workflow/include/TPCWorkflow/TPCTimeSeriesReaderSpec.h create mode 100644 Detectors/TPC/workflow/include/TPCWorkflow/TPCTimeSeriesSpec.h create mode 100644 Detectors/TPC/workflow/include/TPCWorkflow/TPCTimeSeriesWriterSpec.h create mode 100644 Detectors/TPC/workflow/src/TPCMergeTimeSeriesSpec.cxx create mode 100644 Detectors/TPC/workflow/src/TPCTimeSeriesReaderSpec.cxx create mode 100644 Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx create mode 100644 Detectors/TPC/workflow/src/TPCTimeSeriesWriterSpec.cxx create mode 100644 Detectors/TPC/workflow/src/time-series-merge-integrator.cxx create mode 100644 Detectors/TPC/workflow/src/time-series-reader.cxx create mode 100644 Detectors/TPC/workflow/src/tpc-time-series.cxx diff --git a/Common/Utils/include/CommonUtils/DebugStreamer.h b/Common/Utils/include/CommonUtils/DebugStreamer.h index 30fc74bf2b158..38de5fad34f39 100644 --- a/Common/Utils/include/CommonUtils/DebugStreamer.h +++ b/Common/Utils/include/CommonUtils/DebugStreamer.h @@ -39,7 +39,8 @@ enum StreamFlags { streamUpdateTrack = 1 << 6, ///< stream update track informations streamRejectCluster = 1 << 7, ///< stream cluster rejection informations streamMergeBorderTracks = 1 << 8, ///< stream MergeBorderTracks - streamFlagsCount = 9 ///< total number of streamers + streamTimeSeries = 1 << 9, ///< stream tpc DCA debug tree + streamFlagsCount = 10 ///< total number of streamers }; enum SamplingTypes { diff --git a/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h b/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h index dbdd329e1ca3b..884997d54865e 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h +++ b/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h @@ -20,6 +20,8 @@ #include "DetectorsCalibration/TimeSlotCalibration.h" #include "DetectorsCalibration/TimeSlot.h" +class TTree; + namespace o2 { @@ -38,9 +40,11 @@ namespace tof struct ITOFC { std::vector mITOFCNCl; ///< integrated 1D TOF cluster currents std::vector mITOFCQ; ///< integrated 1D TOF qTot currents + long mTimeMS{}; ///< start time in ms bool areSameSize() const { return sameSize(mITOFCNCl, mITOFCQ); } ///< check if stored currents have same number of entries bool isEmpty() const { return mITOFCNCl.empty(); } ///< check if values are empty size_t getEntries() const { return mITOFCNCl.size(); } ///< \return returns number of values stored + void setStartTime(long timeMS) { mTimeMS = timeMS; } /// acummulate integrated currents at given index /// \param posIndex index where data will be copied to @@ -66,7 +70,7 @@ struct ITOFC { mITOFCQ.resize(nTotal); } - ClassDefNV(ITOFC, 1); + ClassDefNV(ITOFC, 2); }; } // end namespace tof @@ -81,6 +85,7 @@ struct ITPCC { std::vector mIQTotC; ///< integrated 1D-currents for QTot A-side std::vector mINClA; ///< integrated 1D-currents for NCl A-side std::vector mINClC; ///< integrated 1D-currents for NCl A-side + long mTimeMS{}; ///< start time in ms float compression(float value, const int nBits) const { @@ -104,6 +109,7 @@ struct ITPCC { bool areSameSize() const { return sameSize(mIQMaxA, mIQMaxC, mIQTotA, mIQTotC, mINClA, mINClC); } ///< check if stored currents have same number of entries bool isEmpty() const { return mIQMaxA.empty(); } ///< check if values are empty size_t getEntries() const { return mIQMaxA.size(); } ///< \return returns number of values stored + void setStartTime(long timeMS) { mTimeMS = timeMS; } /// acummulate integrated currents at given index /// \param posIndex index where data will be copied to @@ -163,7 +169,261 @@ struct ITPCC { std::transform(mINClC.begin(), mINClC.end(), mINClC.begin(), [factor](const float val) { return val * factor; }); } - ClassDefNV(ITPCC, 1); + ClassDefNV(ITPCC, 2); +}; + +/// struct containing time series values +struct TimeSeries { + std::vector mDCAr_A_Median; ///< integrated 1D DCAr for A-side median in phi/tgl slices + std::vector mDCAr_C_Median; ///< integrated 1D DCAr for C-side weighted mean in phi/tgl slices + std::vector mDCAr_A_WeightedMean; ///< integrated 1D DCAr for A-side weighted mean in phi/tgl slices + std::vector mDCAr_C_WeightedMean; ///< integrated 1D DCAr for C-side median in phi/tgl slices + std::vector mDCAr_A_RMS; ///< integrated 1D DCAr for A-side RMS in phi/tgl slices + std::vector mDCAr_C_RMS; ///< integrated 1D DCAr for C-side RMS in phi/tgl slices + std::vector mDCAr_A_NTracks; ///< number of tracks used to calculate the DCAs + std::vector mDCAr_C_NTracks; ///< number of tracks used to calculate the DCAs + std::vector mDCAz_A_Median; ///< integrated 1D DCAz for A-side median in phi/tgl slices + std::vector mDCAz_C_Median; ///< integrated 1D DCAz for C-side median in phi/tgl slices + std::vector mDCAz_A_WeightedMean; ///< integrated 1D DCAz for A-side weighted mean in phi/tgl slices + std::vector mDCAz_C_WeightedMean; ///< integrated 1D DCAz for C-side weighted mean in phi/tgl slices + std::vector mDCAz_A_RMS; ///< integrated 1D DCAz for A-side RMS in phi/tgl slices + std::vector mDCAz_C_RMS; ///< integrated 1D DCAz for C-side RMS in phi/tgl slices + std::vector mDCAz_A_NTracks; ///< number of tracks used to calculate the DCAs + std::vector mDCAz_C_NTracks; ///< number of tracks used to calculate the DCAs + std::vector mMIPdEdxRatioA; ///< ratio of MIP/dEdx + std::vector mMIPdEdxRatioC; ///< ratio of MIP/dEdx + std::vector mTPCChi2A; ///< Chi2 of TPC tracks + std::vector mTPCChi2C; ///< Chi2 of TPC tracks + std::vector mTPCNClA; ///< number of TPC cluster + std::vector mTPCNClC; ///< number of TPC cluster + + unsigned char mNBinsPhi{}; ///< number of tgl bins + unsigned char mNBinsTgl{}; ///< number of phi bins + unsigned char mNBinsqPt{}; ///< number of qPt bins + long mTimeMS{}; ///< start time in ms + + /// dump object to tree + /// \param outFileName name of the output file + /// \param nHBFPerTF number of orbits per TF + void dumpToTree(TTree& tree, const char* prefix = "", const int nHBFPerTF = 32) const; + void setStartTime(long timeMS) { mTimeMS = timeMS; } + bool areSameSize() const { return sameSize(mDCAr_A_WeightedMean, mDCAr_C_WeightedMean, mDCAz_A_WeightedMean, mDCAz_C_WeightedMean, mDCAr_A_Median, mDCAr_C_Median, mDCAr_A_RMS, mDCAr_C_RMS, mDCAz_A_Median, mDCAz_C_Median, mDCAz_A_RMS, mDCAz_C_RMS, mDCAz_C_NTracks, mDCAr_A_NTracks, mDCAz_A_NTracks, mDCAz_C_NTracks); } ///< check if stored currents have same number of entries + bool isEmpty() const { return mDCAr_A_Median.empty(); } ///< check if values are empty + + size_t getEntries() const { return mDCAr_A_Median.size(); } ///< \return returns number of values stored + /// \return returns total number of bins + int getNBins() const { return mNBinsTgl + mNBinsPhi + mNBinsqPt + 1; } + + /// \return returns index for given phi bin + int getIndexPhi(const int iPhi, int slice = 0) const { return iPhi + slice * getNBins(); } + + /// \return returns index for given tgl bin + int getIndexTgl(const int iTgl, int slice = 0) const { return mNBinsPhi + iTgl + slice * getNBins(); } + + /// \return returns index for given qPt bin + int getIndexqPt(const int iqPt, int slice = 0) const { return mNBinsPhi + mNBinsTgl + iqPt + slice * getNBins(); } + + /// \return returns index for integrated over all bins + int getIndexInt(int slice = 0) const { return getNBins() - 1 + slice * getNBins(); } + + /// acummulate integrated currents at given index + /// \param posIndex index where data will be copied to + /// \param data integrated currents which will be copied + void fill(const unsigned int posIndex, const TimeSeries& data) + { + mNBinsPhi = data.mNBinsPhi; + mNBinsTgl = data.mNBinsTgl; + mNBinsqPt = data.mNBinsqPt; + fill(data.mDCAr_A_Median, mDCAr_A_Median, posIndex); + fill(data.mDCAr_C_Median, mDCAr_C_Median, posIndex); + fill(data.mDCAr_A_RMS, mDCAr_A_RMS, posIndex); + fill(data.mDCAr_C_RMS, mDCAr_C_RMS, posIndex); + fill(data.mDCAz_A_Median, mDCAz_A_Median, posIndex); + fill(data.mDCAz_C_Median, mDCAz_C_Median, posIndex); + fill(data.mDCAz_A_RMS, mDCAz_A_RMS, posIndex); + fill(data.mDCAz_C_RMS, mDCAz_C_RMS, posIndex); + fill(data.mDCAr_C_NTracks, mDCAr_C_NTracks, posIndex); + fill(data.mDCAr_A_NTracks, mDCAr_A_NTracks, posIndex); + fill(data.mDCAz_A_NTracks, mDCAz_A_NTracks, posIndex); + fill(data.mDCAz_C_NTracks, mDCAz_C_NTracks, posIndex); + fill(data.mDCAr_A_WeightedMean, mDCAr_A_WeightedMean, posIndex); + fill(data.mDCAr_C_WeightedMean, mDCAr_C_WeightedMean, posIndex); + fill(data.mDCAz_A_WeightedMean, mDCAz_A_WeightedMean, posIndex); + fill(data.mDCAz_C_WeightedMean, mDCAz_C_WeightedMean, posIndex); + fill(data.mMIPdEdxRatioA, mMIPdEdxRatioA, posIndex); + fill(data.mMIPdEdxRatioC, mMIPdEdxRatioC, posIndex); + fill(data.mTPCChi2A, mTPCChi2A, posIndex); + fill(data.mTPCChi2C, mTPCChi2C, posIndex); + fill(data.mTPCNClA, mTPCNClA, posIndex); + fill(data.mTPCNClC, mTPCNClC, posIndex); + } + + void fill(const std::vector& vecFrom, std::vector& vecTo, const unsigned int posIndex) { std::copy(vecFrom.begin(), vecFrom.end(), vecTo.begin() + posIndex); } + + /// \param nDummyValues number of empty values which are inserted at the beginning of the accumulated integrated currents + void insert(const unsigned int nDummyValues) + { + std::vector vecTmp(nDummyValues, 0); + insert(mDCAr_A_Median, vecTmp); + insert(mDCAr_C_Median, vecTmp); + insert(mDCAr_A_RMS, vecTmp); + insert(mDCAr_C_RMS, vecTmp); + insert(mDCAz_A_Median, vecTmp); + insert(mDCAz_C_Median, vecTmp); + insert(mDCAz_A_RMS, vecTmp); + insert(mDCAz_C_RMS, vecTmp); + insert(mDCAr_C_NTracks, vecTmp); + insert(mDCAr_A_NTracks, vecTmp); + insert(mDCAz_A_NTracks, vecTmp); + insert(mDCAz_C_NTracks, vecTmp); + insert(mDCAr_A_WeightedMean, vecTmp); + insert(mDCAr_C_WeightedMean, vecTmp); + insert(mDCAz_A_WeightedMean, vecTmp); + insert(mDCAz_C_WeightedMean, vecTmp); + insert(mMIPdEdxRatioA, vecTmp); + insert(mMIPdEdxRatioC, vecTmp); + insert(mTPCChi2A, vecTmp); + insert(mTPCChi2C, vecTmp); + insert(mTPCNClA, vecTmp); + insert(mTPCNClC, vecTmp); + } + + void insert(std::vector& vec, const std::vector& vecTmp) { vec.insert(vec.begin(), vecTmp.begin(), vecTmp.end()); } + + /// resize buffer for accumulated currents + void resize(const unsigned int nTotal) + { + mDCAr_A_Median.resize(nTotal); + mDCAr_C_Median.resize(nTotal); + mDCAr_A_RMS.resize(nTotal); + mDCAr_C_RMS.resize(nTotal); + mDCAz_A_Median.resize(nTotal); + mDCAz_C_Median.resize(nTotal); + mDCAz_A_RMS.resize(nTotal); + mDCAz_C_RMS.resize(nTotal); + mDCAr_C_NTracks.resize(nTotal); + mDCAr_A_NTracks.resize(nTotal); + mDCAz_A_NTracks.resize(nTotal); + mDCAz_C_NTracks.resize(nTotal); + mDCAr_A_WeightedMean.resize(nTotal); + mDCAr_C_WeightedMean.resize(nTotal); + mDCAz_A_WeightedMean.resize(nTotal); + mDCAz_C_WeightedMean.resize(nTotal); + mMIPdEdxRatioA.resize(nTotal); + mMIPdEdxRatioC.resize(nTotal); + mTPCChi2A.resize(nTotal); + mTPCChi2C.resize(nTotal); + mTPCNClA.resize(nTotal); + mTPCNClC.resize(nTotal); + } + + ClassDefNV(TimeSeries, 1); +}; + +struct ITSTPC_Matching { + std::vector mITSTPC_A_MatchEff; ///< matching efficiency of ITS-TPC tracks A-side + std::vector mITSTPC_C_MatchEff; ///< matching efficiency of ITS-TPC tracks C-side + std::vector mITSTPC_A_Chi2Match; ///< ITS-TPC chi2 A-side + std::vector mITSTPC_C_Chi2Match; ///< ITS-TPC chi2 C-side + + void dumpToTree(TTree& tree, const char* prefix, const int nHBFPerTF, const TimeSeries& timeSeriesRef) const; + + /// acummulate integrated currents at given index + /// \param posIndex index where data will be copied to + /// \param data integrated currents which will be copied + void fill(const unsigned int posIndex, const ITSTPC_Matching& data) + { + std::copy(data.mITSTPC_A_MatchEff.begin(), data.mITSTPC_A_MatchEff.end(), mITSTPC_A_MatchEff.begin() + posIndex); + std::copy(data.mITSTPC_C_MatchEff.begin(), data.mITSTPC_C_MatchEff.end(), mITSTPC_C_MatchEff.begin() + posIndex); + std::copy(data.mITSTPC_A_Chi2Match.begin(), data.mITSTPC_A_Chi2Match.end(), mITSTPC_A_Chi2Match.begin() + posIndex); + std::copy(data.mITSTPC_C_Chi2Match.begin(), data.mITSTPC_C_Chi2Match.end(), mITSTPC_C_Chi2Match.begin() + posIndex); + } + + /// \param nDummyValues number of empty values which are inserted at the beginning of the accumulated integrated currents + void insert(const unsigned int nDummyValues) + { + std::vector vecTmp(nDummyValues, 0); + mITSTPC_A_MatchEff.insert(mITSTPC_A_MatchEff.begin(), vecTmp.begin(), vecTmp.end()); + mITSTPC_C_MatchEff.insert(mITSTPC_C_MatchEff.begin(), vecTmp.begin(), vecTmp.end()); + mITSTPC_A_Chi2Match.insert(mITSTPC_A_Chi2Match.begin(), vecTmp.begin(), vecTmp.end()); + mITSTPC_C_Chi2Match.insert(mITSTPC_C_Chi2Match.begin(), vecTmp.begin(), vecTmp.end()); + } + + /// resize buffer for accumulated currents + void resize(const unsigned int nTotal) + { + mITSTPC_A_MatchEff.resize(nTotal); + mITSTPC_C_MatchEff.resize(nTotal); + mITSTPC_A_Chi2Match.resize(nTotal); + mITSTPC_C_Chi2Match.resize(nTotal); + } + + ClassDefNV(ITSTPC_Matching, 1); +}; + +struct TimeSeriesITSTPC { + TimeSeries mTSTPC; ///< TPC standalone DCAs + TimeSeries mTSITSTPC; ///< ITS-TPC standalone DCAs + ITSTPC_Matching mITSTPCAll; ///< ITS-TPC matching efficiency for ITS standalone + afterburner + ITSTPC_Matching mITSTPCStandalone; ///< ITS-TPC matching efficiency for ITS standalone + ITSTPC_Matching mITSTPCAfterburner; ///< ITS-TPC matchin efficiency fir ITS afterburner + + // dump this object to a tree + void dumpToTree(const char* outFileName, const int nHBFPerTF = 32); + + void setStartTime(long timeMS) + { + mTSTPC.setStartTime(timeMS); + mTSITSTPC.setStartTime(timeMS); + } + + void setBinning(const int nBinsPhi, const int nBinsTgl, const int qPtBins) + { + mTSTPC.mNBinsPhi = nBinsPhi; + mTSTPC.mNBinsTgl = nBinsTgl; + mTSTPC.mNBinsqPt = qPtBins; + mTSITSTPC.mNBinsPhi = nBinsPhi; + mTSITSTPC.mNBinsTgl = nBinsTgl; + mTSITSTPC.mNBinsqPt = qPtBins; + } + + bool areSameSize() const { return (mTSTPC.areSameSize() && mTSITSTPC.areSameSize()); } ///< check if stored currents have same number of entries + bool isEmpty() const { return mTSTPC.isEmpty(); } ///< check if values are empty + size_t getEntries() const { return mTSTPC.getEntries(); } ///< \return returns number of values stored + + /// acummulate integrated currents at given index + /// \param posIndex index where data will be copied to + /// \param data integrated currents which will be copied + void fill(const unsigned int posIndex, const TimeSeriesITSTPC& data) + { + mTSTPC.fill(posIndex, data.mTSTPC); + mTSITSTPC.fill(posIndex, data.mTSITSTPC); + mITSTPCAll.fill(posIndex, data.mITSTPCAll); + mITSTPCStandalone.fill(posIndex, data.mITSTPCStandalone); + mITSTPCAfterburner.fill(posIndex, data.mITSTPCAfterburner); + } + + /// \param nDummyValues number of empty values which are inserted at the beginning of the accumulated integrated currents + void insert(const unsigned int nDummyValues) + { + mTSTPC.insert(nDummyValues); + mTSITSTPC.insert(nDummyValues); + mITSTPCAll.insert(nDummyValues); + mITSTPCStandalone.insert(nDummyValues); + mITSTPCAfterburner.insert(nDummyValues); + } + + /// resize buffer for accumulated currents + void resize(const unsigned int nTotal) + { + mTSTPC.resize(nTotal); + mTSITSTPC.resize(nTotal); + mITSTPCAll.resize(nTotal); + mITSTPCStandalone.resize(nTotal); + mITSTPCAfterburner.resize(nTotal); + } + + ClassDefNV(TimeSeriesITSTPC, 1); }; } // end namespace tpc @@ -177,9 +437,11 @@ struct IFT0C { std::vector mINChanC; ///< integrated 1D FIT currents for NChan C std::vector mIAmplA; ///< integrated 1D FIT currents for Ampl A std::vector mIAmplC; ///< integrated 1D FIT currents for Ampl C + long mTimeMS{}; ///< start time in ms bool areSameSize() const { return sameSize(mINChanA, mINChanC, mIAmplA, mIAmplC); } ///< check if stored currents have same number of entries bool isEmpty() const { return mINChanA.empty(); } ///< check if values are empty size_t getEntries() const { return mINChanA.size(); } ///< \return returns number of values stored + void setStartTime(long timeMS) { mTimeMS = timeMS; } /// acummulate integrated currents at given index /// \param posIndex index where data will be copied to @@ -229,16 +491,18 @@ struct IFT0C { std::transform(mIAmplC.begin(), mIAmplC.end(), mIAmplC.begin(), [factor](const float val) { return val * factor; }); } - ClassDefNV(IFT0C, 1); + ClassDefNV(IFT0C, 2); }; /// struct containing the integrated FV0 currents struct IFV0C { std::vector mINChanA; ///< integrated 1D FIT currents for NChan A std::vector mIAmplA; ///< integrated 1D FIT currents for Ampl A + long mTimeMS{}; ///< start time in ms bool areSameSize() const { return sameSize(mINChanA, mIAmplA); } ///< check if stored currents have same number of entries bool isEmpty() const { return mINChanA.empty(); } ///< check if values are empty size_t getEntries() const { return mINChanA.size(); } ///< \return returns number of values stored + void setStartTime(long timeMS) { mTimeMS = timeMS; } /// acummulate integrated currents at given index /// \param posIndex index where data will be copied to @@ -278,7 +542,7 @@ struct IFV0C { std::transform(mIAmplA.begin(), mIAmplA.end(), mIAmplA.begin(), [factor](const float val) { return val * factor; }); } - ClassDefNV(IFV0C, 1); + ClassDefNV(IFV0C, 2); }; /// struct containing the integrated FDD currents @@ -287,9 +551,11 @@ struct IFDDC { std::vector mINChanC; ///< integrated 1D FIT currents for NChan C std::vector mIAmplA; ///< integrated 1D FIT currents for Ampl A std::vector mIAmplC; ///< integrated 1D FIT currents for Ampl C + long mTimeMS{}; ///< start time in ms bool areSameSize() const { return sameSize(mINChanA, mINChanC, mIAmplA, mIAmplC); } ///< check if stored currents have same number of entries bool isEmpty() const { return mINChanA.empty(); } ///< check if values are empty size_t getEntries() const { return mINChanA.size(); } ///< \return returns number of values stored + void setStartTime(long timeMS) { mTimeMS = timeMS; } /// acummulate integrated currents at given index /// \param posIndex index where data will be copied to @@ -339,7 +605,7 @@ struct IFDDC { std::transform(mIAmplC.begin(), mIAmplC.end(), mIAmplC.begin(), [factor](const float val) { return val * factor; }); } - ClassDefNV(IFDDC, 1); + ClassDefNV(IFDDC, 2); }; } // end namespace fit @@ -395,6 +661,9 @@ class IntegratedClusters /// \param outFileName name of the output file void dumpToTree(const char* outFileName = "ICTree.root"); + /// setting the start time + void setStartTime(long timeMS) { mCurrents.setStartTime(timeMS); } + private: DataT mCurrents; ///< buffer for integrated currents o2::calibration::TFType mTFFirst{}; ///< first TF of currents diff --git a/Detectors/Calibration/src/DetectorsCalibrationLinkDef.h b/Detectors/Calibration/src/DetectorsCalibrationLinkDef.h index f096891c2f8d7..8a9f6284d606c 100644 --- a/Detectors/Calibration/src/DetectorsCalibrationLinkDef.h +++ b/Detectors/Calibration/src/DetectorsCalibrationLinkDef.h @@ -53,4 +53,12 @@ #pragma link C++ class o2::calibration::TimeSlot < o2::calibration::IntegratedClusters < o2::fit::IFDDC>> + ; #pragma link C++ class o2::calibration::TimeSlotCalibration < o2::calibration::IntegratedClusters < o2::fit::IFDDC>> + ; +#pragma link C++ struct o2::tpc::TimeSeries + ; +#pragma link C++ struct o2::tpc::ITSTPC_Matching + ; +#pragma link C++ struct o2::tpc::TimeSeriesITSTPC + ; +#pragma link C++ class o2::calibration::IntegratedClusters < o2::tpc::TimeSeriesITSTPC> + ; +#pragma link C++ class o2::calibration::IntegratedClusterCalibrator < o2::tpc::TimeSeriesITSTPC> + ; +#pragma link C++ class o2::calibration::TimeSlot < o2::calibration::IntegratedClusters < o2::tpc::TimeSeriesITSTPC>> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::calibration::IntegratedClusters < o2::tpc::TimeSeriesITSTPC>> + ; + #endif diff --git a/Detectors/Calibration/src/IntegratedClusterCalibrator.cxx b/Detectors/Calibration/src/IntegratedClusterCalibrator.cxx index 66934ffd06115..b5f07c7304895 100644 --- a/Detectors/Calibration/src/IntegratedClusterCalibrator.cxx +++ b/Detectors/Calibration/src/IntegratedClusterCalibrator.cxx @@ -165,6 +165,7 @@ void IntegratedClusterCalibrator::finalizeSlot(o2::calibration::TimeSlot< LOGP(info, "Finalizing slot {} <= TF <= {}", startTF, endTF); auto& integratedClusters = *slot.getContainer(); + integratedClusters.setStartTime(slot.getStartTimeMS()); if (mDebug) { integratedClusters.dumpToFile(fmt::format("IntegratedClusters_TF_{}_{}_TS_{}_{}.root", startTF, endTF, slot.getStartTimeMS(), slot.getEndTimeMS()).data()); } @@ -196,8 +197,224 @@ template class IntegratedClusterCalibrator; template class IntegratedClusters; template class IntegratedClusterCalibrator; +template class IntegratedClusters; +template class IntegratedClusterCalibrator; + template class IntegratedClusters; template class IntegratedClusterCalibrator; } // end namespace calibration + +void tpc::TimeSeriesITSTPC::dumpToTree(const char* outFileName, const int nHBFPerTF) +{ + TFile f(outFileName, "RECREATE"); + TTree tree("timeSeries", "timeSeries"); + mTSTPC.dumpToTree(tree, "TPC_", nHBFPerTF); + mTSITSTPC.dumpToTree(tree, "ITSTPC_", nHBFPerTF); + mITSTPCAll.dumpToTree(tree, "ITSTPC_", nHBFPerTF, mTSTPC); + mITSTPCStandalone.dumpToTree(tree, "ITS_SA_", nHBFPerTF, mTSTPC); + mITSTPCAfterburner.dumpToTree(tree, "ITS_AB_", nHBFPerTF, mTSTPC); + f.WriteObject(&tree, "timeSeries"); +} + +void tpc::ITSTPC_Matching::dumpToTree(TTree& tree, const char* prefix, const int nHBFPerTF, const TimeSeries& timeSeriesRef) const +{ + // adding matching efficiency + const auto nValues = timeSeriesRef.mDCAr_A_Median.size(); + const int nPointsPerTF = timeSeriesRef.getNBins(); + const int nTotPoints = nValues / nPointsPerTF; + + const int nBinTypes = 4; + for (int type = 0; type < nBinTypes; ++type) { + std::array nBinsAllTypes{timeSeriesRef.mNBinsPhi, timeSeriesRef.mNBinsTgl, timeSeriesRef.mNBinsqPt, 1}; + std::array nBinsAllTypesNames{"phi", "tgl", "qPt", "int"}; + int nBins = nBinsAllTypes[type]; + + std::vector> matching_eff_A(nBins); + std::vector> matching_eff_C(nBins); + std::vector> chi2Match_A(nBins); + std::vector> chi2Match_C(nBins); + + std::vector listBranches; + listBranches.reserve(4 * nBins); + for (int i = 0; i < nBins; ++i) { + const std::string brSuf = (type == nBinTypes - 1) ? nBinsAllTypesNames[type] : fmt::format("{}_{}", nBinsAllTypesNames[type], i); + listBranches.emplace_back(tree.Branch(fmt::format("{}mITSTPC_A_MatchEff_{}", prefix, brSuf).data(), &matching_eff_A[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mITSTPC_C_MatchEff_{}", prefix, brSuf).data(), &matching_eff_C[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mITSTPC_A_Chi2Match_{}", prefix, brSuf).data(), &chi2Match_A[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mITSTPC_C_Chi2Match_{}", prefix, brSuf).data(), &chi2Match_C[i])); + } + + // alloc memory + for (int i = 0; i < nBins; ++i) { + matching_eff_A[i].resize(nTotPoints); + matching_eff_C[i].resize(nTotPoints); + chi2Match_A[i].resize(nTotPoints); + chi2Match_C[i].resize(nTotPoints); + } + + for (int j = 0; j < nTotPoints; ++j) { + for (int i = 0; i < nBins; ++i) { + int idx = timeSeriesRef.getIndexPhi(i, j); // phi bins + if (type == 1) { + idx = timeSeriesRef.getIndexTgl(i, j); // tgl bins + } else if (type == 2) { + idx = timeSeriesRef.getIndexqPt(i, j); // qPt + } else if (type == 3) { + idx = timeSeriesRef.getIndexInt(j); + } + matching_eff_A[i][j] = mITSTPC_A_MatchEff[idx]; + matching_eff_C[i][j] = mITSTPC_C_MatchEff[idx]; + chi2Match_A[i][j] = mITSTPC_A_Chi2Match[idx]; + chi2Match_C[i][j] = mITSTPC_C_Chi2Match[idx]; + } + } + // fill branches + for (auto br : listBranches) { + br->Fill(); + } + } + tree.SetEntries(1); +} + +void tpc::TimeSeries::dumpToTree(TTree& tree, const char* prefix, const int nHBFPerTF) const +{ + const auto nValues = mDCAr_A_Median.size(); + const int nPointsPerTF = getNBins(); + const int nTotPoints = nValues / nPointsPerTF; + + const int nBinTypes = 4; + for (int type = 0; type < nBinTypes; ++type) { + std::array nBinsAllTypes{mNBinsPhi, mNBinsTgl, mNBinsqPt, 1}; + std::array nBinsAllTypesNames{"phi", "tgl", "qPt", "int"}; + int nBins = nBinsAllTypes[type]; + + std::vector> dcar_A_Median(nBins); + std::vector> dcar_C_Median(nBins); + std::vector> dcar_A_WeightedMean(nBins); + std::vector> dcar_C_WeightedMean(nBins); + std::vector> dcar_A_RMS(nBins); + std::vector> dcar_C_RMS(nBins); + std::vector> dcaz_A_Median(nBins); + std::vector> dcaz_C_Median(nBins); + std::vector> dcaz_A_WeightedMean(nBins); + std::vector> dcaz_C_WeightedMean(nBins); + std::vector> dcaz_A_RMS(nBins); + std::vector> dcaz_C_RMS(nBins); + std::vector> nTracksDCAr_A(nBins); + std::vector> nTracksDCAr_C(nBins); + std::vector> nTracksDCAz_A(nBins); + std::vector> nTracksDCAz_C(nBins); + std::vector> mipdEdxRatioA(nBins); + std::vector> mipdEdxRatioC(nBins); + std::vector> tpcChi2A(nBins); + std::vector> tpcChi2C(nBins); + std::vector> tpcNClA(nBins); + std::vector> tpcNClC(nBins); + + std::vector listBranches; + listBranches.reserve(22 * nBins); + for (int i = 0; i < nBins; ++i) { + const std::string brSuf = (type == nBinTypes - 1) ? nBinsAllTypesNames[type] : fmt::format("{}_{}", nBinsAllTypesNames[type], i); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAr_A_Median_{}", prefix, brSuf).data(), &dcar_A_Median[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAr_C_Median_{}", prefix, brSuf).data(), &dcar_C_Median[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAr_A_WeightedMean_{}", prefix, brSuf).data(), &dcar_A_WeightedMean[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAr_C_WeightedMean_{}", prefix, brSuf).data(), &dcar_C_WeightedMean[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAr_A_RMS_{}", prefix, brSuf).data(), &dcar_A_RMS[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAr_C_RMS_{}", prefix, brSuf).data(), &dcar_C_RMS[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAz_A_Median_{}", prefix, brSuf).data(), &dcaz_A_Median[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAz_C_Median_{}", prefix, brSuf).data(), &dcaz_C_Median[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAz_A_WeightedMean_{}", prefix, brSuf).data(), &dcaz_A_WeightedMean[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAz_C_WeightedMean_{}", prefix, brSuf).data(), &dcaz_C_WeightedMean[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAz_A_RMS_{}", prefix, brSuf).data(), &dcaz_A_RMS[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAz_C_RMS_{}", prefix, brSuf).data(), &dcaz_C_RMS[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAr_A_NTracks_{}", prefix, brSuf).data(), &nTracksDCAr_A[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAr_C_NTracks_{}", prefix, brSuf).data(), &nTracksDCAr_C[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAz_A_NTracks_{}", prefix, brSuf).data(), &nTracksDCAz_A[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mDCAz_C_NTracks_{}", prefix, brSuf).data(), &nTracksDCAz_C[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mMIPdEdxRatioA_{}", prefix, brSuf).data(), &mipdEdxRatioA[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mMIPdEdxRatioC_{}", prefix, brSuf).data(), &mipdEdxRatioC[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mTPCChi2A_{}", prefix, brSuf).data(), &tpcChi2A[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mTPCChi2C_{}", prefix, brSuf).data(), &tpcChi2C[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mTPCNClA_{}", prefix, brSuf).data(), &tpcNClA[i])); + listBranches.emplace_back(tree.Branch(fmt::format("{}mTPCNClC_{}", prefix, brSuf).data(), &tpcNClC[i])); + } + + // alloc memory + for (int i = 0; i < nBins; ++i) { + dcar_A_Median[i].resize(nTotPoints); + dcar_C_Median[i].resize(nTotPoints); + dcar_A_WeightedMean[i].resize(nTotPoints); + dcar_C_WeightedMean[i].resize(nTotPoints); + dcar_A_RMS[i].resize(nTotPoints); + dcar_C_RMS[i].resize(nTotPoints); + dcaz_A_Median[i].resize(nTotPoints); + dcaz_C_Median[i].resize(nTotPoints); + dcaz_A_WeightedMean[i].resize(nTotPoints); + dcaz_C_WeightedMean[i].resize(nTotPoints); + dcaz_A_RMS[i].resize(nTotPoints); + dcaz_C_RMS[i].resize(nTotPoints); + nTracksDCAr_A[i].resize(nTotPoints); + nTracksDCAr_C[i].resize(nTotPoints); + nTracksDCAz_A[i].resize(nTotPoints); + nTracksDCAz_C[i].resize(nTotPoints); + mipdEdxRatioA[i].resize(nTotPoints); + mipdEdxRatioC[i].resize(nTotPoints); + tpcChi2A[i].resize(nTotPoints); + tpcChi2C[i].resize(nTotPoints); + tpcNClA[i].resize(nTotPoints); + tpcNClC[i].resize(nTotPoints); + } + + std::vector time(nTotPoints); + if (type == 0) { + listBranches.emplace_back(tree.Branch("time", &time)); + } + + for (int j = 0; j < nTotPoints; ++j) { + for (int i = 0; i < nBins; ++i) { + int idx = getIndexPhi(i, j); + if (type == 1) { + idx = getIndexTgl(i, j); + } else if (type == 2) { + idx = getIndexqPt(i, j); + } else if (type == 3) { + idx = getIndexInt(j); + } + dcar_A_Median[i][j] = mDCAr_A_Median[idx]; + dcar_C_Median[i][j] = mDCAr_C_Median[idx]; + dcar_A_WeightedMean[i][j] = mDCAr_A_WeightedMean[idx]; + dcar_C_WeightedMean[i][j] = mDCAr_C_WeightedMean[idx]; + dcar_A_RMS[i][j] = mDCAr_A_RMS[idx]; + dcar_C_RMS[i][j] = mDCAr_C_RMS[idx]; + dcaz_A_Median[i][j] = mDCAz_A_Median[idx]; + dcaz_C_Median[i][j] = mDCAz_C_Median[idx]; + dcaz_A_WeightedMean[i][j] = mDCAz_A_WeightedMean[idx]; + dcaz_C_WeightedMean[i][j] = mDCAz_C_WeightedMean[idx]; + dcaz_A_RMS[i][j] = mDCAz_A_RMS[idx]; + dcaz_C_RMS[i][j] = mDCAz_C_RMS[idx]; + nTracksDCAr_A[i][j] = mDCAr_A_NTracks[idx]; + nTracksDCAr_C[i][j] = mDCAr_C_NTracks[idx]; + nTracksDCAz_A[i][j] = mDCAz_A_NTracks[idx]; + nTracksDCAz_C[i][j] = mDCAz_C_NTracks[idx]; + mipdEdxRatioA[i][j] = mMIPdEdxRatioA[idx]; + mipdEdxRatioC[i][j] = mMIPdEdxRatioC[idx]; + tpcChi2A[i][j] = mTPCChi2A[idx]; + tpcChi2C[i][j] = mTPCChi2C[idx]; + tpcNClA[i][j] = mTPCNClA[idx]; + tpcNClC[i][j] = mTPCNClC[idx]; + } + // add time only once + if (type == 0) { + time[j] = mTimeMS + j * nHBFPerTF * o2::constants::lhc::LHCOrbitMUS / 1000; + } + } + // fill branches + for (auto br : listBranches) { + br->Fill(); + } + } + tree.SetEntries(1); +} + } // end namespace o2 diff --git a/Detectors/TPC/base/include/TPCBase/CDBInterface.h b/Detectors/TPC/base/include/TPCBase/CDBInterface.h index d601f66db9d99..73ef44f8a510c 100644 --- a/Detectors/TPC/base/include/TPCBase/CDBInterface.h +++ b/Detectors/TPC/base/include/TPCBase/CDBInterface.h @@ -86,6 +86,8 @@ enum class CDBType { CalCorrMapRef, ///< Cluster correction reference map (static distortions) /// CalCorrDerivMap, ///< Cluster correction map (derivative map) + /// + CalTimeSeries, ///< integrated DCAs for longer time interval }; /// Upload intervention type @@ -145,6 +147,8 @@ const std::unordered_map CDBTypeMap{ {CDBType::CalCorrMapRef, "TPC/Calib/CorrectionMapRefV2"}, // derivative map correction {CDBType::CalCorrDerivMap, "TPC/Calib/CorrectionMapDerivativeV2"}, + // time series + {CDBType::CalTimeSeries, "TPC/Calib/TimeSeries"}, }; /// Poor enum reflection ... diff --git a/Detectors/TPC/calibration/include/TPCCalibration/RobustAverage.h b/Detectors/TPC/calibration/include/TPCCalibration/RobustAverage.h index 9b942b35a33dd..debf449189f15 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/RobustAverage.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/RobustAverage.h @@ -57,23 +57,23 @@ class RobustAverage /// reserve memory for member /// \param maxValues maximum number of values which will be averaged. Copy of values will be done. - void reserve(const unsigned int maxValues) { mValues.reserve(maxValues); } + void reserve(const unsigned int maxValues); /// clear the stored values void clear(); /// \param value value which will be added to the list of stored values for averaging /// \param weight weight of the value - void addValue(const float value, const float weight); - - /// \param value value which will be added to the list of stored values for averaging - void addValue(const float value); + void addValue(const float value, const float weight = 1); /// returns the filtered average value /// \param sigma maximum accepted standard deviation: sigma*stdev ///\param interQuartileRange number of points in inner quartile to consider std::pair getFilteredAverage(const float sigma = 3, const float interQuartileRange = 0.9); + /// remove all the point which are abs(val - val_median)>maxAbsMedian + std::tuple filterPointsMedian(const float maxAbsMedian, const float sigma = 5); + /// \return returns mean of stored values float getMean() const { return mValues.empty() ? 0 : getMean(mValues.begin(), mValues.end()); } @@ -89,9 +89,15 @@ class RobustAverage /// \return returns stored values const auto& getValues() { return mValues; } + /// \return returns stored values + const auto& getWeigths() { return mWeights; } + /// values which will be averaged and filtered void print() const; + // sorting values and weights + void sort(); + private: std::vector mValues{}; ///< values which will be averaged and filtered std::vector mWeights{}; ///< weights of each value diff --git a/Detectors/TPC/calibration/src/RobustAverage.cxx b/Detectors/TPC/calibration/src/RobustAverage.cxx index 1bbe65856e10c..3b223c2ef0cbc 100644 --- a/Detectors/TPC/calibration/src/RobustAverage.cxx +++ b/Detectors/TPC/calibration/src/RobustAverage.cxx @@ -13,6 +13,12 @@ #include "Framework/Logger.h" #include +void o2::tpc::RobustAverage::reserve(const unsigned int maxValues) +{ + mValues.reserve(maxValues); + mWeights.reserve(maxValues); +} + std::pair o2::tpc::RobustAverage::getFilteredAverage(const float sigma, const float interQuartileRange) { if (mValues.empty()) { @@ -28,7 +34,7 @@ std::pair o2::tpc::RobustAverage::getFilteredAverage(const float s */ // 1. Sort the values - std::sort(mValues.begin(), mValues.end()); + sort(); // 2. Use only the values in the Interquartile Range (inner n%) const auto upper = mValues.begin() + mValues.size() * interQuartileRange; @@ -48,6 +54,81 @@ std::pair o2::tpc::RobustAverage::getFilteredAverage(const float s return std::pair(getFilteredMean(median, stdev, sigma), stdev); } +std::tuple o2::tpc::RobustAverage::filterPointsMedian(const float maxAbsMedian, const float sigma) +{ + if (mValues.empty()) { + return {0, 0, 0, 0}; + } + + // 1. Sort the values + sort(); + + // 2. median + const float median = mValues[mValues.size() / 2]; + + // 3. select points larger and smaller than specified max value + const auto upperV0 = std::upper_bound(mValues.begin(), mValues.end(), median + maxAbsMedian); + const auto lowerV0 = std::lower_bound(mValues.begin(), mValues.end(), median - maxAbsMedian); + + if (upperV0 == lowerV0) { + return {0, 0, 0, 0}; + } + + // 4. get RMS of selected values + const float stdev = getStdDev(median, lowerV0, upperV0); + + // 5. define RMS cut + const float sigmastddev = sigma * stdev; + const float minVal = median - sigmastddev; + const float maxVal = median + sigmastddev; + const auto upper = std::upper_bound(mValues.begin(), mValues.end(), maxVal); + const auto lower = std::lower_bound(mValues.begin(), mValues.end(), minVal); + + if (upper == lower) { + return {0, 0, 0, 0}; + } + + const int indexUp = upper - mValues.begin(); + const int indexLow = lower - mValues.begin(); + + // 7. get filtered median + const float medianFilterd = mValues[(indexUp - indexLow) / 2 + indexLow]; + + // 8. weighted mean + const auto upperW = mWeights.begin() + indexUp; + const auto lowerW = mWeights.begin() + indexLow; + const float wMean = getWeightedMean(lower, upper, lowerW, upperW); + + // 9. number of points passing the cuts + const int nEntries = indexUp - indexLow; + + return {medianFilterd, wMean, stdev, nEntries}; +} + +void o2::tpc::RobustAverage::sort() +{ + const size_t nVals = mValues.size(); + if (mValues.size() != mWeights.size()) { + LOGP(warning, "values and errors haave different size"); + return; + } + std::vector tmpIdx(nVals); + std::iota(tmpIdx.begin(), tmpIdx.end(), 0); + std::sort(tmpIdx.begin(), tmpIdx.end(), [&](std::size_t i, std::size_t j) { return (mValues[i] < mValues[j]); }); + + std::vector mValues_tmp; + std::vector mWeights_tmp; + mValues_tmp.reserve(nVals); + mWeights_tmp.reserve(nVals); + for (int i = 0; i < nVals; ++i) { + const int idx = tmpIdx[i]; + mValues_tmp.emplace_back(mValues[idx]); + mWeights_tmp.emplace_back(mWeights[idx]); + } + mValues.swap(mValues_tmp); + mWeights.swap(mWeights_tmp); +} + float o2::tpc::RobustAverage::getStdDev(const float mean, std::vector::const_iterator begin, std::vector::const_iterator end) { const auto size = std::distance(begin, end); @@ -110,8 +191,3 @@ void o2::tpc::RobustAverage::addValue(const float value, const float weight) mValues.emplace_back(value); mWeights.emplace_back(weight); } - -void o2::tpc::RobustAverage::addValue(const float value) -{ - mValues.emplace_back(value); -} diff --git a/Detectors/TPC/workflow/CMakeLists.txt b/Detectors/TPC/workflow/CMakeLists.txt index 1834649fb2bf6..a12ccc83b1cc2 100644 --- a/Detectors/TPC/workflow/CMakeLists.txt +++ b/Detectors/TPC/workflow/CMakeLists.txt @@ -41,6 +41,10 @@ o2_add_library(TPCWorkflow src/TPCIntegrateClusterWriterSpec.cxx src/TPCTriggerWriterSpec.cxx src/TPCMergeIntegrateClusterSpec.cxx + src/TPCTimeSeriesSpec.cxx + src/TPCTimeSeriesWriterSpec.cxx + src/TPCTimeSeriesReaderSpec.cxx + src/TPCMergeTimeSeriesSpec.cxx TARGETVARNAME targetName PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsTPC O2::DPLUtils O2::TPCReconstruction @@ -227,6 +231,21 @@ o2_add_executable(merge-integrate-cluster-workflow COMPONENT_NAME tpc PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) +o2_add_executable(time-series-workflow + COMPONENT_NAME tpc + SOURCES src/tpc-time-series.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(time-series-reader-workflow + SOURCES src/time-series-reader.cxx + COMPONENT_NAME tpc + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + +o2_add_executable(merge-time-series-workflow + SOURCES src/time-series-merge-integrator.cxx + COMPONENT_NAME tpc + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + o2_add_test(workflow COMPONENT_NAME tpc LABELS tpc workflow diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCMergeTimeSeriesSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCMergeTimeSeriesSpec.h new file mode 100644 index 0000000000000..1a3b1a3554ddb --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCMergeTimeSeriesSpec.h @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_TPCMERGETIMESERIESSPEC_SPEC +#define O2_TPC_TPCMERGETIMESERIESSPEC_SPEC + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace tpc +{ + +o2::framework::DataProcessorSpec getTPCMergeTimeSeriesSpec(); + +} // end namespace tpc +} // end namespace o2 + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCTimeSeriesReaderSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCTimeSeriesReaderSpec.h new file mode 100644 index 0000000000000..f3ac7aa18fdfb --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCTimeSeriesReaderSpec.h @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_TPCTIMESERIESREADERSPEC_SPEC +#define O2_TPC_TPCTIMESERIESREADERSPEC_SPEC + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace tpc +{ + +o2::framework::DataProcessorSpec getTPCTimeSeriesReaderSpec(); + +} // end namespace tpc +} // end namespace o2 + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCTimeSeriesSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCTimeSeriesSpec.h new file mode 100644 index 0000000000000..c2c21c7f40649 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCTimeSeriesSpec.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_TPCTIMESERIESSPEC_SPEC +#define O2_TPC_TPCTIMESERIESSPEC_SPEC + +#include "Framework/DataProcessorSpec.h" +#include "DetectorsBase/Propagator.h" + +namespace o2 +{ +namespace tpc +{ +static constexpr header::DataDescription getDataDescriptionTimeSeries() { return header::DataDescription{"TIMESERIES"}; } +static constexpr header::DataDescription getDataDescriptionTPCTimeSeriesTFId() { return header::DataDescription{"ITPCTSTFID"}; } + +o2::framework::DataProcessorSpec getTPCTimeSeriesSpec(const bool disableWriter, const o2::base::Propagator::MatCorrType matType); + +} // end namespace tpc +} // end namespace o2 + +#endif diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCTimeSeriesWriterSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCTimeSeriesWriterSpec.h new file mode 100644 index 0000000000000..ab56884b7a6e6 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCTimeSeriesWriterSpec.h @@ -0,0 +1,27 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_TPCTIMESERIESWRITERSPEC_SPEC +#define O2_TPC_TPCTIMESERIESWRITERSPEC_SPEC + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace tpc +{ + +o2::framework::DataProcessorSpec getTPCTimeSeriesWriterSpec(); + +} // end namespace tpc +} // end namespace o2 + +#endif diff --git a/Detectors/TPC/workflow/src/TPCMergeTimeSeriesSpec.cxx b/Detectors/TPC/workflow/src/TPCMergeTimeSeriesSpec.cxx new file mode 100644 index 0000000000000..9a3ef972cb175 --- /dev/null +++ b/Detectors/TPC/workflow/src/TPCMergeTimeSeriesSpec.cxx @@ -0,0 +1,190 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCMergeTimeSeriesSpec.cxx +/// \brief device for merging the tpc time series in contiguous time intervals +/// \author Matthias Kleiner +/// \date Aug 20, 2023 + +#include "TPCWorkflow/TPCMergeTimeSeriesSpec.h" +#include "DetectorsCalibration/IntegratedClusterCalibrator.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsCalibration/Utils.h" +#include "DetectorsCommonDataFormats/FileMetaData.h" +#include "Framework/DataTakingContext.h" +#include "TPCBase/CDBInterface.h" +#include "TPCWorkflow/TPCTimeSeriesSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tpc +{ + +class TPCMergeTimeSeries : public Task +{ + public: + /// \constructor + TPCMergeTimeSeries(std::shared_ptr req) : mCCDBRequest(req){}; + + void init(framework::InitContext& ic) final + { + o2::base::GRPGeomHelper::instance().setRequest(mCCDBRequest); + mCalibrator = std::make_unique>(); + const auto slotLength = ic.options().get("tf-per-slot"); + const auto maxDelay = ic.options().get("max-delay"); + const auto debug = ic.options().get("debug"); + mCalibrator->setSlotLength(slotLength); + mCalibrator->setMaxSlotsDelay(maxDelay); + mCalibrator->setDebug(debug); + + mCalibFileDir = ic.options().get("output-dir"); + if (mCalibFileDir != "/dev/null") { + mCalibFileDir = o2::utils::Str::rectifyDirectory(mCalibFileDir); + } + mMetaFileDir = ic.options().get("meta-output-dir"); + if (mMetaFileDir != "/dev/null") { + mMetaFileDir = o2::utils::Str::rectifyDirectory(mMetaFileDir); + } + mDumpCalibData = ic.options().get("dump-calib-data"); + } + + void run(ProcessingContext& pc) final + { + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mCalibrator->getCurrentTFInfo()); + + // set data taking context only once + if (mSetDataTakingCont) { + mDataTakingContext = pc.services().get(); + mSetDataTakingCont = false; + } + + // check slots to finalize at the beginning to avoid creation of a second slot and thus allocating new memory + mCalibrator->checkSlotsToFinalize(mCalibrator->getCurrentTFInfo().tfCounter, mCalibrator->getMaxSlotsDelay() * mCalibrator->getSlotLength()); + + LOGP(debug, "Created {} objects for {} slots with current TF {} and time stamp {}", mCalibrator->getTFinterval().size(), mCalibrator->getNSlots(), mCalibrator->getCurrentTFInfo().tfCounter, mCalibrator->getCurrentTFInfo().creation); + if (mCalibrator->hasCalibrationData()) { + sendOutput(pc.outputs()); + } + + const auto currents = pc.inputs().get(pc.inputs().get("timeseries")); + + // accumulate the currents + mCalibrator->process(mCalibrator->getCurrentTFInfo().tfCounter, *currents); + } + + void endOfStream(EndOfStreamContext& eos) final + { + LOGP(info, "Finalizing calibration. Dumping all objects"); + // just write everything out + for (int i = 0; i < mCalibrator->getNSlots(); ++i) { + mCalibrator->finalizeSlot(mCalibrator->getSlot(i)); + } + sendOutput(eos.outputs()); + } + + void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final { o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj); } + + static constexpr header::DataDescription getDataDescriptionCCDB() { return header::DataDescription{"TimeSeriesITSTPC"}; } + + private: + std::unique_ptr> mCalibrator; ///< calibrator object for creating the pad-by-pad gain map + std::shared_ptr mCCDBRequest; ///< info for CCDB request + std::string mMetaFileDir{}; ///< output dir for meta data + std::string mCalibFileDir{}; ///< output dir for calib objects + o2::framework::DataTakingContext mDataTakingContext{}; ///< run information for meta data + bool mSetDataTakingCont{true}; ///< flag for setting data taking context only once + bool mDumpCalibData{false}; ///< dump the calibration data as a calibration file + + void sendOutput(DataAllocator& output) + { + auto calibrations = std::move(*mCalibrator).getCalibs(); + const auto& intervals = mCalibrator->getTimeIntervals(); + assert(calibrations.size() == intervals.size()); + for (unsigned int i = 0; i < calibrations.size(); i++) { + auto& object = calibrations[i]; + o2::ccdb::CcdbObjectInfo info(CDBTypeMap.at(CDBType::CalTimeSeries), std::string{}, std::string{}, std::map{}, intervals[i].first, intervals[i].second); + + auto image = o2::ccdb::CcdbApi::createObjectImage(&object, &info); + LOGP(info, "Sending object {} / {} of size {} bytes, valid for {} : {} ", info.getPath(), info.getFileName(), image->size(), info.getStartValidityTimestamp(), info.getEndValidityTimestamp()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, getDataDescriptionCCDB(), i}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, getDataDescriptionCCDB(), i}, info); + + if (mDumpCalibData && mCalibFileDir != "/dev/null") { + std::string calibFName = fmt::format("tpc_timeseries_cal_data_{}_{}.root", info.getStartValidityTimestamp(), info.getEndValidityTimestamp()); + try { + std::ofstream calFile(fmt::format("{}{}", mCalibFileDir, calibFName), std::ios::out | std::ios::binary); + calFile.write(image->data(), image->size()); + calFile.close(); + } catch (std::exception const& e) { + LOG(error) << "Failed to store TimeSeriesITSTPC calibration data file " << calibFName << ", reason: " << e.what(); + } + + if (mMetaFileDir != "/dev/null") { + o2::dataformats::FileMetaData calMetaData; + calMetaData.fillFileData(calibFName); + calMetaData.setDataTakingContext(mDataTakingContext); + calMetaData.type = "calib"; + calMetaData.priority = "low"; + auto metaFileNameTmp = fmt::format("{}{}.tmp", mMetaFileDir, calibFName); + auto metaFileName = fmt::format("{}{}.done", mMetaFileDir, calibFName); + try { + std::ofstream metaFileOut(metaFileNameTmp); + metaFileOut << calMetaData; + metaFileOut.close(); + std::filesystem::rename(metaFileNameTmp, metaFileName); + } catch (std::exception const& e) { + LOG(error) << "Failed to store CTF meta data file " << metaFileName << ", reason: " << e.what(); + } + } + } + } + mCalibrator->initOutput(); // empty the outputs after they are send + } +}; + +o2::framework::DataProcessorSpec getTPCMergeTimeSeriesSpec() +{ + std::vector inputs; + inputs.emplace_back("timeseries", o2::header::gDataOriginTPC, getDataDescriptionTimeSeries(), 0, Lifetime::Sporadic); + auto ccdbRequest = std::make_shared(true, // orbitResetTime + true, // GRPECS=true for nHBF per TF + false, // GRPLHCIF + false, // GRPMagField + false, // askMatLUT + o2::base::GRPGeomRequest::None, // geometry + inputs); + + std::vector outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, TPCMergeTimeSeries::getDataDescriptionCCDB()}, Lifetime::Sporadic); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, TPCMergeTimeSeries::getDataDescriptionCCDB()}, Lifetime::Sporadic); + + return DataProcessorSpec{ + "tpc-merge-time-series", + inputs, + outputs, + AlgorithmSpec{adaptFromTask(ccdbRequest)}, + Options{ + {"debug", VariantType::Bool, false, {"Write debug output files"}}, + {"tf-per-slot", VariantType::UInt32, 1000u, {"number of TFs per calibration time slot"}}, + {"max-delay", VariantType::UInt32, 3u, {"number of slots in past to consider"}}, + {"output-dir", VariantType::String, "none", {"calibration files output directory, must exist"}}, + {"meta-output-dir", VariantType::String, "/dev/null", {"calibration metadata output directory, must exist (if not /dev/null)"}}, + {"dump-calib-data", VariantType::Bool, false, {"Dump TimeSeriesITSTPC calibration data to file"}}}}; +} + +} // end namespace tpc +} // end namespace o2 diff --git a/Detectors/TPC/workflow/src/TPCTimeSeriesReaderSpec.cxx b/Detectors/TPC/workflow/src/TPCTimeSeriesReaderSpec.cxx new file mode 100644 index 0000000000000..9320b8c3a238d --- /dev/null +++ b/Detectors/TPC/workflow/src/TPCTimeSeriesReaderSpec.cxx @@ -0,0 +1,160 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file TPCTimeSeriesReaderSpec.cxx + +#include +#include + +#include "TPCWorkflow/TPCTimeSeriesReaderSpec.h" +#include "TPCWorkflow/TPCTimeSeriesSpec.h" +#include "DetectorsCalibration/IntegratedClusterCalibrator.h" +#include "Framework/Task.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "CommonUtils/NameConf.h" +#include "CommonDataFormat/TFIDInfo.h" +#include "Algorithm/RangeTokenizer.h" +#include "TChain.h" +#include "TGrid.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tpc +{ + +class TimeSeriesReader : public Task +{ + public: + TimeSeriesReader() = default; + ~TimeSeriesReader() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + void connectTrees(); + + int mChainEntry = 0; ///< processed entries in the chain + std::unique_ptr mChain; ///< input TChain + std::vector mFileNames; ///< input files + TimeSeriesITSTPC mTimeSeries, *mTimeSeriesPtr = &mTimeSeries; ///< branch time series values + o2::dataformats::TFIDInfo mTFinfo, *mTFinfoPtr = &mTFinfo; ///< branch TFIDInfo for injecting correct time + std::vector> mIndices; ///< firstTfOrbit, file, index +}; + +void TimeSeriesReader::init(InitContext& ic) +{ + const auto dontCheckFileAccess = ic.options().get("dont-check-file-access"); + auto fileList = o2::RangeTokenizer::tokenize(ic.options().get("tpc-time-series-infiles")); + + // check if only one input file (a txt file contaning a list of files is provided) + if (fileList.size() == 1) { + if (boost::algorithm::ends_with(fileList.front(), "txt")) { + LOGP(info, "Reading files from input file {}", fileList.front()); + std::ifstream is(fileList.front()); + std::istream_iterator start(is); + std::istream_iterator end; + std::vector fileNamesTmp(start, end); + fileList = fileNamesTmp; + } + } + + const std::string inpDir = o2::utils::Str::rectifyDirectory(ic.options().get("input-dir")); + for (const auto& file : fileList) { + if ((file.find("alien://") == 0) && !gGrid && !TGrid::Connect("alien://")) { + LOG(fatal) << "Failed to open alien connection"; + } + const auto fileDir = o2::utils::Str::concat_string(inpDir, file); + if (!dontCheckFileAccess) { + std::unique_ptr filePtr(TFile::Open(fileDir.data())); + if (!filePtr || !filePtr->IsOpen() || filePtr->IsZombie()) { + LOGP(warning, "Could not open file {}", fileDir); + continue; + } + } + mFileNames.emplace_back(fileDir); + } + + if (mFileNames.size() == 0) { + LOGP(error, "No input files to process"); + } + connectTrees(); +} + +void TimeSeriesReader::run(ProcessingContext& pc) +{ + // check time order inside the TChain + if (mChainEntry == 0) { + mIndices.clear(); + mIndices.reserve(mChain->GetEntries()); + // disable all branches except the firstTForbit branch to significantly speed up the loop over the TTree + mChain->SetBranchStatus("*", 0); + mChain->SetBranchStatus("firstTForbit", 1); + for (unsigned long i = 0; i < mChain->GetEntries(); i++) { + mChain->GetEntry(i); + mIndices.emplace_back(std::make_pair(mTFinfo.firstTForbit, i)); + } + mChain->SetBranchStatus("*", 1); + std::sort(mIndices.begin(), mIndices.end()); + } + + LOGP(debug, "Processing entry {}", mIndices[mChainEntry].second); + mChain->GetEntry(mIndices[mChainEntry++].second); + + // inject correct timing informations + auto& timingInfo = pc.services().get(); + timingInfo.firstTForbit = mTFinfo.firstTForbit; + timingInfo.tfCounter = mTFinfo.tfCounter; + timingInfo.runNumber = mTFinfo.runNumber; + timingInfo.creation = mTFinfo.creation; + + pc.outputs().snapshot(Output{header::gDataOriginTPC, getDataDescriptionTimeSeries()}, mTimeSeries); + usleep(100); + + if (mChainEntry >= mChain->GetEntries()) { + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(QuitRequest::Me); + } +} + +void TimeSeriesReader::connectTrees() +{ + mChain.reset(new TChain("treeTimeSeries")); + for (const auto& file : mFileNames) { + LOGP(info, "Adding file to chain: {}", file); + mChain->AddFile(file.data()); + } + assert(mChain->GetEntries()); + mChain->SetBranchAddress("TimeSeries", &mTimeSeriesPtr); + mChain->SetBranchAddress("tfID", &mTFinfoPtr); +} + +DataProcessorSpec getTPCTimeSeriesReaderSpec() +{ + std::vector outputs; + outputs.emplace_back(o2::header::gDataOriginTPC, getDataDescriptionTimeSeries(), 0, Lifetime::Sporadic); + + return DataProcessorSpec{ + "tpc-time-series-reader", + Inputs{}, + outputs, + AlgorithmSpec{adaptFromTask()}, + Options{ + {"tpc-time-series-infiles", VariantType::String, "o2_timeseries_tpc.root", {"comma-separated list of input files or .txt file containing list of input files"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}, + {"dont-check-file-access", VariantType::Bool, false, {"Deactivate check if all files are accessible before adding them to the list of files"}}, + }}; +} + +} // namespace tpc +} // namespace o2 diff --git a/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx b/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx new file mode 100644 index 0000000000000..dc500cb5ee774 --- /dev/null +++ b/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx @@ -0,0 +1,923 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file TPCTimeSeriesSpec.cxx +/// \brief device for time series +/// \author Matthias Kleiner +/// \date Aug 20, 2023 + +#include "Framework/Task.h" +#include "Framework/Logger.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/ControlService.h" +#include "DataFormatsTPC/WorkflowHelper.h" +#include "TPCWorkflow/ProcessingHelpers.h" +#include "TPCBase/Mapper.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "TPCWorkflow/TPCTimeSeriesSpec.h" +#include "DetectorsBase/TFIDInfoHelper.h" +#include "DetectorsBase/Propagator.h" +#include "TPCCalibration/RobustAverage.h" +#include "DetectorsCalibration/IntegratedClusterCalibrator.h" +#include "CommonUtils/DebugStreamer.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "CommonDataFormat/AbstractRefAccessor.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" +#include "TPCBase/ParameterElectronics.h" +#include "TPCCalibration/VDriftHelper.h" +#include +#include + +using namespace o2::framework; + +namespace o2 +{ +namespace tpc +{ + +class TPCTimeSeries : public Task +{ + public: + /// \constructor + TPCTimeSeries(std::shared_ptr req, const bool disableWriter, const o2::base::Propagator::MatCorrType matType) : mCCDBRequest(req), mDisableWriter(disableWriter), mMatType(matType){}; + + void init(framework::InitContext& ic) final + { + o2::base::GRPGeomHelper::instance().setRequest(mCCDBRequest); + mNMaxTracks = ic.options().get("max-tracks"); + mMinMom = ic.options().get("min-momentum"); + mMinNCl = ic.options().get("min-cluster"); + mMaxTgl = ic.options().get("max-tgl"); + mMaxQPtBin = ic.options().get("max-qPt-bin"); + mCoarseStep = ic.options().get("coarse-step"); + mFineStep = ic.options().get("fine-step"); + mCutDCA = ic.options().get("cut-DCA-median"); + mCutRMS = ic.options().get("cut-DCA-RMS"); + mRefXSec = ic.options().get("refX-for-sector"); + mTglBins = ic.options().get("tgl-bins"); + mPhiBins = ic.options().get("phi-bins"); + mQPtBins = ic.options().get("qPt-bins"); + mNThreads = ic.options().get("threads"); + maxITSTPCDCAr = ic.options().get("max-ITS-TPC-DCAr"); + maxITSTPCDCAz = ic.options().get("max-ITS-TPC-DCAz"); + mTimeWindowMUS = ic.options().get("time-window-mult-mus"); + mMIPdEdx = ic.options().get("MIP-dedx"); + mUseQMax = ic.options().get("use-qMax"); + mMaxSnp = ic.options().get("max-snp"); + mXCoarse = ic.options().get("mX-coarse"); + mBufferVals.resize(mNThreads); + mBufferDCA.setBinning(mPhiBins, mTglBins, mQPtBins); + } + + void run(ProcessingContext& pc) final + { + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + mTPCVDriftHelper.extractCCDBInputs(pc); + if (mTPCVDriftHelper.isUpdated()) { + mTPCVDriftHelper.acknowledgeUpdate(); + mVDrift = mTPCVDriftHelper.getVDriftObject().getVDrift(); + LOGP(info, "Updated reference drift velocity to: {}", mVDrift); + } + + const int nBins = getNBins(); + + // init only once + if (mAvgADCAr.size() != nBins) { + mBufferDCA.resize(nBins); + mAvgADCAr.resize(nBins); + mAvgCDCAr.resize(nBins); + mAvgADCAz.resize(nBins); + mAvgCDCAz.resize(nBins); + mAvgMeffA.resize(nBins); + mAvgMeffC.resize(nBins); + mAvgChi2MatchA.resize(nBins); + mAvgChi2MatchC.resize(nBins); + mMIPdEdxRatioA.resize(nBins); + mMIPdEdxRatioC.resize(nBins); + mTPCChi2A.resize(nBins); + mTPCChi2C.resize(nBins); + mTPCNClA.resize(nBins); + mTPCNClC.resize(nBins); + } + + // getting tracks + auto tracksTPC = pc.inputs().get>("tracksTPC"); + auto tracksITSTPC = pc.inputs().get>("tracksITSTPC"); + + // getting the vertices + const auto vertices = pc.inputs().get>("pvtx"); + const auto primMatchedTracks = pc.inputs().get>("pvtx_trmtc"); + const auto primMatchedTracksRef = pc.inputs().get>("pvtx_tref"); + + LOGP(detail, "Processing {} vertices, {} primary matched tracks, {} TPC tracks, {} ITS-TPC tracks", vertices.size(), primMatchedTracks.size(), tracksTPC.size(), tracksITSTPC.size()); + + // storing collision vertex to ITS-TPC track index + std::unordered_map indicesITSTPC_vtx; // ITS-TPC track index -> collision vertex ID + // loop over collisions + for (const auto& ref : primMatchedTracksRef) { + const auto source = o2::dataformats::VtxTrackIndex::Source::ITSTPC; + const int vID = ref.getVtxID(); // vertex ID + const int firstEntry = ref.getFirstEntryOfSource(source); + const int nEntries = ref.getEntriesOfSource(source); + // loop over all tracks belonging to the vertex + for (int i = 0; i < nEntries; ++i) { + // storing vertex ID for ITS-TPC track + const auto& matchedTrk = primMatchedTracks[i + firstEntry]; + if (matchedTrk.isTrackSource(source)) { + indicesITSTPC_vtx[matchedTrk] = vID; + } + } + } + + // storing indices to ITS-TPC tracks and vertex ID for tpc track + std::unordered_map> indicesITSTPC; // TPC track index -> ITS-TPC track index, vertex ID + // loop over all ITS-TPC tracks + for (int i = 0; i < tracksITSTPC.size(); ++i) { + auto it = indicesITSTPC_vtx.find(i); + // check if ITS-TPC track has attached vertex + const auto idxVtx = (it != indicesITSTPC_vtx.end()) ? (it->second) : -1; + // store TPC index and ITS-TPC+vertex index + indicesITSTPC[tracksITSTPC[i].getRefTPC().getIndex()] = {i, idxVtx}; + } + + // find nearest vertex of tracks which have no vertex assigned + findNearesVertex(tracksTPC, vertices); + + // getting cluster references for cluster bitmask + GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamTimeSeries)) { + mTPCTrackClIdx = pc.inputs().get>("trackTPCClRefs"); + mFirstTFOrbit = processing_helpers::getFirstTForbit(pc); + // get local multiplicity - count neighbouring tracks + findNNeighbourTracks(tracksTPC); + }) + + // reset buffers + for (int i = 0; i < nBins; ++i) { + for (int type = 0; type < mAvgADCAr[i].size(); ++type) { + mAvgADCAr[i][type].clear(); + mAvgCDCAr[i][type].clear(); + mAvgADCAz[i][type].clear(); + mAvgCDCAz[i][type].clear(); + mMIPdEdxRatioA[i][type].clear(); + mMIPdEdxRatioC[i][type].clear(); + mTPCChi2A[i][type].clear(); + mTPCChi2C[i][type].clear(); + mTPCNClA[i][type].clear(); + mTPCNClC[i][type].clear(); + } + for (int j = 0; j < mAvgMeffA[i].size(); ++j) { + mAvgMeffA[i][j].clear(); + mAvgMeffC[i][j].clear(); + mAvgChi2MatchA[i][j].clear(); + mAvgChi2MatchC[i][j].clear(); + } + } + + for (int i = 0; i < mNThreads; ++i) { + mBufferVals[i].front().clear(); + mBufferVals[i].back().clear(); + } + + // define number of tracks which are used + const auto nTracks = tracksTPC.size(); + const size_t loopEnd = (mNMaxTracks < 0) ? nTracks : ((mNMaxTracks > nTracks) ? nTracks : size_t(mNMaxTracks)); + + // reserve memory + for (int i = 0; i < nBins; ++i) { + for (int type = 0; type < mAvgADCAr[i].size(); ++type) { + mAvgADCAr[i][type].reserve(loopEnd); + mAvgCDCAr[i][type].reserve(loopEnd); + mAvgADCAz[i][type].reserve(loopEnd); + mAvgCDCAz[i][type].reserve(loopEnd); + mMIPdEdxRatioA[i][type].reserve(loopEnd); + mMIPdEdxRatioC[i][type].reserve(loopEnd); + mTPCChi2A[i][type].reserve(loopEnd); + mTPCChi2C[i][type].reserve(loopEnd); + mTPCNClA[i][type].reserve(loopEnd); + mTPCNClC[i][type].reserve(loopEnd); + } + for (int j = 0; j < mAvgMeffA[i].size(); ++j) { + mAvgMeffA[i][j].reserve(loopEnd); + mAvgMeffC[i][j].reserve(loopEnd); + mAvgChi2MatchA[i][j].reserve(loopEnd); + mAvgChi2MatchC[i][j].reserve(loopEnd); + } + } + for (int iThread = 0; iThread < mNThreads; ++iThread) { + mBufferVals[iThread].front().reserve(loopEnd); + mBufferVals[iThread].back().reserve(loopEnd); + } + + using timer = std::chrono::high_resolution_clock; + auto startTotal = timer::now(); + + // loop over tracks and calculate DCAs + if (loopEnd < nTracks) { + // draw random tracks + std::vector ind(nTracks); + std::iota(ind.begin(), ind.end(), 0); + std::minstd_rand rng(std::time(nullptr)); + std::shuffle(ind.begin(), ind.end(), rng); + + auto myThread = [&](int iThread) { + for (size_t i = iThread; i < loopEnd; i += mNThreads) { + if (acceptTrack(tracksTPC[i])) { + fillDCA(tracksTPC, tracksITSTPC, vertices, i, iThread, indicesITSTPC); + } + } + }; + + std::vector threads(mNThreads); + for (int i = 0; i < mNThreads; i++) { + threads[i] = std::thread(myThread, i); + } + + for (auto& th : threads) { + th.join(); + } + } else { + auto myThread = [&](int iThread) { + for (size_t i = iThread; i < loopEnd; i += mNThreads) { + if (acceptTrack(tracksTPC[i])) { + fillDCA(tracksTPC, tracksITSTPC, vertices, i, iThread, indicesITSTPC); + } + } + }; + + std::vector threads(mNThreads); + for (int i = 0; i < mNThreads; i++) { + threads[i] = std::thread(myThread, i); + } + + for (auto& th : threads) { + th.join(); + } + } + + // fill DCA values from buffer + for (const auto& vals : mBufferVals) { + for (int type = 0; type < vals.size(); ++type) { + const auto& val = vals[type]; + const auto nPoints = val.side.size(); + for (int i = 0; i < nPoints; ++i) { + const auto tglBin = val.tglBin[i]; + const auto phiBin = val.phiBin[i]; + const auto qPtBin = val.qPtBin[i]; + const auto dcar = val.dcar[i]; + const auto dcaz = val.dcaz[i]; + const auto dcarW = val.dcarW[i]; + const int binInt = nBins - 1; + const std::array bins{tglBin, phiBin, qPtBin, binInt}; + // fill bins + for (auto bin : bins) { + if (val.side[i] == Side::C) { + mAvgCDCAr[bin][type].addValue(dcar, dcarW); + // fill only in case of valid value + if (dcaz != 0) { + mAvgCDCAz[bin][type].addValue(dcaz, dcarW); + } + } else { + mAvgADCAr[bin][type].addValue(dcar, dcarW); + // fill only in case of valid value + if (dcaz != 0) { + mAvgADCAz[bin][type].addValue(dcaz, dcarW); + } + } + } + } + } + } + + // calculate statistics and store values + // loop over TPC sides + for (int type = 0; type < 2; ++type) { + // loop over phi and tgl bins + for (int slice = 0; slice < nBins; ++slice) { + auto& bufferDCA = (type == 0) ? mBufferDCA.mTSTPC : mBufferDCA.mTSITSTPC; + + const auto dcaAr = mAvgADCAr[slice][type].filterPointsMedian(mCutDCA, mCutRMS); + bufferDCA.mDCAr_A_Median[slice] = std::get<0>(dcaAr); + bufferDCA.mDCAr_A_WeightedMean[slice] = std::get<1>(dcaAr); + bufferDCA.mDCAr_A_RMS[slice] = std::get<2>(dcaAr); + bufferDCA.mDCAr_A_NTracks[slice] = std::get<3>(dcaAr); + + const auto dcaAz = mAvgADCAz[slice][type].filterPointsMedian(mCutDCA, mCutRMS); + bufferDCA.mDCAz_A_Median[slice] = std::get<0>(dcaAz); + bufferDCA.mDCAz_A_WeightedMean[slice] = std::get<1>(dcaAz); + bufferDCA.mDCAz_A_RMS[slice] = std::get<2>(dcaAz); + bufferDCA.mDCAz_A_NTracks[slice] = std::get<3>(dcaAz); + + const auto dcaCr = mAvgCDCAr[slice][type].filterPointsMedian(mCutDCA, mCutRMS); + bufferDCA.mDCAr_C_Median[slice] = std::get<0>(dcaCr); + bufferDCA.mDCAr_C_WeightedMean[slice] = std::get<1>(dcaCr); + bufferDCA.mDCAr_C_RMS[slice] = std::get<2>(dcaCr); + bufferDCA.mDCAr_C_NTracks[slice] = std::get<3>(dcaCr); + + const auto dcaCz = mAvgCDCAz[slice][type].filterPointsMedian(mCutDCA, mCutRMS); + bufferDCA.mDCAz_C_Median[slice] = std::get<0>(dcaCz); + bufferDCA.mDCAz_C_WeightedMean[slice] = std::get<1>(dcaCz); + bufferDCA.mDCAz_C_RMS[slice] = std::get<2>(dcaCz); + bufferDCA.mDCAz_C_NTracks[slice] = std::get<3>(dcaCz); + } + } + + // calculate matching eff + for (const auto& vals : mBufferVals) { + const auto& val = vals.front(); + const auto nPoints = val.side.size(); + for (int i = 0; i < nPoints; ++i) { + const auto tglBin = val.tglBin[i]; + const auto phiBin = val.phiBin[i]; + const auto qPtBin = val.qPtBin[i]; + const auto dcar = val.dcar[i]; + const auto dcaz = val.dcaz[i]; + const auto hasITS = val.hasITS[i]; + const auto chi2Match = val.chi2Match[i]; + const auto dedxRatio = val.dedxRatio[i]; + const auto sqrtChi2TPC = val.sqrtChi2TPC[i]; + const auto nClTPC = val.nClTPC[i]; + const int binInt = nBins - 1; + const Side side = val.side[i]; + const bool isCSide = (side == Side::C); + const auto& bufferDCARMSR = isCSide ? mBufferDCA.mTSTPC.mDCAr_C_RMS : mBufferDCA.mTSTPC.mDCAr_A_RMS; + const auto& bufferDCARMSZ = isCSide ? mBufferDCA.mTSTPC.mDCAz_C_RMS : mBufferDCA.mTSTPC.mDCAz_A_RMS; + const auto& bufferDCAMedR = isCSide ? mBufferDCA.mTSTPC.mDCAr_C_Median : mBufferDCA.mTSTPC.mDCAr_A_Median; + const auto& bufferDCAMedZ = isCSide ? mBufferDCA.mTSTPC.mDCAz_C_Median : mBufferDCA.mTSTPC.mDCAz_A_Median; + auto& mAvgEff = isCSide ? mAvgMeffC : mAvgMeffA; + auto& mAvgChi2Match = isCSide ? mAvgChi2MatchC : mAvgChi2MatchA; + auto& mAvgmMIPdEdxRatio = isCSide ? mMIPdEdxRatioC : mMIPdEdxRatioA; + auto& mAvgmTPCChi2 = isCSide ? mTPCChi2C : mTPCChi2A; + auto& mAvgmTPCNCl = isCSide ? mTPCNClC : mTPCNClA; + + const std::array bins{tglBin, phiBin, qPtBin, binInt}; + // fill bins + for (auto bin : bins) { + if ((std::abs(dcar - bufferDCAMedR[bin]) < (bufferDCARMSR[bin] * mCutRMS)) && (std::abs(dcaz - bufferDCAMedZ[bin]) < (bufferDCARMSZ[bin] * mCutRMS))) { + const auto gID = val.gID[i]; + mAvgEff[bin][0].addValue(hasITS); + // count tpc only tracks not matched + if (!hasITS) { + mAvgEff[bin][1].addValue(hasITS); + mAvgEff[bin][2].addValue(hasITS); + } + // count tracks from ITS standalone and afterburner + if (gID == o2::dataformats::GlobalTrackID::Source::ITS) { + mAvgEff[bin][1].addValue(hasITS); + } else if (gID == o2::dataformats::GlobalTrackID::Source::ITSAB) { + mAvgEff[bin][2].addValue(hasITS); + } + if (chi2Match > 0) { + mAvgChi2Match[bin][0].addValue(chi2Match); + if (gID == o2::dataformats::GlobalTrackID::Source::ITS) { + mAvgChi2Match[bin][1].addValue(chi2Match); + } else if (gID == o2::dataformats::GlobalTrackID::Source::ITSAB) { + mAvgChi2Match[bin][2].addValue(chi2Match); + } + } + if (dedxRatio > 0) { + mAvgmMIPdEdxRatio[bin][0].addValue(dedxRatio); + } + mAvgmTPCChi2[bin][0].addValue(sqrtChi2TPC); + mAvgmTPCNCl[bin][0].addValue(nClTPC); + if (hasITS) { + if (dedxRatio > 0) { + mAvgmMIPdEdxRatio[bin][1].addValue(dedxRatio); + } + mAvgmTPCChi2[bin][1].addValue(sqrtChi2TPC); + mAvgmTPCNCl[bin][1].addValue(nClTPC); + } + } + } + } + } + + // store matching eff + for (int slice = 0; slice < nBins; ++slice) { + for (int i = 0; i < mAvgMeffA[slice].size(); ++i) { + auto& itsBuf = (i == 0) ? mBufferDCA.mITSTPCAll : ((i == 1) ? mBufferDCA.mITSTPCStandalone : mBufferDCA.mITSTPCAfterburner); + itsBuf.mITSTPC_A_MatchEff[slice] = mAvgMeffA[slice][i].getMean(); + itsBuf.mITSTPC_C_MatchEff[slice] = mAvgMeffC[slice][i].getMean(); + itsBuf.mITSTPC_A_Chi2Match[slice] = mAvgChi2MatchA[slice][i].getMean(); + itsBuf.mITSTPC_C_Chi2Match[slice] = mAvgChi2MatchC[slice][i].getMean(); + } + + for (int i = 0; i < mMIPdEdxRatioC[slice].size(); ++i) { + auto& buff = (i == 0) ? mBufferDCA.mTSTPC : mBufferDCA.mTSITSTPC; + buff.mMIPdEdxRatioC[slice] = mMIPdEdxRatioC[slice][i].getMean(); + buff.mMIPdEdxRatioA[slice] = mMIPdEdxRatioA[slice][i].getMean(); + buff.mTPCChi2C[slice] = mTPCChi2C[slice][i].getMean(); + buff.mTPCChi2A[slice] = mTPCChi2A[slice][i].getMean(); + buff.mTPCNClC[slice] = mTPCNClC[slice][i].getMean(); + buff.mTPCNClA[slice] = mTPCNClA[slice][i].getMean(); + } + } + + auto stop = timer::now(); + std::chrono::duration time = stop - startTotal; + LOGP(detail, "DCA processing took {}", time.count()); + + // send data + sendOutput(pc); + } + + void endOfStream(EndOfStreamContext& eos) final + { + o2::utils::DebugStreamer::instance()->flush(); + eos.services().get().readyToQuit(QuitRequest::Me); + } + + void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final + { + mTPCVDriftHelper.accountCCDBInputs(matcher, obj); + o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj); + } + + private: + /// buffer struct for multithreading + struct FillVals { + void reserve(int n) + { + side.reserve(n); + tglBin.reserve(n); + phiBin.reserve(n); + qPtBin.reserve(n); + dcar.reserve(n); + dcaz.reserve(n); + dcarW.reserve(n); + hasITS.reserve(n); + chi2Match.reserve(n); + dedxRatio.reserve(n); + sqrtChi2TPC.reserve(n); + nClTPC.reserve(n); + gID.reserve(n); + } + + void clear() + { + side.clear(); + tglBin.clear(); + phiBin.clear(); + qPtBin.clear(); + dcar.clear(); + dcaz.clear(); + dcarW.clear(); + hasITS.clear(); + chi2Match.clear(); + dedxRatio.clear(); + sqrtChi2TPC.clear(); + nClTPC.clear(); + gID.clear(); + } + + void emplace_back(Side sideTmp, int tglBinTmp, int phiBinTmp, int qPtBinTmp, float dcarTmp, float dcazTmp, float dcarWTmp, float dedxRatioTmp, float sqrtChi2TPCTmp, float nClTPCTmp, o2::dataformats::GlobalTrackID::Source gIDTmp = o2::dataformats::GlobalTrackID::Source::NSources, float chi2MatchTmp = -2, int hasITSTmp = -1) + { + side.emplace_back(sideTmp); + tglBin.emplace_back(tglBinTmp); + phiBin.emplace_back(phiBinTmp); + qPtBin.emplace_back(qPtBinTmp); + dcar.emplace_back(dcarTmp); + dcaz.emplace_back(dcazTmp); + dcarW.emplace_back(dcarWTmp); + dedxRatio.emplace_back(dedxRatioTmp); + sqrtChi2TPC.emplace_back(sqrtChi2TPCTmp); + nClTPC.emplace_back(nClTPCTmp); + if (chi2MatchTmp != -2) { + chi2Match.emplace_back(chi2MatchTmp); + hasITS.emplace_back(hasITSTmp); + gID.emplace_back(gIDTmp); + } + } + + std::vector side; + std::vector tglBin; + std::vector phiBin; + std::vector qPtBin; + std::vector dcar; + std::vector dcaz; + std::vector dcarW; + std::vector hasITS; + std::vector chi2Match; + std::vector dedxRatio; + std::vector sqrtChi2TPC; + std::vector nClTPC; + std::vector gID; + }; + std::shared_ptr mCCDBRequest; ///< info for CCDB request + const bool mDisableWriter{false}; ///< flag if no ROOT output will be written + o2::base::Propagator::MatCorrType mMatType; ///< material for propagation + int mPhiBins = SECTORSPERSIDE; ///< number of phi bins + int mTglBins{3}; ///< number of tgl bins + int mQPtBins{20}; ///< number of qPt bins + TimeSeriesITSTPC mBufferDCA; ///< buffer for integrate DCAs + std::vector> mAvgADCAr; ///< for averaging the DCAr for TPC and ITS-TPC tracks for A-side + std::vector> mAvgCDCAr; ///< for averaging the DCAr for TPC and ITS-TPC tracks for C-side + std::vector> mAvgADCAz; ///< for averaging the DCAz for TPC and ITS-TPC tracks for A-side + std::vector> mAvgCDCAz; ///< for averaging the DCAz for TPC and ITS-TPC tracks for C-side + std::vector> mMIPdEdxRatioA; ///< for averaging MIP/dEdx + std::vector> mMIPdEdxRatioC; ///< for averaging MIP/dEdx + std::vector> mTPCChi2A; ///< for averaging chi2 TPC A + std::vector> mTPCChi2C; ///< for averaging chi2 TPC C + std::vector> mTPCNClA; ///< for averaging number of cluster A + std::vector> mTPCNClC; ///< for averaging number of cluster C + std::vector> mAvgMeffA; ///< for matching efficiency ITS-TPC standalone + afterburner, standalone, afterburner + std::vector> mAvgMeffC; ///< for matching efficiency ITS-TPC standalone + afterburner, standalone, afterburner + std::vector> mAvgChi2MatchA; ///< for matching efficiency ITS-TPC standalone + afterburner, standalone, afterburner + std::vector> mAvgChi2MatchC; ///< for matching efficiency ITS-TPC standalone + afterburner, standalone, afterburner + int mNMaxTracks{-1}; ///< maximum number of tracks to process + float mMinMom{1}; ///< minimum accepted momentum + int mMinNCl{80}; ///< minimum accepted number of clusters per track + float mMaxTgl{1}; ///< maximum eta + float mMaxQPtBin{5}; ///< max qPt bin + float mCoarseStep{1}; ///< coarse step during track propagation + float mFineStep{0.005}; ///< fine step during track propagation + float mCutDCA{5}; ///< cut on the abs(DCA-median) + float mCutRMS{5}; ///< sigma cut for mean,median calculation + float mRefXSec{108.475}; ///< reference lx position for sector information (default centre of IROC) + int mNThreads{1}; ///< number of parallel threads + float maxITSTPCDCAr{0.2}; ///< maximum abs DCAr value for ITS-TPC tracks + float maxITSTPCDCAz{10}; ///< maximum abs DCAz value for ITS-TPC tracks + gsl::span mTPCTrackClIdx{}; ///< cluster refs for debugging + std::vector> mBufferVals; ///< buffer for multithreading + uint32_t mFirstTFOrbit{0}; ///< first TF orbit + float mTimeWindowMUS{50}; ///< time window in mus for local mult estimate + float mMIPdEdx{50}; ///< MIP dEdx position for MIP/dEdx monitoring + std::vector mNTracksWindow; ///< number of tracks in time window + std::vector mNearestVtxTPC; ///< nearest vertex for tpc tracks + o2::tpc::VDriftHelper mTPCVDriftHelper{}; ///< helper for v-drift + float mVDrift{2.64}; ///< v drift in mus + bool mUseQMax{false}; ///< use dedx qmax for MIP/dEdx monitoring + float mMaxSnp{0.85}; ///< max sinus phi for propagation + float mXCoarse{40}; ///< perform propagation with coarse steps up to this mx + + /// check if track passes coarse cuts + bool acceptTrack(const TrackTPC& track) const + { + if ((track.getP() < mMinMom) || (track.getNClusters() < mMinNCl) || std::abs(track.getTgl()) > mMaxTgl) { + return false; + } + return true; + } + + void fillDCA(const gsl::span tracksTPC, const gsl::span tracksITSTPC, const gsl::span vertices, const int iTrk, const int iThread, const std::unordered_map>& indicesITSTPC) + { + TrackTPC track = tracksTPC[iTrk]; + + // propagate track to the DCA and fill in slice + auto propagator = o2::base::Propagator::Instance(); + + // propagate track to DCA + o2::gpu::gpustd::array dca; + const o2::math_utils::Point3D refPoint{0, 0, 0}; + + // coarse propagation + if (!propagator->PropagateToXBxByBz(track, mXCoarse, mMaxSnp, mCoarseStep, mMatType)) { + return; + } + + // fine propagation with Bz only + if (!propagator->propagateToDCA(refPoint, track, propagator->getNominalBz(), mFineStep, mMatType, &dca)) { + return; + } + + TrackTPC trackTmp = tracksTPC[iTrk]; + + // coarse propagation to centre of IROC for phi bin + if (!propagator->propagateTo(trackTmp, mRefXSec, false, mMaxSnp, mCoarseStep, mMatType)) { + return; + } + + const int tglBin = mTglBins * std::abs(trackTmp.getTgl()) / mMaxTgl + mPhiBins; + const int phiBin = mPhiBins * trackTmp.getPhi() / o2::constants::math::TwoPI; + const int qPtBin = mPhiBins + mTglBins + mQPtBins * (trackTmp.getQ2Pt() + mMaxQPtBin) / (2 * mMaxQPtBin); + const int nBins = getNBins(); + + if ((phiBin < 0) || (phiBin > mPhiBins) || (tglBin < mPhiBins) || (tglBin > (mPhiBins + mTglBins)) || (qPtBin < (mPhiBins + mTglBins)) || (qPtBin > (mPhiBins + mTglBins + mQPtBins))) { + return; + } + + const int sector = o2::math_utils::angle2Sector(trackTmp.getPhiPos()); + if (sector < SECTORSPERSIDE) { + // find possible ITS-TPC track and vertex index + auto it = indicesITSTPC.find(iTrk); + const auto idxITSTPC = (it != indicesITSTPC.end()) ? (it->second) : std::array{-1, -1}; + + // get vertex (check if vertex ID is valid). In case no vertex is assigned return nearest vertex or else default vertex + const auto vertex = (idxITSTPC.back() != -1) ? vertices[idxITSTPC.back()] : ((mNearestVtxTPC[iTrk] != -1) ? vertices[mNearestVtxTPC[iTrk]] : o2::dataformats::PrimaryVertex{}); + + // calculate DCAz: (time TPC track - time vertex) * vDrift + sign_side * vertexZ + const float signSide = track.hasCSideClustersOnly() ? -1 : 1; // invert sign for C-side + const float dcaZFromDeltaTime = (vertex.getTimeStamp().getTimeStamp() == 0) ? 0 : (o2::tpc::ParameterElectronics::Instance().ZbinWidth * track.getTime0() - vertex.getTimeStamp().getTimeStamp()) * mVDrift + signSide * vertex.getZ(); + + // for weight of DCA + const float resCl = std::min(track.getNClusters(), static_cast(Mapper::PADROWS)) / static_cast(Mapper::PADROWS); + + const float div = (resCl * track.getPt()); + if (div == 0) { + return; + } + + const float fB = 0.2 / div; + const float fA = 0.15 + 0.15; // = 0.15 with additional misalignment error + const float dcarW = 1. / std::sqrt(fA * fA + fB * fB); // Weight of DCA: Rms2 ~ 0.15^2 + k/(L^2*pt) → 0.15**2 + (0.2/((NCl/152)*pt)^2); + + // store values for TPC DCA only for A- or C-side only tracks + const bool hasITSTPC = idxITSTPC.front() != -1; + + // get ratio of chi2 in case ITS-TPC track has been found + const float chi2 = hasITSTPC ? tracksITSTPC[idxITSTPC.front()].getChi2Match() : -1; + auto gID = o2::dataformats::GlobalTrackID::Source::TPC; // source + // check for source in case of ITS-TPC + if (hasITSTPC) { + const auto src = tracksITSTPC[idxITSTPC.front()].getRefITS().getSource(); + if (src == o2::dataformats::GlobalTrackID::ITS) { + gID = o2::dataformats::GlobalTrackID::Source::ITS; + } else if (src == o2::dataformats::GlobalTrackID::ITSAB) { + gID = o2::dataformats::GlobalTrackID::Source::ITSAB; + } + } + + const float chi2Match = (chi2 > 0) ? std::sqrt(chi2) : -1; + const float dedx = mUseQMax ? track.getdEdx().dEdxMaxTPC : track.getdEdx().dEdxTotTPC; + const float dedxRatio = (dedx > 0) ? (mMIPdEdx / dedx) : -1; + const float sqrtChi2TPC = (track.getChi2() > 0) ? std::sqrt(track.getChi2()) : 0; + const float nClTPC = track.getNClusters(); + + if (track.hasCSideClustersOnly()) { + mBufferVals[iThread].front().emplace_back(Side::C, tglBin, phiBin, qPtBin, dca[0], dcaZFromDeltaTime, dcarW, dedxRatio, sqrtChi2TPC, nClTPC, gID, chi2Match, hasITSTPC); + } else if (track.hasASideClustersOnly()) { + mBufferVals[iThread].front().emplace_back(Side::A, tglBin, phiBin, qPtBin, dca[0], dcaZFromDeltaTime, dcarW, dedxRatio, sqrtChi2TPC, nClTPC, gID, chi2Match, hasITSTPC); + } + + // check if the track was assigned to ITS track + o2::gpu::gpustd::array dcaITSTPC{0, 0}; + if (hasITSTPC) { + // propagate ITS-TPC track to (0,0) + auto trackITSTPCTmp = tracksITSTPC[idxITSTPC.front()]; + // fine propagation with Bz only + if (propagator->PropagateToXBxByBz(trackITSTPCTmp, mXCoarse, mMaxSnp, mCoarseStep, mMatType) && propagator->propagateToDCA(refPoint, trackITSTPCTmp, propagator->getNominalBz(), mFineStep, mMatType, &dcaITSTPC)) { + // make cut on abs(DCA) + if ((std::abs(dcaITSTPC[0]) < maxITSTPCDCAr) && (std::abs(dcaITSTPC[1]) < maxITSTPCDCAz)) { + // store TPC only DCAs + if (track.hasCSideClustersOnly()) { + mBufferVals[iThread].back().emplace_back(Side::C, tglBin, phiBin, qPtBin, dca[0], dcaZFromDeltaTime, dcarW, dedxRatio, sqrtChi2TPC, nClTPC); + } else if (track.hasASideClustersOnly()) { + mBufferVals[iThread].back().emplace_back(Side::A, tglBin, phiBin, qPtBin, dca[0], dcaZFromDeltaTime, dcarW, dedxRatio, sqrtChi2TPC, nClTPC); + } + } + } + } + + GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamTimeSeries)) { + auto clusterMask = makeClusterBitMask(track); + const auto& trkOrig = tracksTPC[iTrk]; + const bool isNearestVtx = (idxITSTPC.back() == -1); // is nearest vertex in case no vertex was found + const float mx_ITS = hasITSTPC ? tracksITSTPC[idxITSTPC.front()].getX() : -1; + int typeSide = 2; // A- and C-Side cluster + if (track.hasASideClustersOnly()) { + typeSide = 0; + } else if (track.hasCSideClustersOnly()) { + typeSide = 1; + } + + o2::utils::DebugStreamer::instance()->getStreamer("time_series", "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName("treeTimeSeries").data() + // DCAs + << "dcar_tpc=" << dca[0] + << "dcaz_tpc=" << dca[1] + << "dcar_itstpc=" << dcaITSTPC[0] + << "dcaz_itstpc=" << dcaITSTPC[1] + << "dcarW=" << dcarW + << "dcaZFromDeltaTime=" << dcaZFromDeltaTime + << "hasITSTPC=" << hasITSTPC + // vertex + << "vertex_x=" << vertex.getX() + << "vertex_y=" << vertex.getY() + << "vertex_z=" << vertex.getZ() + << "vertex_time=" << vertex.getTimeStamp().getTimeStamp() + << "vertex_nContributors=" << vertex.getNContributors() + << "isNearestVertex=" << isNearestVtx + // tpc track properties + << "pt=" << trkOrig.getPt() + << "tpc_timebin=" << trkOrig.getTime0() + << "qpt=" << trkOrig.getParam(4) + << "ncl=" << trkOrig.getNClusters() + << "tgl=" << trkOrig.getTgl() + << "side_type=" << typeSide + << "phi=" << trkOrig.getPhi() + << "clusterMask=" << clusterMask + << "dedxTotTPC=" << trkOrig.getdEdx().dEdxTotTPC + << "dedxTotIROC=" << trkOrig.getdEdx().dEdxTotIROC + << "dedxTotOROC1=" << trkOrig.getdEdx().dEdxTotOROC1 + << "dedxTotOROC2=" << trkOrig.getdEdx().dEdxTotOROC2 + << "dedxTotOROC3=" << trkOrig.getdEdx().dEdxTotOROC3 + << "chi2=" << trkOrig.getChi2() + << "mX=" << trkOrig.getX() + << "mX_ITS=" << mx_ITS + // meta + << "mult=" << mNTracksWindow[iTrk] + << "time_window_mult=" << mTimeWindowMUS + << "firstTFOrbit=" << mFirstTFOrbit + << "mVDrift=" << mVDrift + << "\n"; + }) + } + } + + void sendOutput(ProcessingContext& pc) + { + pc.outputs().snapshot(Output{header::gDataOriginTPC, getDataDescriptionTimeSeries()}, mBufferDCA); + // in case of ROOT output also store the TFinfo in the TTree + if (!mDisableWriter) { + o2::dataformats::TFIDInfo tfinfo; + o2::base::TFIDInfoHelper::fillTFIDInfo(pc, tfinfo); + const long timeMS = o2::base::GRPGeomHelper::instance().getOrbitResetTimeMS() + processing_helpers::getFirstTForbit(pc) * o2::constants::lhc::LHCOrbitMUS / 1000; + mBufferDCA.mTSTPC.setStartTime(timeMS); + mBufferDCA.mTSITSTPC.setStartTime(timeMS); + pc.outputs().snapshot(Output{header::gDataOriginTPC, getDataDescriptionTPCTimeSeriesTFId()}, tfinfo); + } + } + + /// find for tpc tracks the nearest vertex + void findNearesVertex(const gsl::span tracksTPC, const gsl::span vertices) + { + // create list of time bins of tracks + const int nVertices = vertices.size(); + + const int nTracks = tracksTPC.size(); + mNearestVtxTPC.clear(); + mNearestVtxTPC.resize(nTracks); + + // in case no vertices are found + if (!nVertices) { + std::fill(mNearestVtxTPC.begin(), mNearestVtxTPC.end(), -1); + return; + } + + // store timestamps of vertices. Assume vertices are already sorted in time! + std::vector times_vtx; + times_vtx.reserve(nVertices); + for (const auto& vtx : vertices) { + times_vtx.emplace_back(vtx.getTimeStamp().getTimeStamp()); + } + + // loop over tpc tracks and find nearest vertex + auto myThread = [&](int iThread) { + for (int i = iThread; i < nTracks; i += mNThreads) { + const float timeTrack = o2::tpc::ParameterElectronics::Instance().ZbinWidth * tracksTPC[i].getTime0(); + const auto lower = std::lower_bound(times_vtx.begin(), times_vtx.end(), timeTrack); + int closestVtx = std::distance(times_vtx.begin(), lower); + // if value is out of bounds use last value + if (closestVtx == nVertices) { + closestVtx -= 1; + } else if (closestVtx > 0) { + // if idx > 0 check preceeding value + double diff1 = std::abs(timeTrack - *lower); + double diff2 = std::abs(timeTrack - *(lower - 1)); + if (diff2 < diff1) { + closestVtx -= 1; + } + } + mNearestVtxTPC[i] = closestVtx; + } + }; + + std::vector threads(mNThreads); + for (int i = 0; i < mNThreads; i++) { + threads[i] = std::thread(myThread, i); + } + + // wait for the threads to finish + for (auto& th : threads) { + th.join(); + } + } + + /// make bit mask of clusters + std::vector makeClusterBitMask(const TrackTPC& track) const + { + std::vector tpcClusterMask(Mapper::PADROWS, false); + const int nCl = track.getNClusterReferences(); + for (int j = 0; j < nCl; ++j) { + uint8_t sector, padrow; + uint32_t clusterIndexInRow; + track.getClusterReference(mTPCTrackClIdx, j, sector, padrow, clusterIndexInRow); + tpcClusterMask[padrow] = true; + } + return tpcClusterMask; + } + + /// find number of neighbouring tracks for mult estimate + void findNNeighbourTracks(const gsl::span tracksTPC) + { + const float tpcTBinMUS = o2::tpc::ParameterElectronics::Instance().ZbinWidth; // 0.199606f; time bin in MUS + const float windowTimeBins = mTimeWindowMUS / tpcTBinMUS; // number of neighbouring time bins to check + + // create list of time bins of tracks + std::vector times; + const int nTracks = tracksTPC.size(); + times.reserve(nTracks); + for (const auto& trk : tracksTPC) { + times.emplace_back(trk.getTime0()); + } + std::sort(times.begin(), times.end()); + + mNTracksWindow.clear(); + mNTracksWindow.resize(nTracks); + + // loop over tpc tracks and count number of neighouring tracks + auto myThread = [&](int iThread) { + for (int i = iThread; i < nTracks; i += mNThreads) { + const float t0 = tracksTPC[i].getTime0(); + const auto upperV0 = std::upper_bound(times.begin(), times.end(), t0 + windowTimeBins); + const auto lowerV0 = std::lower_bound(times.begin(), times.end(), t0 - windowTimeBins); + const int nMult = std::distance(times.begin(), upperV0) - std::distance(times.begin(), lowerV0); + mNTracksWindow[i] = nMult; + } + }; + + std::vector threads(mNThreads); + for (int i = 0; i < mNThreads; i++) { + threads[i] = std::thread(myThread, i); + } + + // wait for the threads to finish + for (auto& th : threads) { + th.join(); + } + } + + /// \return returns total number of stored values per TF + int getNBins() const { return mBufferDCA.mTSTPC.getNBins(); } +}; + +o2::framework::DataProcessorSpec getTPCTimeSeriesSpec(const bool disableWriter, const o2::base::Propagator::MatCorrType matType) +{ + const bool enableAskMatLUT = matType == o2::base::Propagator::MatCorrType::USEMatCorrLUT; + std::vector inputs; + inputs.emplace_back("tracksITSTPC", "GLO", "TPCITS", 0, Lifetime::Timeframe); + inputs.emplace_back("tracksTPC", header::gDataOriginTPC, "TRACKS", 0, Lifetime::Timeframe); + GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamTimeSeries)) { + // request tpc clusters only in case the debug streamer is used for the cluster bit mask + inputs.emplace_back("trackTPCClRefs", header::gDataOriginTPC, "CLUSREFS", 0, Lifetime::Timeframe); + }) + inputs.emplace_back("pvtx", "GLO", "PVTX", 0, Lifetime::Timeframe); + inputs.emplace_back("pvtx_trmtc", "GLO", "PVTX_TRMTC", 0, Lifetime::Timeframe); // global ids of associated tracks + inputs.emplace_back("pvtx_tref", "GLO", "PVTX_TRMTCREFS", 0, Lifetime::Timeframe); // vertex - trackID refs + + auto ccdbRequest = std::make_shared(!disableWriter, // orbitResetTime + false, // GRPECS=true for nHBF per TF + false, // GRPLHCIF + true, // GRPMagField + enableAskMatLUT, // askMatLUT + o2::base::GRPGeomRequest::None, // geometry + inputs, + true, + true); + + o2::tpc::VDriftHelper::requestCCDBInputs(inputs); + std::vector outputs; + outputs.emplace_back(o2::header::gDataOriginTPC, getDataDescriptionTimeSeries(), 0, Lifetime::Sporadic); + if (!disableWriter) { + outputs.emplace_back(o2::header::gDataOriginTPC, getDataDescriptionTPCTimeSeriesTFId(), 0, Lifetime::Sporadic); + } + + return DataProcessorSpec{ + "tpc-time-series", + inputs, + outputs, + AlgorithmSpec{adaptFromTask(ccdbRequest, disableWriter, matType)}, + Options{{"min-momentum", VariantType::Float, 0.2f, {"Minimum momentum of the tracks"}}, + {"min-cluster", VariantType::Int, 80, {"Minimum number of clusters of the tracks"}}, + {"max-tgl", VariantType::Float, 1.1f, {"Maximum accepted tgl of the tracks"}}, + {"max-qPt-bin", VariantType::Float, 5.f, {"Maximum abs(qPt) bin"}}, + {"max-snp", VariantType::Float, 0.85f, {"Maximum sinus(phi) for propagation"}}, + {"coarse-step", VariantType::Float, 5.f, {"Coarse step during track propagation"}}, + {"fine-step", VariantType::Float, 2.f, {"Fine step during track propagation"}}, + {"mX-coarse", VariantType::Float, 40.f, {"Perform coarse propagation up to this mx"}}, + {"max-tracks", VariantType::Int, -1, {"Number of maximum tracks to process"}}, + {"cut-DCA-median", VariantType::Float, 3.f, {"Cut on the DCA: abs(DCA-medianDCA) +#include "TPCWorkflow/TPCTimeSeriesWriterSpec.h" +#include "TPCWorkflow/TPCTimeSeriesSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "CommonDataFormat/TFIDInfo.h" + +#include "DetectorsCalibration/IntegratedClusterCalibrator.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tpc +{ +template +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; + +DataProcessorSpec getTPCTimeSeriesWriterSpec() +{ + return MakeRootTreeWriterSpec("tpc-time-series-writer", + "o2_timeseries_tpc.root", + "treeTimeSeries", + BranchDefinition{InputSpec{"timeseries", o2::header::gDataOriginTPC, getDataDescriptionTimeSeries(), 0}, "TimeSeries", 1}, + BranchDefinition{InputSpec{"itpctfid", o2::header::gDataOriginTPC, getDataDescriptionTPCTimeSeriesTFId(), 0}, "tfID", 1})(); +} + +} // namespace tpc +} // namespace o2 diff --git a/Detectors/TPC/workflow/src/time-series-merge-integrator.cxx b/Detectors/TPC/workflow/src/time-series-merge-integrator.cxx new file mode 100644 index 0000000000000..c17b68e307328 --- /dev/null +++ b/Detectors/TPC/workflow/src/time-series-merge-integrator.cxx @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCWorkflow/TPCMergeTimeSeriesSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +void customize(std::vector& workflowOptions) +{ + std::vector options{ + ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + }; + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); + wf.emplace_back(o2::tpc::getTPCMergeTimeSeriesSpec()); + return wf; +} diff --git a/Detectors/TPC/workflow/src/time-series-reader.cxx b/Detectors/TPC/workflow/src/time-series-reader.cxx new file mode 100644 index 0000000000000..ccedbdf4f9599 --- /dev/null +++ b/Detectors/TPC/workflow/src/time-series-reader.cxx @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "TPCWorkflow/TPCTimeSeriesReaderSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec wf; + wf.emplace_back(o2::tpc::getTPCTimeSeriesReaderSpec()); + return wf; +} diff --git a/Detectors/TPC/workflow/src/tpc-time-series.cxx b/Detectors/TPC/workflow/src/tpc-time-series.cxx new file mode 100644 index 0000000000000..e6ce77a1227cc --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-time-series.cxx @@ -0,0 +1,48 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file tpc-time-series.cxx +/// \author Matthias Kleiner, mkleiner@ikf.uni-frankfurt.de + +#include "TPCWorkflow/TPCTimeSeriesSpec.h" +#include "TPCWorkflow/TPCTimeSeriesWriterSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "TPCReaderWorkflow/TPCSectorCompletionPolicy.h" +#include "Framework/ConfigParamSpec.h" +#include "GPUDebugStreamer.h" + +using namespace o2::framework; + +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + std::vector options{ + ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + {"disable-root-output", VariantType::Bool, false, {"disable root-files output writers"}}, + {"material-type", VariantType::Int, 2, {"Type for the material budget during track propagation: 0=None, 1=Geo, 2=LUT"}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + WorkflowSpec workflow; + o2::conf::ConfigurableParam::updateFromString(config.options().get("configKeyValues")); + const bool disableWriter = config.options().get("disable-root-output"); + auto materialType = static_cast(config.options().get("material-type")); + workflow.emplace_back(o2::tpc::getTPCTimeSeriesSpec(disableWriter, materialType)); + if (!disableWriter) { + workflow.emplace_back(o2::tpc::getTPCTimeSeriesWriterSpec()); + } + return workflow; +} From 705b8bf767c3b3ddad150ff8d2b18f83324dbc60 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 11 Oct 2023 00:04:20 +0200 Subject: [PATCH 255/324] DPL: If in OnlineMode, input proxies should only send EoS if they receive it --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index dff5a75e6c755..5f640863e016c 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -29,6 +29,8 @@ #include "Framework/TimingInfo.h" #include "Framework/DeviceState.h" #include "Framework/Monitoring.h" +#include "Framework/DefaultsHelpers.h" +#include "Framework/DataTakingContext.h" #include "Headers/DataHeader.h" #include "Headers/Stack.h" #include "DecongestionService.h" @@ -52,6 +54,8 @@ namespace o2::framework { +static bool gAllowEoSdefault = !(DefaultsHelpers::deploymentMode() == DeploymentMode::OnlineDDS || DefaultsHelpers::deploymentMode() == DeploymentMode::OnlineECS); +static bool gAllowEoS = gAllowEoSdefault; using DataHeader = o2::header::DataHeader; @@ -793,6 +797,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, if (newRun) { std::fill(numberOfEoS.begin(), numberOfEoS.end(), 0); std::fill(eosPeersCount.begin(), eosPeersCount.end(), 0); + gAllowEoS = gAllowEoSdefault; } if (numberOfEoS[ci]) { eosPeersCount[ci] = std::max(eosPeersCount[ci], device->GetNumberOfConnectedPeers(channel)); @@ -813,6 +818,8 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, bool everyEoS = shouldstop || (numberOfEoS[ci] >= eosPeersCount[ci] && nEos); if (everyEoS) { + LOG(info) << "Received " << numberOfEoS[ci] << " end-of-stream from " << eosPeersCount[ci] << " peers, forwarding end-of-stream (shouldstop " << (int)shouldstop << ", nEos " << nEos << ", newRun " << (int)newRun << ")"; + gAllowEoS = true; // Mark all input channels as closed for (auto& info : deviceState->inputChannelInfos) { info.state = InputChannelState::Completed; @@ -940,6 +947,9 @@ DataProcessorSpec specifyFairMQDeviceOutputProxy(char const* name, // DPL implements an internal end of stream signal, which is propagated through // all downstream channels if a source is dry, make it available to other external // devices via a message of type {DPL/EOS/0} + if (!gAllowEoS) { + return; + } for (auto& channelInfo : device->GetChannels()) { auto& channelName = channelInfo.first; if (channelName != outputChannelName) { From 80963c9c5c003da45091d40284bbc6b4bb5acf56 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 11 Oct 2023 01:19:40 +0200 Subject: [PATCH 256/324] DPL: Should not set newRun flag with incoming runNumber 0, as is the case e.g. with EoS messages --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 5f640863e016c..55d43747e28a4 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -856,7 +856,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, auto const dh = o2::header::get(parts.At(0)->GetData()); auto& timingInfo = ctx.services().get(); if (dh != nullptr) { - if (currentRunNumber != -1 && dh->runNumber != currentRunNumber) { + if (currentRunNumber != -1 && dh->runNumber != 0 && dh->runNumber != currentRunNumber) { newRun = true; inStopTransition = false; } From d932b1f4fbf23e3203859a66816c8ab2510fb431 Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Wed, 11 Oct 2023 17:24:04 +0200 Subject: [PATCH 257/324] Protection against bogus TRD PH values --- DataFormats/Detectors/TRD/include/DataFormatsTRD/PHData.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/PHData.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/PHData.h index dbbc3161f9b02..b8873a5247d03 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/PHData.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/PHData.h @@ -42,7 +42,7 @@ class PHData void set(int adc, int det, int tb, int nb, int type) { - mData = (type << 30) | (nb << 27) | (tb << 22) | (det << 12) | adc; + mData = ((type & 0x3) << 30) | ((nb & 0x7) << 27) | ((tb & 0x1f) << 22) | ((det & 0x3ff) << 12) | (adc & 0xfff); } // the ADC sum for given time bin for up to three neighbours From d19409fcf271c686495a5efde007b9b5c9b04d4d Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Fri, 13 Oct 2023 10:28:00 +0200 Subject: [PATCH 258/324] DPL Analysis: correctly account for extended table version with aod-spawner (#12056) --- Framework/Core/src/AODReaderHelpers.cxx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Framework/Core/src/AODReaderHelpers.cxx b/Framework/Core/src/AODReaderHelpers.cxx index e8e9700a8f519..28b1c65f7def2 100644 --- a/Framework/Core/src/AODReaderHelpers.cxx +++ b/Framework/Core/src/AODReaderHelpers.cxx @@ -147,7 +147,7 @@ AlgorithmSpec AODReaderHelpers::indexBuilderCallback(std::vector& req AlgorithmSpec AODReaderHelpers::aodSpawnerCallback(std::vector& requested) { - return AlgorithmSpec::InitCallback{[requested](InitContext& ic) { + return AlgorithmSpec::InitCallback{[requested](InitContext& /*ic*/) { return [requested](ProcessingContext& pc) { auto outputs = pc.outputs(); // spawn tables @@ -184,9 +184,11 @@ AlgorithmSpec AODReaderHelpers::aodSpawnerCallback(std::vector& reque } else if (description == header::DataDescription{"FWDTRACKCOV"}) { outputs.adopt(Output{origin, description, version}, maker(o2::aod::FwdTracksCovExtensionMetadata{})); } else if (description == header::DataDescription{"MCPARTICLE"}) { - outputs.adopt(Output{origin, description, version}, maker(o2::aod::McParticles_000ExtensionMetadata{})); - } else if (description == header::DataDescription{"MCPARTICLE_001"}) { - outputs.adopt(Output{origin, description, version}, maker(o2::aod::McParticles_001ExtensionMetadata{})); + if (version == 0U) { + outputs.adopt(Output{origin, description, version}, maker(o2::aod::McParticles_000ExtensionMetadata{})); + } else if (version == 1U) { + outputs.adopt(Output{origin, description, version}, maker(o2::aod::McParticles_001ExtensionMetadata{})); + } } else { throw runtime_error("Not an extended table"); } From 0053e56eb6de5a6ce03906402b3579bf9932ce5d Mon Sep 17 00:00:00 2001 From: noferini Date: Thu, 12 Oct 2023 19:40:39 +0200 Subject: [PATCH 259/324] adding paranoid flag in tof-compressor on epn --- prodtests/full-system-test/dpl-workflow.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 40a290e918ef4..fdcdac651ae1a 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -443,7 +443,7 @@ if [[ $CTFINPUT == 0 && $DIGITINPUT == 0 ]]; then has_detector FV0 && ! has_detector_from_global_reader FV0 && ! has_detector_flp_processing FV0 && add_W o2-fv0-flp-dpl-workflow "$DISABLE_ROOT_OUTPUT --pipeline $(get_N fv0-datareader-dpl FV0 RAW 1)" has_detector MID && ! has_detector_from_global_reader MID && add_W o2-mid-raw-to-digits-workflow "$MIDDEC_CONFIG --pipeline $(get_N MIDRawDecoder MID RAW 1),$(get_N MIDDecodedDataAggregator MID RAW 1)" has_detector MCH && ! has_detector_from_global_reader MCH && add_W o2-mch-raw-to-digits-workflow "--pipeline $(get_N mch-data-decoder MCH RAW 1)" - has_detector TOF && ! has_detector_from_global_reader TOF && ! has_detector_flp_processing TOF && add_W o2-tof-compressor "--pipeline $(get_N tof-compressor-0 TOF RAW 1)" + has_detector TOF && ! has_detector_from_global_reader TOF && ! has_detector_flp_processing TOF && add_W o2-tof-compressor "--tof-compressor-paranoid --pipeline $(get_N tof-compressor-0 TOF RAW 1)" has_detector FDD && ! has_detector_from_global_reader FDD && ! has_detector_flp_processing FDD && add_W o2-fdd-flp-dpl-workflow "$DISABLE_ROOT_OUTPUT --pipeline $(get_N fdd-datareader-dpl FDD RAW 1)" has_detector TRD && ! has_detector_from_global_reader TRD && add_W o2-trd-datareader "$DISABLE_ROOT_OUTPUT --sortDigits --pipeline $(get_N trd-datareader TRD RAW 1 TRDRAWDEC)" "" 0 has_detector ZDC && ! has_detector_from_global_reader ZDC && add_W o2-zdc-raw2digits "$DISABLE_ROOT_OUTPUT --pipeline $(get_N zdc-datareader-dpl ZDC RAW 1)" From 451c92cd1e40aabd5999997a791bfa156fbaa902 Mon Sep 17 00:00:00 2001 From: cortesep <57937610+cortesep@users.noreply.github.com> Date: Fri, 13 Oct 2023 10:53:57 +0200 Subject: [PATCH 260/324] ZDC Small fixes and improved printout in waveform calibration (#11900) * Better printout and fixes * WIP * Fixes and cleanup * Improved raw data debugging * Reduce output size in waveform calibration * Update in debug * Update in debug * Updated printout * Fixes * Please consider the following formatting changes (#82) * Fix inversion of cuts --------- Co-authored-by: ALICE Builder --- .../include/ZDCCalib/WaveformCalibData.h | 7 ++ .../calib/include/ZDCCalib/WaveformCalibEPN.h | 5 +- .../include/ZDCCalib/WaveformCalibQueue.h | 1 + .../ZDC/calib/src/BaselineCalibConfig.cxx | 4 +- Detectors/ZDC/calib/src/InterCalibConfig.cxx | 4 +- Detectors/ZDC/calib/src/TDCCalibConfig.cxx | 4 +- .../ZDC/calib/src/WaveformCalibConfig.cxx | 8 +-- Detectors/ZDC/calib/src/WaveformCalibData.cxx | 26 +++++-- Detectors/ZDC/calib/src/WaveformCalibEPN.cxx | 19 ++++- .../ZDC/calib/src/WaveformCalibEPNSpec.cxx | 3 + .../ZDC/calib/src/WaveformCalibQueue.cxx | 71 ++++++++++++++----- Detectors/ZDC/macro/CreateRecoConfigZDC.C | 20 +++--- .../ZDC/macro/CreateWaveformCalibConfig.C | 19 ++++- Detectors/ZDC/raw/include/ZDCRaw/DumpRaw.h | 1 + Detectors/ZDC/raw/src/DumpRaw.cxx | 29 +++++++- .../include/ZDCReconstruction/DigiReco.h | 1 + .../include/ZDCReconstruction/RecoParamZDC.h | 9 +-- Detectors/ZDC/reconstruction/src/DigiReco.cxx | 14 ++-- .../ZDC/reconstruction/src/RecoConfigZDC.cxx | 11 ++- Detectors/ZDC/workflow/src/DigitRecoSpec.cxx | 4 +- 20 files changed, 201 insertions(+), 59 deletions(-) diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibData.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibData.h index 87bb6886f7cad..2818146d75f32 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibData.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibData.h @@ -59,12 +59,18 @@ struct WaveformCalibData { inline void setFirstValid(int isig, int ipos) { if (ipos > mWave[isig].mFirstValid) { +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + printf("WaveformCalibChData::%s isig=%-2d mFirstValid %5d -> %5d\n", __func__, isig, mWave[isig].mFirstValid, ipos); +#endif mWave[isig].mFirstValid = ipos; } } inline void setLastValid(int isig, int ipos) { if (ipos < mWave[isig].mLastValid) { +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + printf("WaveformCalibChData::%s isig=%-2d mLastValid %5d -> %5d\n", __func__, isig, mWave[isig].mLastValid, ipos); +#endif mWave[isig].mLastValid = ipos; } } @@ -77,6 +83,7 @@ struct WaveformCalibData { int getLastValid(int is) const; void print() const; void clear(); + void clearWaveforms(); void setCreationTime(uint64_t ctime); void setN(int n); int saveDebugHistos(const std::string fn); diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPN.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPN.h index b759d94ff781a..929190f09d162 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPN.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPN.h @@ -29,7 +29,7 @@ class WaveformCalibEPN public: WaveformCalibEPN() = default; int init(); - void clear(int ih = -1); + void clear(); int process(const gsl::span& bcrec, const gsl::span& energy, const gsl::span& tdc, @@ -54,7 +54,7 @@ class WaveformCalibEPN int mFirst = 0; int mLast = 0; - int mN = 1; + int mN = 10; void configure(int ifirst, int ilast) { @@ -64,6 +64,7 @@ class WaveformCalibEPN mFirst = ifirst; mLast = ilast; mN = ilast - ifirst + 1; + LOG(info) << "WaveformCalibEPN::" << __func__ << " mN=" << mN << "[" << mFirst << ":" << mLast << "]"; } WaveformCalibQueue mQueue; diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibQueue.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibQueue.h index a18f23fab7ea8..20d39b6fdb8ce 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibQueue.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibQueue.h @@ -47,6 +47,7 @@ struct WaveformCalibQueue { int mNP = 0; // Number of interpolated points in waveform int mTimeLow[NChannels]; /// Cut on position difference low int mTimeHigh[NChannels]; /// Cut on position difference high + int mVerbosity = 0; const WaveformCalibConfig* mCfg = nullptr; diff --git a/Detectors/ZDC/calib/src/BaselineCalibConfig.cxx b/Detectors/ZDC/calib/src/BaselineCalibConfig.cxx index ac462250d20e6..ad9b889bd7d10 100644 --- a/Detectors/ZDC/calib/src/BaselineCalibConfig.cxx +++ b/Detectors/ZDC/calib/src/BaselineCalibConfig.cxx @@ -83,6 +83,6 @@ void BaselineCalibConfig::setCuts(int low, int high) void BaselineCalibConfig::setCuts(int isig, int low, int high) { - cutHigh[isig] = low; - cutLow[isig] = high; + cutLow[isig] = low; + cutHigh[isig] = high; } diff --git a/Detectors/ZDC/calib/src/InterCalibConfig.cxx b/Detectors/ZDC/calib/src/InterCalibConfig.cxx index c351cb31cf3c9..d0caff4c97d40 100644 --- a/Detectors/ZDC/calib/src/InterCalibConfig.cxx +++ b/Detectors/ZDC/calib/src/InterCalibConfig.cxx @@ -106,8 +106,8 @@ void InterCalibConfig::setCuts(double low, double high) void InterCalibConfig::setCuts(int ih, double low, double high) { - cutHigh[ih] = low; - cutLow[ih] = high; + cutLow[ih] = low; + cutHigh[ih] = high; } void InterCalibConfig::setBinning1D(int nb, double amin, double amax) diff --git a/Detectors/ZDC/calib/src/TDCCalibConfig.cxx b/Detectors/ZDC/calib/src/TDCCalibConfig.cxx index 7ca0254161ec9..d2bbbefb39abc 100644 --- a/Detectors/ZDC/calib/src/TDCCalibConfig.cxx +++ b/Detectors/ZDC/calib/src/TDCCalibConfig.cxx @@ -106,8 +106,8 @@ void TDCCalibConfig::setCuts(double low, double high) void TDCCalibConfig::setCuts(int ih, double low, double high) { - cutHigh[ih] = low; - cutLow[ih] = high; + cutLow[ih] = low; + cutHigh[ih] = high; } void TDCCalibConfig::setBinning1D(int nb, double amin, double amax) diff --git a/Detectors/ZDC/calib/src/WaveformCalibConfig.cxx b/Detectors/ZDC/calib/src/WaveformCalibConfig.cxx index fa0a5a78b3fcb..f0aeff5d53fc7 100644 --- a/Detectors/ZDC/calib/src/WaveformCalibConfig.cxx +++ b/Detectors/ZDC/calib/src/WaveformCalibConfig.cxx @@ -21,8 +21,8 @@ WaveformCalibConfig::WaveformCalibConfig() cutHigh[isig] = std::numeric_limits::infinity(); } for (int itdc = 0; itdc < NTDCChannels; itdc++) { - cutTimeLow[itdc] = -2.5; - cutTimeHigh[itdc] = 2.5; + cutTimeLow[itdc] = -1.25; + cutTimeHigh[itdc] = 1.25; } } @@ -132,8 +132,8 @@ void WaveformCalibConfig::setCuts(double low, double high) void WaveformCalibConfig::setCuts(int isig, double low, double high) { - cutHigh[isig] = low; - cutLow[isig] = high; + cutLow[isig] = low; + cutHigh[isig] = high; } void WaveformCalibConfig::setTimeCuts(double low, double high) diff --git a/Detectors/ZDC/calib/src/WaveformCalibData.cxx b/Detectors/ZDC/calib/src/WaveformCalibData.cxx index 14063f9e93f40..759d85a6a0f88 100644 --- a/Detectors/ZDC/calib/src/WaveformCalibData.cxx +++ b/Detectors/ZDC/calib/src/WaveformCalibData.cxx @@ -59,9 +59,15 @@ WaveformCalibChData& WaveformCalibChData::operator+=(const WaveformCalibChData& { if (other.mEntries > 0) { if (other.mFirstValid > mFirstValid) { +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + printf("WaveformCalibChData::+= mFirstValid %5d -> %5d\n", mFirstValid, other.mFirstValid); +#endif mFirstValid = other.mFirstValid; } if (other.mLastValid < mLastValid) { +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + printf("WaveformCalibChData::+= mLastValid %5d -> %5d\n", mLastValid, other.mLastValid); +#endif mLastValid = other.mLastValid; } mEntries = mEntries + other.mEntries; @@ -130,23 +136,23 @@ int WaveformCalibChData::getLastValid() const //______________________________________________________________________________ void WaveformCalibData::setN(int n) { - if (n >= 0 && n < NBT) { + if (n > 0 && n <= NBT) { mN = n; for (int is = 0; is < NChannels; is++) { mWave[is].setN(n); } } else { - LOG(fatal) << "WaveformCalibData " << __func__ << " wrong stored b.c. setting " << n << " not in range [0:" << NBT << "]"; + LOG(warn) << "WaveformCalibData " << __func__ << " wrong stored b.c. setting " << n << " not in range [1:" << NBT << "]"; } } void WaveformCalibChData::setN(int n) { - if (n >= 0 && n < NBT) { + if (n > 0 && n <= NBT) { mFirstValid = 0; mLastValid = n * NTimeBinsPerBC * TSN - 1; } else { - LOG(fatal) << "WaveformCalibChData " << __func__ << " wrong stored b.c. setting " << n << " not in range [0:" << NBT << "]"; + LOG(warn) << "WaveformCalibChData " << __func__ << " wrong stored b.c. setting " << n << " not in range [1:" << NBT << "]"; } } @@ -172,6 +178,8 @@ int WaveformCalibData::saveDebugHistos(const std::string fn) } h.SetEntries(mWave[is].mEntries); h.Write("", TObject::kOverwrite); + } else { + LOG(warn) << "WaveformCalibData " << __func__ << " waveform for ch " << is << " has too few entries: " << mWave[is].mEntries; } } f->Close(); @@ -191,6 +199,16 @@ void WaveformCalibData::clear() } } +//______________________________________________________________________________ +void WaveformCalibData::clearWaveforms() +{ + mCTimeBeg = 0; + mCTimeEnd = 0; + for (int32_t is = 0; is < NChannels; is++) { + mWave[is].clear(); + } +} + void WaveformCalibChData::clear() { mEntries = 0; diff --git a/Detectors/ZDC/calib/src/WaveformCalibEPN.cxx b/Detectors/ZDC/calib/src/WaveformCalibEPN.cxx index 37590995d9701..cda158e9f5b6a 100644 --- a/Detectors/ZDC/calib/src/WaveformCalibEPN.cxx +++ b/Detectors/ZDC/calib/src/WaveformCalibEPN.cxx @@ -45,17 +45,29 @@ int WaveformCalibEPN::init() if (mVerbosity > DbgZero) { mQueue.printConf(); } + mQueue.mVerbosity = mVerbosity; // number of bins - mNBin = cfg->nbun * TSN; + mNBin = cfg->nbun * TSN * NTimeBinsPerBC; mFirst = cfg->ibeg; mLast = cfg->iend; mData.setN(cfg->nbun); mData.mPeak = mQueue.mPeak; + LOGF(info, "o2::zdc::WaveformCalibEPN::%s mNBin=%d mFirst=%d mLast=%d mN=%d mPeak=%d", __func__, mNBin, mFirst, mLast, cfg->nbun, mData.mPeak); mInitDone = true; return 0; } +void WaveformCalibEPN::clear() +{ +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOG(info) << "o2::zdc::WaveformCalibEPN::" << __func__; +#endif + // mQueue.clear(); + mData.clearWaveforms(); + mData.setN(mN); +} + //______________________________________________________________________________ int WaveformCalibEPN::process(const gsl::span& RecBC, const gsl::span& Energy, @@ -111,9 +123,10 @@ int WaveformCalibEPN::endOfRun() LOGF(info, "WaveformCalibEPN::endOfRun ts (%llu:%llu)", mData.mCTimeBeg, mData.mCTimeEnd); for (int is = 0; is < NChannels; is++) { if (mData.getEntries(is) > 0) { - LOGF(info, "Waveform %2d %s with %10d events and cuts AMP:(%g:%g) TDC:(%g:%g) Valid:[%d:%d:%d]", is, ChannelNames[is].data(), + int itdc = SignalTDC[is]; + LOGF(info, "Waveform %2d %s with %10d events and cuts AMP:(%g:%g) TDC:%d:(%g:%g) Valid:[%d:%d:%d]", is, ChannelNames[is].data(), mData.getEntries(is), mConfig->cutLow[is], mConfig->cutHigh[is], - mConfig->cutTimeLow[is], mConfig->cutTimeHigh[is], + itdc, mConfig->cutTimeLow[itdc], mConfig->cutTimeHigh[itdc], mData.getFirstValid(is), mData.mPeak, mData.getLastValid(is)); } } diff --git a/Detectors/ZDC/calib/src/WaveformCalibEPNSpec.cxx b/Detectors/ZDC/calib/src/WaveformCalibEPNSpec.cxx index d90f26d341515..62ee862905524 100644 --- a/Detectors/ZDC/calib/src/WaveformCalibEPNSpec.cxx +++ b/Detectors/ZDC/calib/src/WaveformCalibEPNSpec.cxx @@ -88,10 +88,13 @@ void WaveformCalibEPNSpec::run(ProcessingContext& pc) mTimer.Stop(); mTimer.Reset(); mTimer.Start(false); + } else { + mWorker.clear(); } auto creationTime = pc.services().get().creation; // approximate time in ms WaveformCalibData& data = mWorker.getData(); + data.setCreationTime(creationTime); auto bcrec = pc.inputs().get>("bcrec"); diff --git a/Detectors/ZDC/calib/src/WaveformCalibQueue.cxx b/Detectors/ZDC/calib/src/WaveformCalibQueue.cxx index 25d48d9cbf825..c62306f21b1ad 100644 --- a/Detectors/ZDC/calib/src/WaveformCalibQueue.cxx +++ b/Detectors/ZDC/calib/src/WaveformCalibQueue.cxx @@ -52,6 +52,9 @@ uint32_t WaveformCalibQueue::append(RecEventFlat& ev) auto& last = mIR.back(); // If BC are not consecutive, clear queue if (toadd.differenceInBC(last) > 1) { +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOG(info) << "WaveformCalibQueue::" << __func__ << " gap detected. Clearing " << mIR.size() << " bc"; +#endif clear(); } // If queue is not empty and is too long remove first element @@ -61,6 +64,9 @@ uint32_t WaveformCalibQueue::append(RecEventFlat& ev) // If BC are consecutive or cleared queue append element appendEv(ev); if (mIR.size() == mN) { +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOG(info) << "WaveformCalibQueue::" << __func__ << " processing " << mIR.size() << " bcs"; +#endif uint32_t mask = 0; for (int32_t itdc = 0; itdc < NTDCChannels; itdc++) { // Check which channels satisfy the condition on TDC @@ -92,6 +98,9 @@ uint32_t WaveformCalibQueue::append(RecEventFlat& ev) } return mask; } else { + // #ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + // LOG(info) << "WaveformCalibQueue::" << __func__ << " IR size = " << mIR.size() << " != " << mN; + // #endif return 0; } } @@ -182,7 +191,7 @@ int WaveformCalibQueue::hasData(int isig, const gsl::span mTimeHigh[itdc]) { - // Put a warning message for a signal out of time - LOGF(warning, "%d.%04d Signal %2d peak position %d-%d=%d is outside allowed range [%d:%d]", mIR[mPk].orbit, mIR[mPk].bc, isig, ppos, mPeak, ppos - mPeak, mTimeLow[isig], mTimeHigh[isig]); + if (mVerbosity > DbgMinimal) { + // Put a warning message for a signal out of time + LOGF(warning, "%d.%04d Signal %2d peak position %d-%d=%d is outside allowed range [%d:%d]", mIR[mPk].orbit, mIR[mPk].bc, isig, ppos, mPeak, ppos - mPeak, mTimeLow[isig], mTimeHigh[isig]); + } return -1; } } @@ -277,7 +291,7 @@ int WaveformCalibQueue::addData(int isig, const gsl::span 0) { + if (!printed) { + printf("mNTDC:"); + printed = true; + } printf(" %2d=%6u", j, mNTDC[j][i]); } } - printf("\n"); - printf("mTDCA:"); + if (printed) { + printf("\n"); + printed = false; + } for (int j = 0; j < NTDCChannels; j++) { if (mNTDC[j][i] > 0) { + if (!printed) { + printf("mTDCA:"); + printed = true; + } printf(" %2d=%6.1f", j, mTDCA[j][i]); } } - printf("\n"); - printf("mTDCP:"); + if (printed) { + printf("\n"); + printed = false; + } for (int j = 0; j < NTDCChannels; j++) { if (mNTDC[j][i] > 0) { + if (!printed) { + printf("mTDCP:"); + printed = true; + } printf(" %2d=%6.1f", j, mTDCP[j][i]); } } - printf("\n"); + if (printed) { + printf("\n"); + } } } diff --git a/Detectors/ZDC/macro/CreateRecoConfigZDC.C b/Detectors/ZDC/macro/CreateRecoConfigZDC.C index 30808371bcff2..c504241346787 100644 --- a/Detectors/ZDC/macro/CreateRecoConfigZDC.C +++ b/Detectors/ZDC/macro/CreateRecoConfigZDC.C @@ -33,16 +33,16 @@ void CreateRecoConfigZDC(long tmin = 0, long tmax = -1, std::string ccdbHost = " // Offline trigger // Set trigger bitsincoincidence to ignore dead channels - // conf.setBit(IdZNAC); - // conf.setBit(IdZNASum); - // conf.setBit(IdZPAC); - // conf.setBit(IdZPASum); - // conf.setBit(IdZEM1); - // conf.setBit(IdZEM2); - // conf.setBit(IdZNCC); - // conf.setBit(IdZNCSum); - // conf.setBit(IdZPCC); - // conf.setBit(IdZPCSum); + // conf.setBit(TDCZNAC); + // conf.setBit(TDCZNAS); + // conf.setBit(TDCZPAC); + // conf.setBit(TDCZPAS); + // conf.setBit(TDCZEM1); + // conf.setBit(TDCZEM2); + // conf.setBit(TDCZNCC); + // conf.setBit(TDCZNCS); + // conf.setBit(TDCZPCC); + // conf.setBit(TDCZPCS); // conf.setTripleTrigger(); conf.setDoubleTrigger(); diff --git a/Detectors/ZDC/macro/CreateWaveformCalibConfig.C b/Detectors/ZDC/macro/CreateWaveformCalibConfig.C index 7c19eef5bbd64..fbe1063b0933d 100644 --- a/Detectors/ZDC/macro/CreateWaveformCalibConfig.C +++ b/Detectors/ZDC/macro/CreateWaveformCalibConfig.C @@ -13,6 +13,7 @@ #include #include +#include #include "Framework/Logger.h" #include "CCDB/CcdbApi.h" #include "ZDCBase/Constants.h" @@ -38,13 +39,29 @@ void CreateWaveformCalibConfig(long tmin = 0, long tmax = -1, std::string ccdbHo // range -2048 : 2047 one should not use signals too close to // maximum allowed amplitude (1800+2048) conf.setCuts(100, 3000); + conf.setCuts(o2::zdc::IdZNA1, 100, 2500); + conf.setCuts(o2::zdc::IdZNA2, 100, 2500); + conf.setCuts(o2::zdc::IdZNA3, 100, 2500); + conf.setCuts(o2::zdc::IdZNA4, 100, 2500); + conf.setCuts(o2::zdc::IdZPA1, 50, 2500); + conf.setCuts(o2::zdc::IdZPA2, 100, 2500); + conf.setCuts(o2::zdc::IdZPA3, 100, 2500); + conf.setCuts(o2::zdc::IdZPA4, 100, 2500); + conf.setCuts(o2::zdc::IdZNC1, 100, 2500); + conf.setCuts(o2::zdc::IdZNC2, 100, 2500); + conf.setCuts(o2::zdc::IdZNC3, 100, 2500); + conf.setCuts(o2::zdc::IdZNC4, 100, 2500); + conf.setCuts(o2::zdc::IdZPC1, 100, 2500); + conf.setCuts(o2::zdc::IdZPC2, 100, 2500); + conf.setCuts(o2::zdc::IdZPC3, 100, 2500); + conf.setCuts(o2::zdc::IdZPC4, 50, 2500); conf.setDescription("Simulated data"); conf.setMinEntries(200); // Restrict waveform range (default is -3, 6 as defined in WaveformCalib_NBB // WaveformCalib_NBA in file Detectors/ZDC/base/include/ZDCBase/Constants.h) - conf.restrictRange(-1, 0); + // conf.restrictRange(-1, 0); conf.print(); diff --git a/Detectors/ZDC/raw/include/ZDCRaw/DumpRaw.h b/Detectors/ZDC/raw/include/ZDCRaw/DumpRaw.h index 11da9a96533cf..41158552d86cb 100644 --- a/Detectors/ZDC/raw/include/ZDCRaw/DumpRaw.h +++ b/Detectors/ZDC/raw/include/ZDCRaw/DumpRaw.h @@ -54,6 +54,7 @@ class DumpRaw std::unique_ptr mCounts[NDigiChannels] = {nullptr}; std::unique_ptr mSignalA[NDigiChannels] = {nullptr}; std::unique_ptr mSignalT[NDigiChannels] = {nullptr}; + std::unique_ptr mSignalTH[NDigiChannels] = {nullptr}; std::unique_ptr mBunchA[NDigiChannels] = {nullptr}; // Bunch pattern ALICE std::unique_ptr mBunchT[NDigiChannels] = {nullptr}; // Bunch pattern Autotrigger std::unique_ptr mBunchH[NDigiChannels] = {nullptr}; // Bunch pattern Hit diff --git a/Detectors/ZDC/raw/src/DumpRaw.cxx b/Detectors/ZDC/raw/src/DumpRaw.cxx index 3a2cfd79f9ccb..7375c946fb3e3 100644 --- a/Detectors/ZDC/raw/src/DumpRaw.cxx +++ b/Detectors/ZDC/raw/src/DumpRaw.cxx @@ -133,6 +133,11 @@ void DumpRaw::init() TString htit = TString::Format("Signal mod. %d ch. %d AUTOT; Sample; ADC", imod, ich); mSignalT[i] = std::make_unique(hname, htit, nbx, xmin, xmax, ADCRange, ADCMin - 0.5, ADCMax + 0.5); } + if (mSignalTH[i] == nullptr) { + TString hname = TString::Format("hsth%d%d", imod, ich); + TString htit = TString::Format("Signal mod. %d ch. %d AUTOT & Hit; Sample; ADC", imod, ich); + mSignalTH[i] = std::make_unique(hname, htit, 2 * NTimeBinsPerBC, -0.5 - NTimeBinsPerBC, NTimeBinsPerBC - 0.5, ADCRange, ADCMin - 0.5, ADCMax + 0.5); + } if (mBunchA[i] == nullptr) { TString hname = TString::Format("hba%d%d", imod, ich); TString htit = TString::Format("Bunch mod. %d ch. %d ALICET; Sample; ADC", imod, ich); @@ -203,6 +208,10 @@ void DumpRaw::write() setStat(mSignalT[i].get()); mSignalT[i]->Write(); } + if (mSignalTH[i] && mSignalTH[i]->GetEntries() > 0) { + setStat(mSignalTH[i].get()); + mSignalTH[i]->Write(); + } } mTransmitted->Write(); mFired->Write(); @@ -279,11 +288,11 @@ int DumpRaw::process(const EventChData& ch) // Not empty event auto f = ch.f; int ih = getHPos(f.board, f.ch); - if (ih < 0) { + if (ih < 0 || ih >= NDigiChannels) { return -1; } - if (mVerbosity > 0) { + if (mVerbosity > 1) { for (int32_t iw = 0; iw < NWPerBc; iw++) { Digits2Raw::print_gbt_word(ch.w[iw]); } @@ -294,6 +303,10 @@ int DumpRaw::process(const EventChData& ch) mFired->Fill(f.board, f.ch); } + static int16_t prev_s[NDigiChannels][NTimeBinsPerBC] = {0}; + static uint32_t prev_orbit[NDigiChannels] = {0}; + static uint16_t prev_bc[NDigiChannels] = {0}; + uint16_t us[12]; int16_t s[12]; us[0] = f.s00; @@ -386,6 +399,12 @@ int DumpRaw::process(const EventChData& ch) mBits->Fill(ih, 2); if (f.Hit) { mBitsH->Fill(ih, 2); + if ((prev_orbit[ih] == f.orbit && (f.bc - prev_bc[ih]) == 1) || ((f.orbit - prev_orbit[ih]) == 1 && prev_bc[ih] == 3563 && f.bc == 0)) { + for (int32_t i = 0; i < 12; i++) { + mSignalTH[ih]->Fill(i + 0., double(s[i])); + mSignalTH[ih]->Fill(i - NTimeBinsPerBC + 0., double(prev_s[ih][i])); + } + } } for (int32_t i = 0; i < 12; i++) { mSignalT[ih]->Fill(i + 0., double(s[i])); @@ -429,6 +448,12 @@ int DumpRaw::process(const EventChData& ch) mError->Fill(ih); } } + // Save information to process next bunch crossing + prev_orbit[ih] = f.orbit; + prev_bc[ih] = f.bc; + for (int32_t i = 0; i < 12; i++) { + prev_s[ih][i] = s[i]; + } return 0; } diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiReco.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiReco.h index 32368791f9817..f611da568b2a8 100644 --- a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiReco.h +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiReco.h @@ -157,6 +157,7 @@ class DigiReco bool mLowPassFilterSet = false; /// Low pass filtering set via function call bool mFullInterpolation = false; /// Full waveform interpolation bool mFullInterpolationSet = false; /// Full waveform interpolation set via function call + int mFullInterpolationMinLength = 2; /// Minimum length to perform full interpolation int mInterpolationStep = 25; /// Coarse interpolation step bool mCorrSignal = true; /// Enable TDC signal correction bool mCorrSignalSet = false; /// TDC signal correction set via function call diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoParamZDC.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoParamZDC.h index 79b6bca3b1bc4..fe5652da6fc15 100644 --- a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoParamZDC.h +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoParamZDC.h @@ -33,10 +33,11 @@ struct RecoParamZDC : public o2::conf::ConfigurableParamHelper { uint8_t triggerCondition = 0x0; // Trigger condition: 0x1 single, 0x3 double and 0x7 triple // Signal processing - int low_pass_filter = -1; // Low pass filtering - int full_interpolation = -1; // Full interpolation of waveform - int corr_signal = -1; // TDC signal correction - int corr_background = -1; // TDC pile-up correction + int low_pass_filter = -1; // Low pass filtering + int full_interpolation = -1; // Full interpolation of waveform + int full_interpolation_min_length = -1; // Minimum length to perform full interpolation + int corr_signal = -1; // TDC signal correction + int corr_background = -1; // TDC pile-up correction int debug_output = -1; // Debug output diff --git a/Detectors/ZDC/reconstruction/src/DigiReco.cxx b/Detectors/ZDC/reconstruction/src/DigiReco.cxx index 136588cd0fdf4..bdf66c8a45a77 100644 --- a/Detectors/ZDC/reconstruction/src/DigiReco.cxx +++ b/Detectors/ZDC/reconstruction/src/DigiReco.cxx @@ -101,8 +101,12 @@ void DigiReco::init() } mFullInterpolation = ropt.full_interpolation > 0 ? true : false; } + if (ropt.full_interpolation_min_length >= 2) { + // Minimum is 2 consecutive bunch crossings + mFullInterpolationMinLength = ropt.full_interpolation_min_length; + } if (mVerbosity > DbgZero) { - LOG(info) << "Full waveform interpolation is " << (mFullInterpolation ? "enabled" : "disabled"); + LOG(info) << "Full waveform interpolation is " << (mFullInterpolation ? "enabled" : "disabled") << " min length is " << mFullInterpolationMinLength; } if (ropt.triggerCondition == 0) { @@ -828,8 +832,8 @@ int DigiReco::reconstructTDC(int ibeg, int iend) istop = ibun; } else { // No data from channel // A gap is detected - if (istart >= 0 && (istop - istart) > 0) { - // Need data for at least two consecutive bunch crossings + if (istart >= 0 && (istop - istart + 1) >= mFullInterpolationMinLength) { + // Need data for at least mFullInterpolationMinLength (two) consecutive bunch crossings int rval = fullInterpolation(isig, istart, istop); if (rval) { return rval; @@ -839,8 +843,8 @@ int DigiReco::reconstructTDC(int ibeg, int iend) istop = -1; } } - // Check if there are consecutive bunch crossings at the end of group - if (istart >= 0 && (istop - istart) > 0) { + // Check if there are mFullInterpolationMinLength consecutive bunch crossings at the end of group + if (istart >= 0 && (istop - istart + 1) >= mFullInterpolationMinLength) { int rval = fullInterpolation(isig, istart, istop); if (rval) { return rval; diff --git a/Detectors/ZDC/reconstruction/src/RecoConfigZDC.cxx b/Detectors/ZDC/reconstruction/src/RecoConfigZDC.cxx index 001c64100b82f..8e4bd173691b3 100644 --- a/Detectors/ZDC/reconstruction/src/RecoConfigZDC.cxx +++ b/Detectors/ZDC/reconstruction/src/RecoConfigZDC.cxx @@ -14,6 +14,15 @@ using namespace o2::zdc; +void RecoConfigZDC::setBit(uint32_t ibit, bool val) +{ + if (ibit >= 0 && ibit < NTDCChannels) { + bitset[ibit] = val; + } else { + LOG(fatal) << __func__ << " channel " << ibit << " not in allowed range"; + } +} + void RecoConfigZDC::setSearch(uint32_t ich, int val) { if (ich >= 0 && ich < NTDCChannels) { @@ -95,7 +104,7 @@ void RecoConfigZDC::print() const (storeEvPileup ? " StoreEvPileup(EvE)" : " DontStoreEvPileup(EvE)"), (triggerCondition == 0x1 ? " SINGLEtrigger" : (triggerCondition == 0x3 ? " DOUBLEtrigger" : (triggerCondition == 0x7 ? "TRIPLEtrigger" : "WRONGtrigger")))); for (int itdc = 0; itdc < NTDCChannels; itdc++) { - LOG(info) << itdc << " " << ChannelNames[TDCSignal[itdc]] << " search= " << tdc_search[itdc] << " = " << tdc_search[itdc] * FTDCVal << " ns"; + LOG(info) << itdc << " " << ChannelNames[TDCSignal[itdc]] << " search= " << tdc_search[itdc] << " = " << tdc_search[itdc] * FTDCVal << " ns" << (bitset[itdc] ? " BITSET" : ""); } for (Int_t ich = 0; ich < NChannels; ich++) { LOG(info) << ChannelNames[ich] << " integration: signal=[" << beg_int[ich] << ":" << end_int[ich] << "] pedestal=[" << beg_ped_int[ich] << ":" << end_ped_int[ich] diff --git a/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx b/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx index 1d47b1884c3f5..d504d33483081 100644 --- a/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx +++ b/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx @@ -229,7 +229,9 @@ void DigitRecoSpec::run(ProcessingContext& pc) } // Limit the number of waveforms in output message if (mMaxWave > 0 && ntw >= mMaxWave) { - LOG(warning) << "Maximum number of output waveforms per TF reached: " << mMaxWave; + if (mVerbosity > DbgMinimal) { + LOG(warning) << "Maximum number of output waveforms per TF reached: " << mMaxWave; + } break; } } From b4204f07dc93aebe6c0c57a35444e2031f088404 Mon Sep 17 00:00:00 2001 From: Diego Stocco Date: Fri, 13 Oct 2023 11:08:24 +0200 Subject: [PATCH 261/324] Macro to query or upload MID CCDB objects (#12025) --- Detectors/MUON/MID/Calibration/CMakeLists.txt | 13 +- .../MID/Calibration/macros/CMakeLists.txt | 15 ++ .../MUON/MID/Calibration/macros/ccdbUtils.C | 208 ++++++++++++++++++ 3 files changed, 230 insertions(+), 6 deletions(-) create mode 100644 Detectors/MUON/MID/Calibration/macros/CMakeLists.txt create mode 100644 Detectors/MUON/MID/Calibration/macros/ccdbUtils.C diff --git a/Detectors/MUON/MID/Calibration/CMakeLists.txt b/Detectors/MUON/MID/Calibration/CMakeLists.txt index 5c17e204065ca..4d2a33527d527 100644 --- a/Detectors/MUON/MID/Calibration/CMakeLists.txt +++ b/Detectors/MUON/MID/Calibration/CMakeLists.txt @@ -1,13 +1,13 @@ -# Copyright 2019-2020 CERN and copyright holders of ALICE O2. See -# https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. # All rights not expressly granted are reserved. # -# This software is distributed under the terms of the GNU General Public License -# v3 (GPL Version 3), copied verbatim in the file "COPYING". +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". # # In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization or -# submit itself to any jurisdiction. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_library( MIDCalibration @@ -19,3 +19,4 @@ o2_target_root_dictionary(MIDCalibration HEADERS include/MIDCalibration/ChannelCalibrator.h include/MIDCalibration/ChannelCalibratorParam.h) add_subdirectory(exe) +add_subdirectory(macros) diff --git a/Detectors/MUON/MID/Calibration/macros/CMakeLists.txt b/Detectors/MUON/MID/Calibration/macros/CMakeLists.txt new file mode 100644 index 0000000000000..d665140902c43 --- /dev/null +++ b/Detectors/MUON/MID/Calibration/macros/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_test_root_macro( + ccdbUtils.C + PUBLIC_LINK_LIBRARIES O2::MIDCalibration O2::MathUtils + LABELS muon mid) diff --git a/Detectors/MUON/MID/Calibration/macros/ccdbUtils.C b/Detectors/MUON/MID/Calibration/macros/ccdbUtils.C new file mode 100644 index 0000000000000..0e3ac4bfbcfa5 --- /dev/null +++ b/Detectors/MUON/MID/Calibration/macros/ccdbUtils.C @@ -0,0 +1,208 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MID/Calibration/macros/ccdbUtils.cxx +/// \brief Retrieve or upload MID calibration objects +/// \author Diego Stocco +/// \date 16 May 2022 + +#include +#include +#include +#include "TFile.h" +#include "TObjString.h" +#include "CCDB/CcdbApi.h" +#include "DataFormatsMID/ColumnData.h" +#include "DataFormatsMID/ROFRecord.h" +#include "DataFormatsMID/ROBoard.h" +#include "MIDRaw/ROBoardConfigHandler.h" +#include "MIDRaw/DecodedDataAggregator.h" +#include "MIDFiltering/FetToDead.h" + +const std::string BadChannelCCDBPath = "MID/Calib/BadChannels"; + +/// @brief Prints the list of bad channels from the CCDB +/// @param ccdbUrl CCDB url +/// @param timestamp Timestamp +/// @param verbose True for verbose output +void queryBadChannels(const char* ccdbUrl, long timestamp, bool verbose) +{ + o2::ccdb::CcdbApi api; + api.init(ccdbUrl); + std::map metadata; + auto* badChannels = api.retrieveFromTFileAny>(BadChannelCCDBPath.c_str(), metadata, timestamp); + if (!badChannels) { + std::cout << "Error: cannot find " << BadChannelCCDBPath << " in " << ccdbUrl << std::endl; + return; + } + std::cout << "number of bad channels = " << badChannels->size() << std::endl; + if (verbose) { + for (const auto& badChannel : *badChannels) { + std::cout << badChannel << "\n"; + } + } +} + +/// @brief Returns the masks from the DCS CCDB +/// @param ccdbUrl CCDB url +/// @param timestamp Timestamp +/// @param verbose True for verbose output +/// @return Masks as string +std::string queryDCSMasks(const char* ccdbUrl, long timestamp, bool verbose) +{ + o2::ccdb::CcdbApi api; + std::string maskCCDBPath = "MID/Calib/ElectronicsMasks"; + api.init(ccdbUrl); + std::map metadata; + auto* masks = api.retrieveFromTFileAny(maskCCDBPath.c_str(), metadata, timestamp); + if (!masks) { + std::cout << "Error: cannot find " << maskCCDBPath << " in " << ccdbUrl << std::endl; + return ""; + } + if (verbose) { + std::cout << masks->GetName() << "\n"; + } + return masks->GetName(); +} + +/// @brief Writes the masks from the DCS CCDB to a text file +/// @param ccdbUrl DCS CCDB url +/// @param timestamp Timestamp +/// @param outFilename Output text filename +void writeDCSMasks(const char* ccdbUrl, long timestamp, const char* outFilename = "masks.txt") +{ + auto masks = queryDCSMasks(ccdbUrl, timestamp, false); + std::ofstream outFile(outFilename); + if (!outFile.is_open()) { + std::cout << "Error: cannot write to file " << outFilename << std::endl; + return; + } + outFile << masks << std::endl; + outFile.close(); +} + +/// @brief Uploads the list of bad channels provided +/// @param ccdbUrl CCDB url +/// @param timestamp Timestamp +/// @param badChannels List of bad channels. Default is no bad channel +void uploadBadChannels(const char* ccdbUrl, long timestamp, std::vector badChannels = {}) +{ + o2::ccdb::CcdbApi api; + api.init(ccdbUrl); + std::map md; + std::cout << "storing default MID bad channels (valid from " << timestamp << ") to " << BadChannelCCDBPath << "\n"; + + api.storeAsTFileAny(&badChannels, BadChannelCCDBPath, md, timestamp, o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP); +} + +/// @brief Reads the DCS masks from a file +/// @param filename Root or txt filename +/// @return DCS masks as string +std::string readDCSMasksFile(std::string filename) +{ + std::string out; + if (filename.find(".root") != std::string::npos) { + TFile* file = TFile::Open(filename.data()); + auto obj = file->Get("ccdb_object"); + out = obj->GetName(); + delete file; + } else { + std::ifstream inFile(filename); + if (inFile.is_open()) { + std::stringstream ss; + ss << inFile.rdbuf(); + out = ss.str(); + } + } + return out; +} + +/// @brief Returns the list of masked channels from the DCS masks +/// @param masksTxt DCS masks as string +/// @return Vector of bad channels +std::vector getBadChannelsFromDCSMasks(const char* masksTxt) +{ + std::stringstream ss; + ss << masksTxt; + o2::mid::ROBoardConfigHandler cfgHandler(ss); + auto cfgMap = cfgHandler.getConfigMap(); + std::vector boards; + o2::mid::ROBoard board; + board.statusWord = o2::mid::raw::sCARDTYPE | o2::mid::raw::sACTIVE; + for (auto& item : cfgMap) { + board.boardId = item.second.boardId; + bool isMasked = item.second.configWord & o2::mid::crateconfig::sMonmoff; + board.firedChambers = 0; + for (size_t ich = 0; ich < 4; ++ich) { + board.patternsBP[ich] = isMasked ? item.second.masksBP[ich] : 0xFFFF; + board.patternsNBP[ich] = isMasked ? item.second.masksNBP[ich] : 0xFFFF; + if (board.patternsBP[ich] || board.patternsNBP[ich]) { + board.firedChambers |= 1 << ich; + } + } + boards.emplace_back(board); + } + std::vector rofs; + rofs.emplace_back(o2::InteractionRecord{2, 2}, o2::mid::EventType::Standard, 0, boards.size()); + o2::mid::DecodedDataAggregator aggregator; + aggregator.process(boards, rofs); + o2::mid::FetToDead ftd; + return ftd.process(aggregator.getData()); +} + +/// @brief Uploads the bad channels list from DCS mask to CCDB +/// @param filename DCS mask text filename +/// @param timestamp Timestamp +/// @param ccdbUrl CCDB url +void uploadBadChannelsFromDCSMask(const char* filename, long timestamp, const char* ccdbUrl, bool verbose) +{ + auto masks = readDCSMasksFile(filename); + auto badChannels = getBadChannelsFromDCSMasks(masks.data()); + if (verbose) { + for (auto& col : badChannels) { + std::cout << col << std::endl; + } + } + uploadBadChannels(ccdbUrl, timestamp, badChannels); +} + +/// @brief Utility to query or upload bad channels and masks from/to the CCDB +/// @param what Command to be executed +/// @param timestamp Timestamp +/// @param verbose True for verbose output +/// @param ccdbUrl CCDB url +void ccdbUtils(const char* what, long timestamp = 0, const char* inFilename = "mask.txt", bool verbose = false, const char* ccdbUrl = "http://ccdb-test.cern.ch:8080") +{ + if (timestamp == 0) { + timestamp = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + } + + std::vector whats = {"querybad", "uploadbad", "querymasks", "writemasks", "uploadbadfrommasks"}; + + if (what == whats[0]) { + queryBadChannels(ccdbUrl, timestamp, verbose); + } else if (what == whats[1]) { + uploadBadChannels(ccdbUrl, timestamp); + } else if (what == whats[2]) { + queryDCSMasks(ccdbUrl, timestamp, verbose); + } else if (what == whats[3]) { + writeDCSMasks(ccdbUrl, timestamp); + } else if (what == whats[4]) { + uploadBadChannelsFromDCSMask(inFilename, timestamp, ccdbUrl, verbose); + } else { + std::cout << "Unimplemented option chosen " << what << std::endl; + std::cout << "Available:\n"; + for (auto& str : whats) { + std::cout << str << " "; + } + std::cout << std::endl; + } +} From 6245e6ed2e561430eeb862307aed596bfb2d3153 Mon Sep 17 00:00:00 2001 From: Benedikt Volkel Date: Thu, 12 Oct 2023 17:21:15 +0200 Subject: [PATCH 262/324] [MatchITSTPCQC] Skip invalid MC labels --- Detectors/GlobalTracking/src/MatchITSTPCQC.cxx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx b/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx index ffabdfb906690..d1984e3b1a7b8 100644 --- a/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx +++ b/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx @@ -323,6 +323,9 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) auto idxTrkTpc = trk.getRefTPC().getIndex(); if (isTPCTrackSelectedEntry[idxTrkTpc] == true) { auto lbl = mRecoCont.getTrackMCLabel({(unsigned int)(itrk), GID::Source::ITSTPC}); + if (!lbl.isValid()) { + continue; + } if (mMapLabels[matchType::TPC].find(lbl) == mMapLabels[matchType::TPC].end()) { int source = lbl.getSourceID(); int event = lbl.getEventID(); @@ -343,6 +346,9 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) auto idxTrkIts = trk.getRefITS().getIndex(); if (isITSTrackSelectedEntry[idxTrkIts] == true) { auto lbl = mRecoCont.getTrackMCLabel({(unsigned int)(itrk), GID::Source::ITSTPC}); + if (!lbl.isValid()) { + continue; + } if (mMapLabels[matchType::ITS].find(lbl) == mMapLabels[matchType::ITS].end()) { int source = lbl.getSourceID(); int event = lbl.getEventID(); @@ -508,6 +514,9 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) auto const& trk = mTPCTracks[itrk]; if (isTPCTrackSelectedEntry[itrk] == true) { auto lbl = mRecoCont.getTrackMCLabel({(unsigned int)(itrk), GID::Source::TPC}); + if (!lbl.isValid()) { + continue; + } if (mMapLabels[matchType::TPC].find(lbl) != mMapLabels[matchType::TPC].end()) { // the track was already added to the denominator continue; @@ -537,6 +546,9 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) auto const& trk = mITSTracks[itrk]; if (isITSTrackSelectedEntry[itrk] == true) { auto lbl = mRecoCont.getTrackMCLabel({(unsigned int)(itrk), GID::Source::ITS}); + if (!lbl.isValid()) { + continue; + } if (mMapLabels[matchType::ITS].find(lbl) != mMapLabels[matchType::ITS].end()) { // the track was already added to the denominator continue; From 06558256c4856a9c58ffac9b1c1a8ceef03b1a0f Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 13 Oct 2023 14:50:46 +0200 Subject: [PATCH 263/324] Add CTP Lumi to rawTF-reader outputs --- Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx b/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx index 245dc07082024..9a16e6622bcbf 100644 --- a/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx +++ b/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx @@ -443,6 +443,10 @@ o2f::DataProcessorSpec o2::rawdd::getTFReaderSpec(o2::rawdd::TFReaderInp& rinp) continue; } // in case detectors were processed on FLP + if (id == DetID::CTP) { + spec.outputs.emplace_back(o2f::OutputSpec{o2f::OutputSpec{DetID::getDataOrigin(DetID::CTP), "LUMI", 0}}); + rinp.hdVec.emplace_back(o2h::DataHeader{"LUMI", DetID::getDataOrigin(DetID::CTP), 0, 0}); // in abcence of real data this will be sent + } if (id == DetID::TOF) { spec.outputs.emplace_back(o2f::OutputSpec{o2f::ConcreteDataTypeMatcher{DetID::getDataOrigin(DetID::TOF), "CRAWDATA"}}); rinp.hdVec.emplace_back(o2h::DataHeader{"CRAWDATA", DetID::getDataOrigin(DetID::TOF), 0xDEADBEEF, 0}); // in abcence of real data this will be sent From 392dfed7aefc53f9af3e7396d8ded239d22faea0 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 21 Sep 2023 09:25:58 +0200 Subject: [PATCH 264/324] DPL: cleanup DataAllocator * Remove references to the now unsupported boost serialization * Unify common codepaths --- .../Core/include/Framework/DataAllocator.h | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/Framework/Core/include/Framework/DataAllocator.h b/Framework/Core/include/Framework/DataAllocator.h index 2cc912c4ba534..57c2801b139af 100644 --- a/Framework/Core/include/Framework/DataAllocator.h +++ b/Framework/Core/include/Framework/DataAllocator.h @@ -174,12 +174,13 @@ class DataAllocator template decltype(auto) make(const Output& spec, Args... args) { + auto& timingInfo = mRegistry.get(); + auto routeIndex = matchDataHeader(spec, timingInfo.timeslice); + auto& context = mRegistry.get(); + if constexpr (is_specialization_v) { // plain buffer as polymorphic spectator std::vector, which does not run constructors / destructors using ValueType = typename T::value_type; - auto& timingInfo = mRegistry.get(); - auto routeIndex = matchDataHeader(spec, timingInfo.timeslice); - auto& context = mRegistry.get(); // Note: initial payload size is 0 and will be set by the context before sending fair::mq::MessagePtr headerMessage = headerMessageFromOutput(spec, routeIndex, o2::header::gSerializationMethodNone, 0); @@ -190,9 +191,6 @@ class DataAllocator // this catches all std::vector objects with messageable value type before checking if is also // has a root dictionary, so non-serialized transmission is preferred using ValueType = typename T::value_type; - auto& timingInfo = mRegistry.get(); - auto routeIndex = matchDataHeader(spec, timingInfo.timeslice); - auto& context = mRegistry.get(); // Note: initial payload size is 0 and will be set by the context before sending fair::mq::MessagePtr headerMessage = headerMessageFromOutput(spec, routeIndex, o2::header::gSerializationMethodNone, 0); @@ -200,9 +198,6 @@ class DataAllocator } else if constexpr (has_root_dictionary::value == true && is_messageable::value == false) { // Extended support for types implementing the Root ClassDef interface, both TObject // derived types and others - auto& timingInfo = mRegistry.get(); - auto routeIndex = matchDataHeader(spec, timingInfo.timeslice); - auto& context = mRegistry.get(); if constexpr (enable_root_serialization::value) { fair::mq::MessagePtr headerMessage = headerMessageFromOutput(spec, routeIndex, o2::header::gSerializationMethodROOT, 0); @@ -239,9 +234,6 @@ class DataAllocator if constexpr (is_messageable::value == true) { auto [nElements] = std::make_tuple(args...); auto size = nElements * sizeof(T); - auto& timingInfo = mRegistry.get(); - auto routeIndex = matchDataHeader(spec, timingInfo.timeslice); - auto& context = mRegistry.get(); fair::mq::MessagePtr headerMessage = headerMessageFromOutput(spec, routeIndex, o2::header::gSerializationMethodNone, size); return context.add>(std::move(headerMessage), routeIndex, 0, nElements).get(); @@ -261,14 +253,6 @@ class DataAllocator } } - template - T& make_boost(const Output& spec) - { - auto buff = new T{}; - adopt_boost(spec, buff); - return *buff; - } - /// Adopt a string in the framework and serialize / send /// it to the consumers of @a spec once done. void From ba8d89d7d587841c11b2a8a39459dbfb22ee5a65 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 10 Oct 2023 11:31:13 +0200 Subject: [PATCH 265/324] DPL: add support for converting various containers to vectors --- .../Core/include/Framework/DataAllocator.h | 28 ++++++++++++++----- Framework/Core/test/test_DataAllocator.cxx | 13 +++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/Framework/Core/include/Framework/DataAllocator.h b/Framework/Core/include/Framework/DataAllocator.h index 57c2801b139af..f80d6d0836e28 100644 --- a/Framework/Core/include/Framework/DataAllocator.h +++ b/Framework/Core/include/Framework/DataAllocator.h @@ -58,13 +58,12 @@ namespace o2::framework { struct ServiceRegistry; -#define ERROR_STRING \ - "data type T not supported by API, " \ - "\n specializations available for" \ - "\n - trivially copyable, non-polymorphic structures" \ - "\n - arrays of those" \ - "\n - TObject with additional constructor arguments" \ - "\n - Classes and structs with boost serialization support" \ +#define ERROR_STRING \ + "data type T not supported by API, " \ + "\n specializations available for" \ + "\n - trivially copyable, non-polymorphic structures" \ + "\n - arrays of those" \ + "\n - TObject with additional constructor arguments" \ "\n - std containers of those" /// Helper to allow framework managed objecs to have a callback @@ -339,6 +338,21 @@ class DataAllocator "\n - pointers to those" "\n - types with ROOT dictionary and implementing ROOT ClassDef interface"); } + } else if constexpr (is_container::value == true && has_messageable_value_type::value == true) { + // Serialize a snapshot of a std::container of trivially copyable, non-polymorphic elements + // Note: in most cases it is better to use the `make` function und work with the provided + // reference object + constexpr auto elementSizeInBytes = sizeof(typename T::value_type); + auto sizeInBytes = elementSizeInBytes * object.size(); + payloadMessage = proxy.createOutputMessage(routeIndex, sizeInBytes); + + // serialize vector of pointers to elements + auto target = reinterpret_cast(payloadMessage->GetData()); + for (auto const& entry : object) { + memcpy(target, (void*)&entry, elementSizeInBytes); + target += elementSizeInBytes; + } + serializationType = o2::header::gSerializationMethodNone; } else if constexpr (has_root_dictionary::value == true || is_specialization_v == true) { // Serialize a snapshot of an object with root dictionary payloadMessage = proxy.createOutputMessage(routeIndex); diff --git a/Framework/Core/test/test_DataAllocator.cxx b/Framework/Core/test/test_DataAllocator.cxx index 5536eb1c07684..d880da72d7cb4 100644 --- a/Framework/Core/test/test_DataAllocator.cxx +++ b/Framework/Core/test/test_DataAllocator.cxx @@ -31,6 +31,7 @@ #include #include #include +#include #include // std::declval #include @@ -76,6 +77,8 @@ DataProcessorSpec getSourceSpec() o2::test::TriviallyCopyable a(42, 23, 0xdead); o2::test::Polymorphic b(0xbeef); std::vector c{{0xaffe}, {0xd00f}}; + std::deque testDequePayload{10, 20, 30}; + // class TriviallyCopyable is both messageable and has a dictionary, the default // picked by the framework is no serialization test::MetaHeader meta1{42}; @@ -88,6 +91,8 @@ DataProcessorSpec getSourceSpec() pc.outputs().snapshot(Output{"TST", "ROOTNONTOBJECT", 0, Lifetime::Timeframe}, b); // vector of ROOT serializable class pc.outputs().snapshot(Output{"TST", "ROOTVECTOR", 0, Lifetime::Timeframe}, c); + // deque of simple types + pc.outputs().snapshot(Output{"TST", "DEQUE", 0, Lifetime::Timeframe}, testDequePayload); // likewise, passed anonymously with char type and class name o2::framework::ROOTSerialized d(*((char*)&c), "vector"); pc.outputs().snapshot(Output{"TST", "ROOTSERLZDVEC", 0, Lifetime::Timeframe}, d); @@ -174,6 +179,7 @@ DataProcessorSpec getSourceSpec() OutputSpec{"TST", "MSGBLEROOTSRLZ", 0, Lifetime::Timeframe}, OutputSpec{"TST", "ROOTNONTOBJECT", 0, Lifetime::Timeframe}, OutputSpec{"TST", "ROOTVECTOR", 0, Lifetime::Timeframe}, + OutputSpec{"TST", "DEQUE", 0, Lifetime::Timeframe}, OutputSpec{"TST", "ROOTSERLZDVEC", 0, Lifetime::Timeframe}, OutputSpec{"TST", "ROOTSERLZDVEC2", 0, Lifetime::Timeframe}, OutputSpec{"TST", "PMRTESTVECTOR", 0, Lifetime::Timeframe}, @@ -317,6 +323,12 @@ DataProcessorSpec getSinkSpec() ASSERT_ERROR(object15[0] == o2::test::Polymorphic{0xacdc}); ASSERT_ERROR(object15[1] == o2::test::Polymorphic{0xbeef}); + LOG(info) << "extracting deque to vector from input16"; + auto object16 = pc.inputs().get>("input16"); + LOG(info) << "object16.size() = " << object16.size() << std::endl; + ASSERT_ERROR(object16.size() == 3); + ASSERT_ERROR(object16[0] == 10 && object16[1] == 20 && object16[2] == 30); + LOG(info) << "extracting PMR vector"; auto pmrspan = pc.inputs().get>("inputPMR"); ASSERT_ERROR((pmrspan[0] == o2::test::TriviallyCopyable{1, 2, 3})); @@ -351,6 +363,7 @@ DataProcessorSpec getSinkSpec() InputSpec{"input13", "TST", "MAKETOBJECT", 0, Lifetime::Timeframe}, InputSpec{"input14", "TST", "ROOTSERLZBLOBJ", 0, Lifetime::Timeframe}, InputSpec{"input15", "TST", "ROOTSERLZBLVECT", 0, Lifetime::Timeframe}, + InputSpec{"input16", "TST", "DEQUE", 0, Lifetime::Timeframe}, InputSpec{"inputPMR", "TST", "PMRTESTVECTOR", 0, Lifetime::Timeframe}, InputSpec{"inputPODvector", "TST", "PODVECTOR", 0, Lifetime::Timeframe}, InputSpec{"inputMP", ConcreteDataTypeMatcher{"TST", "MULTIPARTS"}, Lifetime::Timeframe}}, From 9a3a522e3cf64ebf3cbb24d477eb7dbc12c220a5 Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Fri, 13 Oct 2023 15:22:07 +0200 Subject: [PATCH 266/324] TRD most probably track time is trigger time --- .../RecoContainerCreateTracksVariadic.h | 14 ++++++-------- .../Detectors/GlobalTracking/src/RecoContainer.cxx | 2 -- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h index 6c31dec12c7d4..4bbe355a781c7 100644 --- a/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h +++ b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h @@ -196,12 +196,11 @@ void o2::globaltracking::RecoContainer::createTracksVariadic(T creator, GTrackID flagUsed(trc.getRefGlobalTrackId()); // flag seeding ITS-TPC track continue; } - float t0 = t0Trig, t0Err = 5.e-3; // 5ns nominal error - if (trc.hasPileUpInfo()) { // distance to farthest collision within the pileup integration time - t0 += trc.getPileUpTimeShiftMUS(); + float t0Err = 5.e-3; // 5ns nominal error + if (trc.hasPileUpInfo()) { // distance to farthest collision within the pileup integration time t0Err += trc.getPileUpTimeErrorMUS(); } - if (creator(trc, {i, currentSource}, t0, t0Err)) { // assign 1ns error to BC + if (creator(trc, {i, currentSource}, t0Trig, t0Err)) { // assign 1ns error to BC flagUsed(trc.getRefGlobalTrackId()); // flag seeding ITS-TPC track } } @@ -249,12 +248,11 @@ void o2::globaltracking::RecoContainer::createTracksVariadic(T creator, GTrackID flagUsed(trc.getRefGlobalTrackId()); // flag seeding TPC track continue; } - float t0 = t0Trig, t0Err = 5.e-3; // 5ns nominal error - if (trc.hasPileUpInfo()) { // distance to farthest collision within the pileup integration time - t0 += trc.getPileUpTimeShiftMUS(); + float t0Err = 5.e-3; // 5ns nominal error + if (trc.hasPileUpInfo()) { // distance to farthest collision within the pileup integration time t0Err += trc.getPileUpTimeErrorMUS(); } - if (creator(trc, {i, currentSource}, t0, t0Err)) { // assign 1ns error to BC + if (creator(trc, {i, currentSource}, t0Trig, t0Err)) { // assign 1ns error to BC flagUsed(trc.getRefGlobalTrackId()); // flag seeding TPC track } } diff --git a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx index 4c244b61bc5f8..1ecc67cda9bfb 100644 --- a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx +++ b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx @@ -1521,7 +1521,6 @@ void RecoContainer::getTrackTimeITSTPCTRD(GTrackID gid, float& t, float& tErr) c tErr = 5.e-3; const auto& trc = getITSTPCTRDTracks()[gid]; if (trc.hasPileUpInfo()) { // distance to farthest collision within the pileup integration time - t += trc.getPileUpTimeShiftMUS(); tErr += trc.getPileUpTimeErrorMUS(); } } @@ -1539,7 +1538,6 @@ void RecoContainer::getTrackTimeTPCTRD(GTrackID gid, float& t, float& tErr) cons tErr = 5.e-3; const auto& trc = getTPCTRDTracks()[gid]; if (trc.hasPileUpInfo()) { // distance to farthest collision within the pileup integration time - t += trc.getPileUpTimeShiftMUS(); tErr += trc.getPileUpTimeErrorMUS(); } } From 8a2502bb2c7fe9d2347372b6013b104e7d6709be Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Thu, 31 Aug 2023 11:27:37 +0200 Subject: [PATCH 267/324] Debug streamer: add sampling by weight - Storing weights and sampling frequency in debug tree --- .../Utils/include/CommonUtils/DebugStreamer.h | 30 +++++++++++-------- Common/Utils/src/DebugStreamer.cxx | 5 +++- GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx | 4 +-- GPU/GPUTracking/Merger/GPUTPCGMMerger.h | 6 ++-- GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx | 16 +++++----- 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/Common/Utils/include/CommonUtils/DebugStreamer.h b/Common/Utils/include/CommonUtils/DebugStreamer.h index 38de5fad34f39..8952842d5fc89 100644 --- a/Common/Utils/include/CommonUtils/DebugStreamer.h +++ b/Common/Utils/include/CommonUtils/DebugStreamer.h @@ -30,17 +30,18 @@ namespace o2::utils /// struct defining the flags which can be used to check if a certain debug streamer is used enum StreamFlags { - streamdEdx = 1 << 0, ///< stream corrections and cluster properties used for the dE/dx - streamDigitFolding = 1 << 1, ///< stream ion tail and saturatio information - streamDigits = 1 << 2, ///< stream digit information - streamFastTransform = 1 << 3, ///< stream tpc fast transform - streamITCorr = 1 << 4, ///< stream ion tail correction information - streamDistortionsSC = 1 << 5, ///< stream distortions applied in the TPC space-charge class (used for example in the tpc digitizer) - streamUpdateTrack = 1 << 6, ///< stream update track informations - streamRejectCluster = 1 << 7, ///< stream cluster rejection informations - streamMergeBorderTracks = 1 << 8, ///< stream MergeBorderTracks - streamTimeSeries = 1 << 9, ///< stream tpc DCA debug tree - streamFlagsCount = 10 ///< total number of streamers + streamdEdx = 1 << 0, ///< stream corrections and cluster properties used for the dE/dx + streamDigitFolding = 1 << 1, ///< stream ion tail and saturatio information + streamDigits = 1 << 2, ///< stream digit information + streamFastTransform = 1 << 3, ///< stream tpc fast transform + streamITCorr = 1 << 4, ///< stream ion tail correction information + streamDistortionsSC = 1 << 5, ///< stream distortions applied in the TPC space-charge class (used for example in the tpc digitizer) + streamUpdateTrack = 1 << 6, ///< stream update track informations + streamRejectCluster = 1 << 7, ///< stream cluster rejection informations + streamMergeBorderTracksBest = 1 << 8, ///< stream MergeBorderTracks best track + streamTimeSeries = 1 << 9, ///< stream tpc DCA debug tree + streamMergeBorderTracksAll = 1 << 10, ///< stream MergeBorderTracks all tracks + streamFlagsCount = 11 ///< total number of streamers }; enum SamplingTypes { @@ -48,6 +49,7 @@ enum SamplingTypes { sampleRandom = 1, ///< sample randomly every n points sampleID = 2, ///< sample every n IDs (per example track) sampleIDGlobal = 3, ///< in case different streamers have access to the same IDs use this gloabl ID + sampleWeights = 4, ///< perform sampling on weights, defined where the streamer is called }; #if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) @@ -123,6 +125,9 @@ class DebugStreamer /// \return returns sampling type and sampling frequency for given streamer static std::pair getSamplingTypeFrequency(const StreamFlags streamFlag); + /// \return returns sampling type and sampling frequency for given streamer + static float getSamplingFrequency(const StreamFlags streamFlag) { return getSamplingTypeFrequency(streamFlag).second; } + ///< return returns unique ID for each CPU thread to give each thread an own output file static size_t getCPUID(); @@ -146,7 +151,8 @@ class DebugStreamer /// check if streamer for specific flag is enabled /// \param samplingID optional index of the data which is streamed in to perform sampling on this index - static bool checkStream(const StreamFlags streamFlag, const size_t samplingID = -1); + /// \param weight weight which can be used to perform some weightes sampling + static bool checkStream(const StreamFlags streamFlag, const size_t samplingID = -1, const float weight = 1); /// merge trees with the same content structure, but different naming /// \param inpFile input file containing several trees with the same content diff --git a/Common/Utils/src/DebugStreamer.cxx b/Common/Utils/src/DebugStreamer.cxx index d146ecc808c2f..30de7c8de2e24 100644 --- a/Common/Utils/src/DebugStreamer.cxx +++ b/Common/Utils/src/DebugStreamer.cxx @@ -55,7 +55,7 @@ void o2::utils::DebugStreamer::flush() } } -bool o2::utils::DebugStreamer::checkStream(const StreamFlags streamFlag, const size_t samplingID) +bool o2::utils::DebugStreamer::checkStream(const StreamFlags streamFlag, const size_t samplingID, const float weight) { const bool isStreamerSet = ((getStreamFlags() & streamFlag) == streamFlag); if (!isStreamerSet) { @@ -104,6 +104,9 @@ bool o2::utils::DebugStreamer::checkStream(const StreamFlags streamFlag, const s refIDs[index][samplingID] = storeTrk; return storeTrk; } + } else if (sampling.first == SamplingTypes::sampleWeights) { + // sample with weight + return (weight * distr(generator) < sampling.second); } } return true; diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx index 01872cb5d2c64..41214b836fb76 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx @@ -907,7 +907,7 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<2>(int nBlocks, int nThreads, int } } - GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamMergeBorderTracks, b1.TrackID())) { MergedTrackStreamer(b1, b2, "merge_all_tracks", iSlice1, iSlice2, mergeMode); }); + GPUCA_DEBUG_STREAMER_CHECK(float weight = b1.Par()[4] * b1.Par()[4]; if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamMergeBorderTracksAll, b1.TrackID(), weight)) { MergedTrackStreamer(b1, b2, "merge_all_tracks", iSlice1, iSlice2, mergeMode, weight, o2::utils::DebugStreamer::getSamplingFrequency(o2::utils::StreamFlags::streamMergeBorderTracksAll)); }); if (!b1.CheckChi2Y(b2, factor2ys)) { CADEBUG2(continue, printf("!Y\n")); @@ -941,7 +941,7 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<2>(int nBlocks, int nThreads, int if (iBest2 < 0) { continue; } - GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamMergeBorderTracks, b1.TrackID())) { MergedTrackStreamer(b1, MergedTrackStreamerFindBorderTrack(B2, N2, iBest2), "merge_best_track", iSlice1, iSlice2, mergeMode); }); + GPUCA_DEBUG_STREAMER_CHECK(float weight = b1.Par()[4] * b1.Par()[4]; if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamMergeBorderTracksBest, b1.TrackID(), weight)) { MergedTrackStreamer(b1, MergedTrackStreamerFindBorderTrack(B2, N2, iBest2), "merge_best_track", iSlice1, iSlice2, mergeMode, weight, o2::utils::DebugStreamer::getSamplingFrequency(o2::utils::StreamFlags::streamMergeBorderTracksBest)); }); // statMerged++; diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.h b/GPU/GPUTracking/Merger/GPUTPCGMMerger.h index 6cba252a69710..e4e0d796a33d3 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.h @@ -195,8 +195,8 @@ class GPUTPCGMMerger : public GPUProcessor void DumpFinal(std::ostream& out); template - void MergedTrackStreamerInternal(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int slice1, int slice2, int mergeMode); - void MergedTrackStreamer(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int slice1, int slice2, int mergeMode); + void MergedTrackStreamerInternal(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int slice1, int slice2, int mergeMode, float weight, float frac); + void MergedTrackStreamer(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int slice1, int slice2, int mergeMode, float weight, float frac); const GPUTPCGMBorderTrack& MergedTrackStreamerFindBorderTrack(const GPUTPCGMBorderTrack* tracks, int N, int trackId); #endif @@ -274,7 +274,7 @@ class GPUTPCGMMerger : public GPUProcessor unsigned int* mTrackSort; tmpSort* mTrackSortO2; GPUAtomic(unsigned int) * mSharedCount; // Must be unsigned int unfortunately for atomic support - GPUTPCGMBorderTrack* mBorderMemory; // memory for border tracks + GPUTPCGMBorderTrack* mBorderMemory; // memory for border tracks GPUTPCGMBorderTrack* mBorder[2 * NSLICES]; gputpcgmmergertypes::GPUTPCGMBorderRange* mBorderRangeMemory; // memory for border tracks gputpcgmmergertypes::GPUTPCGMBorderRange* mBorderRange[NSLICES]; // memory for border tracks diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx index 192ffec35f942..490d49f9d2a17 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx @@ -183,7 +183,7 @@ void GPUTPCGMMerger::DumpFinal(std::ostream& out) } template -inline void GPUTPCGMMerger::MergedTrackStreamerInternal(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int slice1, int slice2, int mergeMode) +inline void GPUTPCGMMerger::MergedTrackStreamerInternal(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int slice1, int slice2, int mergeMode, float weight, float frac) { #ifdef DEBUG_STREAMER std::vector hits1(152), hits2(152); @@ -209,19 +209,17 @@ inline void GPUTPCGMMerger::MergedTrackStreamerInternal(const GPUTPCGMBorderTrac std::string debugname = std::string("debug_") + name; std::string treename = std::string("tree_") + name; - o2::utils::DebugStreamer::instance()->getStreamer(debugname.c_str(), "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName(treename.c_str()).data() << "slice1=" << slice1 << "slice2=" << slice2 << "b1=" << b1 << "b2=" << b2 << "clusters1=" << hits1 << "clusters2=" << hits2 << "sliceTrack1=" << sliceTrack1 << "sliceTrack2=" << sliceTrack2 << "mergeMode=" << mergeMode << "\n"; + o2::utils::DebugStreamer::instance()->getStreamer(debugname.c_str(), "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName(treename.c_str()).data() << "slice1=" << slice1 << "slice2=" << slice2 << "b1=" << b1 << "b2=" << b2 << "clusters1=" << hits1 << "clusters2=" << hits2 << "sliceTrack1=" << sliceTrack1 << "sliceTrack2=" << sliceTrack2 << "mergeMode=" << mergeMode << "weight=" << weight << "fraction=" << frac << "\n"; #endif } -void GPUTPCGMMerger::MergedTrackStreamer(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int slice1, int slice2, int mergeMode) +void GPUTPCGMMerger::MergedTrackStreamer(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int slice1, int slice2, int mergeMode, float weight, float frac) { #ifdef DEBUG_STREAMER - if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamMergeBorderTracks, b1.TrackID())) { - if (mergeMode == 0) { - MergedTrackStreamerInternal<0>(b1, b2, name, slice1, slice2, mergeMode); - } else if (mergeMode >= 1 && mergeMode <= 0) { - // MergedTrackStreamerInternal<1>(b1, b2, name, slice1, slice2, mergeMode); Not yet working - } + if (mergeMode == 0) { + MergedTrackStreamerInternal<0>(b1, b2, name, slice1, slice2, mergeMode, weight, frac); + } else if (mergeMode >= 1 && mergeMode <= 0) { + // MergedTrackStreamerInternal<1>(b1, b2, name, slice1, slice2, mergeMode, weight, frac); Not yet working } #endif } From cf8ed9343bc63f0acb3eeb3fa921bb21b563fb05 Mon Sep 17 00:00:00 2001 From: noferini Date: Fri, 13 Oct 2023 17:12:08 +0200 Subject: [PATCH 268/324] adding protection in tof-compressor --- .../compression/include/TOFCompression/Compressor.h | 1 + Detectors/TOF/compression/src/Compressor.cxx | 11 +++++++++++ Detectors/TOF/compression/src/tof-compressor.cxx | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Detectors/TOF/compression/include/TOFCompression/Compressor.h b/Detectors/TOF/compression/include/TOFCompression/Compressor.h index c807b5cfc0fe2..ede65acdccccc 100644 --- a/Detectors/TOF/compression/include/TOFCompression/Compressor.h +++ b/Detectors/TOF/compression/include/TOFCompression/Compressor.h @@ -40,6 +40,7 @@ class Compressor inline bool run() { rewind(); + mEncoderPointerMax = reinterpret_cast(mEncoderBuffer + mEncoderBufferSize); if (mDecoderCONET) { mDecoderPointerMax = reinterpret_cast(mDecoderBuffer + mDecoderBufferSize); while (mDecoderPointer < mDecoderPointerMax) { diff --git a/Detectors/TOF/compression/src/Compressor.cxx b/Detectors/TOF/compression/src/Compressor.cxx index 75f5fac714fb2..180d26cb7a6bf 100644 --- a/Detectors/TOF/compression/src/Compressor.cxx +++ b/Detectors/TOF/compression/src/Compressor.cxx @@ -209,6 +209,12 @@ bool Compressor::processHBF() } /** copy RDH open to encoder buffer **/ + + if (mEncoderPointer + mDecoderRDH->headerSize >= mEncoderPointerMax) { + LOG(error) << "link = " << rdh->feeId << ": beyond the buffer size mEncoderPointer+mDecoderRDH->headerSize = " << mEncoderPointer + mDecoderRDH->headerSize << " >= " + << "mEncoderPointerMax = " << mEncoderPointerMax; + return true; + } std::memcpy(mEncoderPointer, mDecoderRDH, mDecoderRDH->headerSize); mEncoderPointer = reinterpret_cast(reinterpret_cast(mEncoderPointer) + rdh->headerSize); @@ -246,6 +252,11 @@ bool Compressor::processHBF() /** copy RDH close to encoder buffer **/ /** CAREFUL WITH THE PAGE COUNTER **/ + if (mEncoderPointer + rdh->headerSize >= mEncoderPointerMax) { + LOG(error) << "link = " << rdh->feeId << ": beyond the buffer size mEncoderPointer+rdh->headerSize = " << mEncoderPointer + rdh->headerSize << " >= " + << "mEncoderPointerMax = " << mEncoderPointerMax; + return true; + } mEncoderRDH = reinterpret_cast(mEncoderPointer); std::memcpy(mEncoderRDH, rdh, rdh->headerSize); mEncoderRDH->memorySize = rdh->headerSize; diff --git a/Detectors/TOF/compression/src/tof-compressor.cxx b/Detectors/TOF/compression/src/tof-compressor.cxx index 604609e1080d6..4358ceae84bdb 100644 --- a/Detectors/TOF/compression/src/tof-compressor.cxx +++ b/Detectors/TOF/compression/src/tof-compressor.cxx @@ -135,7 +135,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) outputs, algoSpec, Options{ - {"tof-compressor-output-buffer-size", VariantType::Int, 0, {"Encoder output buffer size (in bytes). Zero = automatic (careful)."}}, + {"tof-compressor-output-buffer-size", VariantType::Int, 1048576, {"Encoder output buffer size (in bytes). Zero = automatic (careful)."}}, {"tof-compressor-conet-mode", VariantType::Bool, false, {"Decoder CONET flag"}}, {"tof-compressor-decoder-verbose", VariantType::Bool, false, {"Decoder verbose flag"}}, {"tof-compressor-encoder-verbose", VariantType::Bool, false, {"Encoder verbose flag"}}, From 550263cf5cb874a89df15b3da4684f27909ebea1 Mon Sep 17 00:00:00 2001 From: noferini Date: Sat, 14 Oct 2023 18:54:11 +0200 Subject: [PATCH 269/324] fix FEE mismatch in tof-compressor --- Detectors/TOF/compression/src/Compressor.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Detectors/TOF/compression/src/Compressor.cxx b/Detectors/TOF/compression/src/Compressor.cxx index 180d26cb7a6bf..26c5d6b4cf09f 100644 --- a/Detectors/TOF/compression/src/Compressor.cxx +++ b/Detectors/TOF/compression/src/Compressor.cxx @@ -413,7 +413,8 @@ bool Compressor::processDRM() /** encode Crate Header **/ *mEncoderPointer = 0x80000000; *mEncoderPointer |= GET_DRMHEADW1_PARTSLOTMASK(*mDecoderSummary.drmHeadW1) << 12; - *mEncoderPointer |= GET_DRMDATAHEADER_DRMID(*mDecoderSummary.drmDataHeader) << 24; + // R+OLD *mEncoderPointer |= GET_DRMDATAHEADER_DRMID(*mDecoderSummary.drmDataHeader) << 24; + *mEncoderPointer |= (mDecoderRDH->feeId & 0xFF) << 24; *mEncoderPointer |= GET_DRMHEADW3_GBTBUNCHCNT(*mDecoderSummary.drmHeadW3); if (verbose && mEncoderVerbose) { auto crateHeader = reinterpret_cast(mEncoderPointer); From adbdea859e15cb1a019cb40e0ed0beed35509353 Mon Sep 17 00:00:00 2001 From: noferini Date: Sun, 15 Oct 2023 18:27:33 +0200 Subject: [PATCH 270/324] add protections in tof-compressor --- .../include/TOFCompression/Compressor.h | 28 +++++++++--- Detectors/TOF/compression/src/Compressor.cxx | 44 +++++++++++++++---- 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/Detectors/TOF/compression/include/TOFCompression/Compressor.h b/Detectors/TOF/compression/include/TOFCompression/Compressor.h index ede65acdccccc..280aa163e53c2 100644 --- a/Detectors/TOF/compression/include/TOFCompression/Compressor.h +++ b/Detectors/TOF/compression/include/TOFCompression/Compressor.h @@ -40,7 +40,7 @@ class Compressor inline bool run() { rewind(); - mEncoderPointerMax = reinterpret_cast(mEncoderBuffer + mEncoderBufferSize); + mEncoderPointerMax = reinterpret_cast(mEncoderBuffer + mEncoderBufferSizeInt); if (mDecoderCONET) { mDecoderPointerMax = reinterpret_cast(mDecoderBuffer + mDecoderBufferSize); while (mDecoderPointer < mDecoderPointerMax) { @@ -90,10 +90,20 @@ class Compressor void setDecoderBuffer(const char* val) { mDecoderBuffer = val; }; void setEncoderBuffer(char* val) { mEncoderBuffer = val; }; void setDecoderBufferSize(long val) { mDecoderBufferSize = val; }; - void setEncoderBufferSize(long val) { mEncoderBufferSize = val; }; + void setEncoderBufferSize(long val) + { + mEncoderBufferSize = val; + mEncoderBufferSizeInt = mEncoderBufferSize / 4; + }; inline uint32_t getDecoderByteCounter() const { return reinterpret_cast(mDecoderPointer) - mDecoderBuffer; }; - inline uint32_t getEncoderByteCounter() const { return reinterpret_cast(mEncoderPointer) - mEncoderBuffer; }; + inline uint32_t getEncoderByteCounter() const + { + if (reinterpret_cast(mEncoderPointer) < mEncoderBuffer) { + return 0; + } + return reinterpret_cast(mEncoderPointer) - mEncoderBuffer; + }; // benchmarks double mIntegratedBytes = 0.; @@ -140,13 +150,21 @@ class Compressor /** encoder private functions and data members **/ - void encoderSpider(int itrm); + int encoderSpider(int itrm); inline void encoderRewind() { mEncoderPointer = reinterpret_cast(mEncoderBuffer); }; - inline void encoderNext() { mEncoderPointer++; }; + inline int encoderNext() + { + if (mEncoderPointer + 1 >= mEncoderPointerMax) { + return 1; + }; + mEncoderPointer++; + return 0; + }; std::ofstream mEncoderFile; char* mEncoderBuffer = nullptr; long mEncoderBufferSize; + long mEncoderBufferSizeInt; uint32_t* mEncoderPointer = nullptr; uint32_t* mEncoderPointerMax = nullptr; uint32_t* mEncoderPointerStart = nullptr; diff --git a/Detectors/TOF/compression/src/Compressor.cxx b/Detectors/TOF/compression/src/Compressor.cxx index 26c5d6b4cf09f..ef76e386733ee 100644 --- a/Detectors/TOF/compression/src/Compressor.cxx +++ b/Detectors/TOF/compression/src/Compressor.cxx @@ -213,6 +213,7 @@ bool Compressor::processHBF() if (mEncoderPointer + mDecoderRDH->headerSize >= mEncoderPointerMax) { LOG(error) << "link = " << rdh->feeId << ": beyond the buffer size mEncoderPointer+mDecoderRDH->headerSize = " << mEncoderPointer + mDecoderRDH->headerSize << " >= " << "mEncoderPointerMax = " << mEncoderPointerMax; + encoderRewind(); return true; } std::memcpy(mEncoderPointer, mDecoderRDH, mDecoderRDH->headerSize); @@ -423,7 +424,10 @@ bool Compressor::processDRM() auto slotPartMask = crateHeader->slotPartMask; printf("%s %08x Crate header (drmID=%d, bunchID=%d, slotPartMask=0x%x) %s \n", colorGreen, *mEncoderPointer, drmID, bunchID, slotPartMask, colorReset); } - encoderNext(); + if (encoderNext()) { + encoderRewind(); + return true; + } /** encode Crate Orbit **/ *mEncoderPointer = *mDecoderSummary.tofOrbit; @@ -432,7 +436,10 @@ bool Compressor::processDRM() auto orbitID = crateOrbit->orbitID; printf("%s %08x Crate orbit (orbitID=%u) %s \n", colorGreen, *mEncoderPointer, orbitID, colorReset); } - encoderNext(); + if (encoderNext()) { + encoderRewind(); + return true; + } /** loop over DRM payload **/ int nsteps = 0; @@ -493,7 +500,10 @@ bool Compressor::processDRM() auto NumberOfErrors = CrateTrailer->numberOfErrors; printf("%s %08x Crate trailer (EventCounter=%d, NumberOfDiagnostics=%d, NumberOfErrors=%d) %s \n", colorGreen, *mEncoderPointer, EventCounter, NumberOfDiagnostics, NumberOfErrors, colorReset); } - encoderNext(); + if (encoderNext()) { + encoderRewind(); + return true; + } /** encode Diagnostic Words **/ for (int iword = 0; iword < mCheckerSummary.nDiagnosticWords; ++iword) { @@ -505,7 +515,10 @@ bool Compressor::processDRM() auto faultBits = Diagnostic->faultBits; printf("%s %08x Diagnostic (slotId=%d, faultBits=0x%x) %s \n", colorGreen, *mEncoderPointer, slotId, faultBits, colorReset); } - encoderNext(); + if (encoderNext()) { + encoderRewind(); + return true; + } } /** encode TDC errors **/ @@ -525,7 +538,10 @@ bool Compressor::processDRM() auto tdcID = Error->tdcID; printf("%s %08x Error (slotId=%d, chain=%d, tdcId=%d, errorFlags=0x%x) %s \n", colorGreen, *mEncoderPointer, slotID, chain, tdcID, errorFlags, colorReset); } - encoderNext(); + if (encoderNext()) { + encoderRewind(); + return true; + } } #endif mDecoderSummary.trmErrors[itrm][ichain] = 0; @@ -692,7 +708,10 @@ bool Compressor::processTRM() /** encoder Spider **/ if (mDecoderSummary.hasHits[itrm][0] || mDecoderSummary.hasHits[itrm][1]) { - encoderSpider(itrm); + if (encoderSpider(itrm)) { + encoderRewind(); + return true; + } } /** success **/ @@ -833,7 +852,7 @@ bool Compressor::decoderParanoid() } template -void Compressor::encoderSpider(int itrm) +int Compressor::encoderSpider(int itrm) { /** encoder spider **/ @@ -924,7 +943,10 @@ void Compressor::encoderSpider(int itrm) auto TRMID = FrameHeader->trmID; printf("%s %08x Frame header (TRMID=%d, FrameID=%d, NumberOfHits=%d) %s \n", colorGreen, *mEncoderPointer, TRMID, FrameID, NumberOfHits, colorReset); } - encoderNext(); + if (encoderNext()) { + encoderRewind(); + return true; + } // packed hits for (int ihit = 0; ihit < mSpiderSummary.nFramePackedHits[iframe]; ++ihit) { @@ -938,11 +960,15 @@ void Compressor::encoderSpider(int itrm) auto TOT = PackedHit->tot; printf("%s %08x Packed hit (Chain=%d, TDCID=%d, Channel=%d, Time=%d, TOT=%d) %s \n", colorGreen, *mEncoderPointer, Chain, TDCID, Channel, Time, TOT, colorReset); } - encoderNext(); + if (encoderNext()) { + encoderRewind(); + return true; + } } mSpiderSummary.nFramePackedHits[iframe] = 0; } + return 0; } template From ef472d665b1b9914372fa9ffda9e42e0cbb44813 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Sun, 15 Oct 2023 17:25:48 +0200 Subject: [PATCH 271/324] Avoid copy of tracks --- Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx | 3 +-- GPU/Workflow/src/GPUWorkflowITS.cxx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx index a61f454822681..b9831462b0a13 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx @@ -170,7 +170,6 @@ void TrackerDPL::run(ProcessingContext& pc) LOG(info) << labels->getIndexedSize() << " MC label objects , in " << mc2rofs.size() << " MC events"; } - std::vector tracks; auto& allClusIdx = pc.outputs().make>(Output{"ITS", "TRACKCLSID", 0, Lifetime::Timeframe}); std::vector trackLabels; std::vector verticesLabels; @@ -276,7 +275,7 @@ void TrackerDPL::run(ProcessingContext& pc) for (unsigned int iROF{0}; iROF < rofs.size(); ++iROF) { auto& rof{rofs[iROF]}; - tracks = mTimeFrame->getTracks(iROF); + auto& tracks = mTimeFrame->getTracks(iROF); trackLabels = mTimeFrame->getTracksLabel(iROF); auto number{tracks.size()}; auto first{allTracks.size()}; diff --git a/GPU/Workflow/src/GPUWorkflowITS.cxx b/GPU/Workflow/src/GPUWorkflowITS.cxx index 3c621d4d9d66e..876561d381594 100644 --- a/GPU/Workflow/src/GPUWorkflowITS.cxx +++ b/GPU/Workflow/src/GPUWorkflowITS.cxx @@ -155,7 +155,6 @@ int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) LOG(info) << labels->getIndexedSize() << " MC label objects , in " << mc2rofs.size() << " MC events"; } - std::vector tracks; auto& allClusIdx = pc.outputs().make>(Output{"ITS", "TRACKCLSID", 0, Lifetime::Timeframe}); std::vector trackLabels; std::vector verticesLabels; @@ -261,7 +260,7 @@ int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) for (unsigned int iROF{0}; iROF < rofs.size(); ++iROF) { auto& rof{rofs[iROF]}; - tracks = mITSTimeFrame->getTracks(iROF); + auto& tracks = mITSTimeFrame->getTracks(iROF); trackLabels = mITSTimeFrame->getTracksLabel(iROF); auto number{tracks.size()}; auto first{allTracks.size()}; From 1c89505f548ef86ede6a3b0738f1dfdea45eaaa0 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 15 Oct 2023 23:52:00 +0200 Subject: [PATCH 272/324] DPL: If we receive only the EoS for that run, we need to add to the counter after the resetting --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 55d43747e28a4..4cc861c0edb73 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -793,12 +793,12 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, std::string const& channel = channels[ci]; // we buffer the condition since the converter will forward messages by move int nEos = countEoS(inputs); - numberOfEoS[ci] += nEos; if (newRun) { std::fill(numberOfEoS.begin(), numberOfEoS.end(), 0); std::fill(eosPeersCount.begin(), eosPeersCount.end(), 0); gAllowEoS = gAllowEoSdefault; } + numberOfEoS[ci] += nEos; if (numberOfEoS[ci]) { eosPeersCount[ci] = std::max(eosPeersCount[ci], device->GetNumberOfConnectedPeers(channel)); } From 607495d023d12f6f8e8aa21cfc5da793be492dc2 Mon Sep 17 00:00:00 2001 From: shahoian Date: Sat, 7 Oct 2023 03:46:29 +0200 Subject: [PATCH 273/324] Fix getTime... methodes in the RecoContainer --- DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx index 1ecc67cda9bfb..fdfdf1e18fd96 100644 --- a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx +++ b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx @@ -1523,6 +1523,7 @@ void RecoContainer::getTrackTimeITSTPCTRD(GTrackID gid, float& t, float& tErr) c if (trc.hasPileUpInfo()) { // distance to farthest collision within the pileup integration time tErr += trc.getPileUpTimeErrorMUS(); } + return; } } } @@ -1540,6 +1541,7 @@ void RecoContainer::getTrackTimeTPCTRD(GTrackID gid, float& t, float& tErr) cons if (trc.hasPileUpInfo()) { // distance to farthest collision within the pileup integration time tErr += trc.getPileUpTimeErrorMUS(); } + return; } } } @@ -1568,6 +1570,7 @@ void RecoContainer::getTrackTimeITS(GTrackID gid, float& t, float& tErr) const if (gid.getIndex() < rof.getFirstEntry() + rof.getNEntries()) { t = rof.getBCData().differenceInBC(startIR) * o2::constants::lhc::LHCBunchSpacingMUS; tErr = 0.5; + return; } } } From abd645789a5c82a128951618673dae1b66c9bf06 Mon Sep 17 00:00:00 2001 From: shahoian Date: Sat, 14 Oct 2023 03:23:49 +0200 Subject: [PATCH 274/324] Improve FT0 interaction tag, use for TRD pileup --- .../include/FT0Reconstruction/InteractionTag.h | 7 ++++--- Detectors/TRD/workflow/CMakeLists.txt | 1 + Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx | 3 ++- prodtests/full-system-test/dpl-workflow.sh | 6 ++++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/InteractionTag.h b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/InteractionTag.h index 408eed72e3af1..7ac54d79144ef 100644 --- a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/InteractionTag.h +++ b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/InteractionTag.h @@ -26,11 +26,12 @@ namespace ft0 // These are configurable params for FT0 selection as interaction tag struct InteractionTag : public o2::conf::ConfigurableParamHelper { - int minAmplitudeAC = 0; ///< use only FT0 triggers with high enough amplitude - + int minAmplitudeAC = 2; ///< use only FT0 triggers with high enough amplitude + int minAmplitudeA = 1; + int minAmplitudeC = 1; bool isSelected(const RecPoints& rp) const { - return rp.getTrigger().getVertex() && (rp.getTrigger().getAmplA() + rp.getTrigger().getAmplC()) > minAmplitudeAC; + return rp.getTrigger().getVertex() && rp.getTrigger().getAmplA() >= minAmplitudeA && rp.getTrigger().getAmplC() >= minAmplitudeC && (rp.getTrigger().getAmplA() + rp.getTrigger().getAmplC()) > minAmplitudeAC; } O2ParamDef(InteractionTag, "ft0tag"); diff --git a/Detectors/TRD/workflow/CMakeLists.txt b/Detectors/TRD/workflow/CMakeLists.txt index 069e5f11dc00e..481a085306eed 100644 --- a/Detectors/TRD/workflow/CMakeLists.txt +++ b/Detectors/TRD/workflow/CMakeLists.txt @@ -44,6 +44,7 @@ o2_add_library(TRDWorkflow O2::GlobalTrackingWorkflowReaders O2::GPUWorkflowHelper O2::ReconstructionDataFormats + O2::FT0Reconstruction O2::ITSWorkflow O2::TPCWorkflow O2::TRDWorkflowIO diff --git a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx index 87c7037475236..afa2108a224a6 100644 --- a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx +++ b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx @@ -35,6 +35,7 @@ #include "DataFormatsFT0/RecPoints.h" #include "ITSReconstruction/RecoGeomHelper.h" #include "ITSMFTReconstruction/ClustererParam.h" +#include "FT0Reconstruction/InteractionTag.h" #include "DataFormatsGlobalTracking/TrackTuneParams.h" // GPU header @@ -402,7 +403,7 @@ void TRDGlobalTracking::run(ProcessingContext& pc) uint8_t fwd = 0, bwd = 0; for (size_t ft0id = curFT0; ft0id < ft0recPoints.size(); ft0id++) { const auto& f0rec = ft0recPoints[ft0id]; - if (f0rec.getTrigger().getVertex()) { + if (o2::ft0::InteractionTag::Instance().isSelected(f0rec)) { auto bcdiff = trig.getBCData().toLong() - f0rec.getInteractionRecord().toLong(); if (bcdiff > maxDiffBwd) { curFT0 = ft0id + 1; diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index fdcdac651ae1a..0e228ee911e2f 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -87,6 +87,7 @@ EMCRAW2C_CONFIG= PHS_CONFIG= MCH_CONFIG_KEY= CTP_CONFIG= +INTERACTION_TAG_CONFIG_KEY= : ${STRTRACKING:=} : ${ITSEXTRAERR:=} : ${TRACKTUNETPCINNER:=} @@ -146,6 +147,7 @@ fi if [[ $BEAMTYPE == "PbPb" ]]; then PVERTEXING_CONFIG_KEY+="pvertexer.maxChi2TZDebris=2000;" + INTERACTION_TAG_CONFIG_KEY="ft0tag.minAmplitudeA=${INT_TAG_FT0A:-5};ft0tag.minAmplitudeC=${INT_TAG_FT0C:-5};ft0tag.minAmplitudeAC=${INT_TAG_FT0AC:-20};" elif [[ $BEAMTYPE == "pp" ]]; then PVERTEXING_CONFIG_KEY+="pvertexer.maxChi2TZDebris=10;" fi @@ -461,8 +463,8 @@ fi has_detector_reco ITS && ! has_detector_from_global_reader ITS && add_W o2-its-reco-workflow "--trackerCA $ITS_CONFIG $DISABLE_MC $DISABLE_DIGIT_CLUSTER_INPUT $DISABLE_ROOT_OUTPUT --pipeline $(get_N its-tracker ITS REST 1 ITSTRK)" "$ITS_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" has_detector_reco FT0 && ! has_detector_from_global_reader FT0 && add_W o2-ft0-reco-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC --pipeline $(get_N ft0-reconstructor FT0 REST 1)" has_detector_reco TRD && ! has_detector_from_global_reader TRD && add_W o2-trd-tracklet-transformer "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TRD_FILTER_CONFIG --pipeline $(get_N TRDTRACKLETTRANSFORMER TRD REST 1 TRDTRKTRANS)" -has_detectors_reco ITS TPC && has_detector_matching ITSTPC && add_W o2-tpcits-match-workflow "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $SEND_ITSTPC_DTGL $TPC_CORR_SCALING --nthreads $ITSTPC_THREADS --pipeline $(get_N itstpc-track-matcher MATCH REST $ITSTPC_THREADS TPCITS)" "$ITSTPC_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" -has_detector_reco TRD && [[ ! -z "$TRD_SOURCES" ]] && add_W o2-trd-global-tracking "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TRD_CONFIG $TRD_FILTER_CONFIG $TPC_CORR_SCALING --track-sources $TRD_SOURCES --pipeline $(get_N trd-globaltracking_TPC_ITS-TPC_ TRD REST 1 TRDTRK),$(get_N trd-globaltracking_TPC_FT0_ITS-TPC_ TRD REST 1 TRDTRK)" "$TRD_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" +has_detectors_reco ITS TPC && has_detector_matching ITSTPC && add_W o2-tpcits-match-workflow "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $SEND_ITSTPC_DTGL $TPC_CORR_SCALING --nthreads $ITSTPC_THREADS --pipeline $(get_N itstpc-track-matcher MATCH REST $ITSTPC_THREADS TPCITS)" "$ITSTPC_CONFIG_KEY;$INTERACTION_TAG_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" +has_detector_reco TRD && [[ ! -z "$TRD_SOURCES" ]] && add_W o2-trd-global-tracking "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TRD_CONFIG $TRD_FILTER_CONFIG $TPC_CORR_SCALING --track-sources $TRD_SOURCES --pipeline $(get_N trd-globaltracking_TPC_ITS-TPC_ TRD REST 1 TRDTRK),$(get_N trd-globaltracking_TPC_FT0_ITS-TPC_ TRD REST 1 TRDTRK)" "$TRD_CONFIG_KEY;$INTERACTION_TAG_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" has_detector_reco TOF && [[ ! -z "$TOF_SOURCES" ]] && add_W o2-tof-matcher-workflow "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TPC_CORR_SCALING --track-sources $TOF_SOURCES --pipeline $(get_N tof-matcher TOF REST 1 TOFMATCH)" "$ITSMFT_STROBES;$ITSEXTRAERR" has_detectors TPC && [[ -z "$DISABLE_ROOT_OUTPUT" && "${SKIP_TPC_CLUSTERSTRACKS_OUTPUT:-}" != 1 ]] && add_W o2-tpc-reco-workflow "--input-type pass-through --output-type clusters,tpc-triggers,tracks,send-clusters-per-sector $DISABLE_MC" From c45d372036304992f8dad681c58dcddd0a27df10 Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 12 Oct 2023 00:11:25 +0200 Subject: [PATCH 275/324] remove unnecessary include --- .../include/GlobalTracking/MatchHMP.h | 1 - .../include/GlobalTracking/MatchTPCITS.h | 49 ++++--- .../GlobalTracking/MatchTPCITSParams.h | 1 + Detectors/GlobalTracking/src/MatchTPCITS.cxx | 136 +++++++++++------- .../src/TPCITSMatchingSpec.cxx | 23 ++- 5 files changed, 119 insertions(+), 91 deletions(-) diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchHMP.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchHMP.h index 0f856bdae9717..0f7e2214220d9 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchHMP.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchHMP.h @@ -37,7 +37,6 @@ #include "DetectorsBase/GeometryManager.h" #include "DataFormatsHMP/Cluster.h" -#include "GlobalTracking/MatchTPCITS.h" #include "DataFormatsTPC/TrackTPC.h" #include "DataFormatsTRD/TrackTRD.h" #include "ReconstructionDataFormats/PID.h" diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h index 7dc23b0af84de..db2f362070492 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h @@ -55,6 +55,9 @@ #include "DataFormatsITSMFT/TrkClusRef.h" #include "ITSMFTReconstruction/ChipMappingITS.h" #include "CorrectionMapsHelper.h" +#if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) +#include "MemoryResources/MemoryResources.h" +#endif class TTree; @@ -228,6 +231,7 @@ struct TPCABSeed { winLinkID = lID; status = Validated; } + int8_t getNLayers() const { return o2::its::RecoGeomHelper::getNLayers() - lowestLayer; } bool needAlteranative() const { return status == NeedAlternative; } void setNeedAlternative() { status = NeedAlternative; } ABTrackLink& getLink(int i) { return trackLinks[i]; } @@ -287,6 +291,8 @@ struct ITSChipClustersRefs { } }; +#if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) + class MatchTPCITS { public: @@ -310,7 +316,15 @@ class MatchTPCITS static constexpr int MaxSeedsPerLayer = 50; // TODO static constexpr int NITSLayers = o2::its::RecoGeomHelper::getNLayers(); ///< perform matching for provided input - void run(const o2::globaltracking::RecoContainer& inp); + void run(const o2::globaltracking::RecoContainer& inp, + pmr::vector& matchedTracks, + pmr::vector& ABTrackletRefs, + pmr::vector& ABTrackletClusterIDs, + pmr::vector& matchLabels, + pmr::vector& ABTrackletLabels, + pmr::vector>& calib); + void refitWinners(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector>& calib); + bool refitTrackTPCITS(int iTPC, int& iITS, pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector>& calib); void setSkipTPCOnly(bool v) { mSkipTPCOnly = v; } void setCosmics(bool v) { mCosmics = v; } @@ -368,13 +382,6 @@ class MatchTPCITS void printCandidatesTPC() const; void printCandidatesITS() const; - const std::vector& getMatchedTracks() const { return mMatchedTracks; } - const MCLabContTr& getMatchLabels() const { return mOutLabels; } - const MCLabContTr& getABTrackletLabels() const { return mABTrackletLabels; } - const std::vector& getABTrackletClusterIDs() const { return mABTrackletClusterIDs; } - const std::vector& getABTrackletRefs() const { return mABTrackletRefs; } - const std::vector& getTglITSTPC() const { return mTglITSTPC; } - //>>> ====================== options =============================>>> void setUseMatCorrFlag(MatCorrType f) { mUseMatCorrFlag = f; } auto getUseMatCorrFlag() const { return mUseMatCorrFlag; } @@ -433,8 +440,6 @@ class MatchTPCITS void doMatching(int sec); - void refitWinners(); - bool refitTrackTPCITS(int iTPC, int& iITS); bool refitTPCInward(o2::track::TrackParCov& trcIn, float& chi2, float xTgt, int trcID, float timeTB) const; void selectBestMatches(); @@ -511,14 +516,14 @@ class MatchTPCITS } // ========================= AFTERBURNER ========================= - void runAfterBurner(); + void runAfterBurner(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector& ABTrackletLabels, pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs); int prepareABSeeds(); void processABSeed(int sid, const ITSChipClustersRefs& itsChipClRefs); int followABSeed(const o2::track::TrackParCov& seed, const ITSChipClustersRefs& itsChipClRefs, int seedID, int lrID, TPCABSeed& ABSeed); int registerABTrackLink(TPCABSeed& ABSeed, const o2::track::TrackParCov& trc, int clID, int parentID, int lr, int laddID, float chi2Cl); bool isBetter(float chi2A, float chi2B) { return chi2A < chi2B; } // RS FIMXE TODO - void refitABWinners(); - bool refitABTrack(int iITSAB, const TPCABSeed& seed); + void refitABWinners(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector& ABTrackletLabels, pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs); + bool refitABTrack(int iITSAB, const TPCABSeed& seed, pmr::vector& matchedTracks, pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs); void accountForOverlapsAB(int lrSeed); float correctTPCTrack(o2::track::TrackParCov& trc, const TrackLocTPC& tTPC, const InteractionCandidate& cand) const; // RS FIXME will be needed for refit //================================================================ @@ -608,7 +613,11 @@ class MatchTPCITS MCLabSpan mTPCTrkLabels; ///< input TPC Track MC labels /// <<<----- + size_t mNMatches = 0; + size_t mNCalibPrelim = 0; size_t mNMatchesControl = 0; + size_t mNABRefsClus = 0; + float mAB2MatchGuess = 0.2; // heuristic guess about fraction of AB matches in total matches std::vector mInteractions; ///< possible interaction times std::vector mInteractionMUSLUT; ///< LUT for interactions in 1MUS bins @@ -630,11 +639,7 @@ class MatchTPCITS ///< indices of selected track entries in mTPCWork (for tracks selected by AfterBurner) std::vector mTPCABIndexCache; std::vector mABWinnersIDs; - std::vector mABTrackletClusterIDs; ///< IDs of ITS clusters for AfterBurner winners - std::vector mABTrackletRefs; ///< references on AfterBurner winners clusters - std::vector mABClusterLinkIndex; ///< index of 1st ABClusterLink for every cluster used by AfterBurner, -1: unused, -10: used by external ITS tracks - MCLabContTr mABTrackletLabels; - // ------------------------------ + std::vector mABClusterLinkIndex; ///< index of 1st ABClusterLink for every cluster used by AfterBurner, -1: unused, -10: used by external ITS tracks ///< per sector indices of TPC track entry in mTPCWork std::array, o2::constants::math::NSectors> mTPCSectIndexCache; @@ -649,13 +654,6 @@ class MatchTPCITS /// mapping for tracks' continuos ROF cycle to actual continuous readout ROFs with eventual gaps std::vector mITSTrackROFContMapping; - ///< outputs tracks container - std::vector mMatchedTracks; - MCLabContTr mOutLabels; ///< Labels: = TPC labels with flag isFake set in case of fake matching - - ///< container for for vdrift calibration - std::vector mTglITSTPC; - o2::its::RecoGeomHelper mRGHelper; ///< helper for cluster and geometry access #ifdef _ALLOW_DEBUG_TREES_ @@ -712,4 +710,5 @@ inline bool MatchTPCITS::isDisabledTPC(const TrackLocTPC& t) const { return t.ma } // namespace globaltracking } // namespace o2 +#endif // cling #endif diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h index 7bdd883336859..6718c48e42570 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h @@ -71,6 +71,7 @@ struct MatchTPCITSParams : public o2::conf::ConfigurableParamHelper& matchedTracks, + pmr::vector& ABTrackletRefs, + pmr::vector& ABTrackletClusterIDs, + pmr::vector& matchLabels, + pmr::vector& ABTrackletLabels, + pmr::vector>& calib) { ///< perform matching for provided input if (!mInitDone) { @@ -83,8 +89,8 @@ void MatchTPCITS::run(const o2::globaltracking::RecoContainer& inp) break; } if (mVDriftCalibOn) { // in the beginning of the output vector we send the full and reference VDrift used for this TF - mTglITSTPC.emplace_back(mTPCVDrift, mTPCDrift.refVDrift, -999.); - mTglITSTPC.emplace_back(mTPCDriftTimeOffset, mTPCDrift.refTimeOffset, -999.); + calib.emplace_back(mTPCVDrift, mTPCDrift.refVDrift, -999.); + calib.emplace_back(mTPCDriftTimeOffset, mTPCDrift.refTimeOffset, -999.); } mTimer[SWDoMatching].Start(false); @@ -101,10 +107,10 @@ void MatchTPCITS::run(const o2::globaltracking::RecoContainer& inp) selectBestMatches(); - refitWinners(); + refitWinners(matchedTracks, matchLabels, calib); if (mUseFT0 && Params::Instance().runAfterBurner) { - runAfterBurner(); + runAfterBurner(matchedTracks, matchLabels, ABTrackletLabels, ABTrackletClusterIDs, ABTrackletRefs); } #ifdef _ALLOW_DEBUG_TREES_ @@ -139,7 +145,6 @@ void MatchTPCITS::clear() mMatchRecordsTPC.clear(); mMatchRecordsITS.clear(); mWinnerChi2Refit.clear(); - mMatchedTracks.clear(); mITSWork.clear(); mTPCWork.clear(); mInteractions.clear(); @@ -150,10 +155,6 @@ void MatchTPCITS::clear() mTPCABIndexCache.clear(); mABWinnersIDs.clear(); mABClusterLinkIndex.clear(); - mABTrackletRefs.clear(); - mABTrackletClusterIDs.clear(); - mABTrackletLabels.clear(); - mTglITSTPC.clear(); mNMatchesControl = 0; for (int sec = o2::constants::math::NSectors; sec--;) { @@ -164,7 +165,6 @@ void MatchTPCITS::clear() } if (mMCTruthON) { - mOutLabels.clear(); mITSROFTimes.clear(); mTPCLblWork.clear(); } @@ -197,6 +197,7 @@ void MatchTPCITS::init() mTimer[i].Reset(); } mParams = &Params::Instance(); + mAB2MatchGuess = mParams->AB2MatchGuess; YMaxAtXMatchingRef = mParams->XMatchingRef * 0.17632698; ///< max Y in the sector at reference X mParams->printKeyValues(); mFT0Params = &o2::ft0::InteractionTag::Instance(); @@ -263,7 +264,9 @@ void MatchTPCITS::selectBestMatches() { ///< loop over match records and select the ones with best chi2 mTimer[SWSelectBest].Start(false); - int nValidated = 0, iter = 0, nValidatedTotal = 0; + int nValidated = 0, iter = 0; + mNMatches = 0; + mNCalibPrelim = 0; do { nValidated = 0; int ntpc = mTPCWork.size(), nremaining = 0; @@ -275,6 +278,9 @@ void MatchTPCITS::selectBestMatches() nremaining++; if (validateTPCMatch(it)) { nValidated++; + if (mVDriftCalibOn && (!mFieldON || std::abs(tTPC.getQ2Pt()) < mParams->maxVDriftTrackQ2Pt)) { + mNCalibPrelim++; + } continue; } } @@ -282,11 +288,11 @@ void MatchTPCITS::selectBestMatches() LOGP(info, "iter {}: Validated {} of {} remaining matches", iter, nValidated, nremaining); } iter++; - nValidatedTotal += nValidated; + mNMatches += nValidated; } while (nValidated); mTimer[SWSelectBest].Stop(); - LOGP(info, "Validated {} matches out of {} for {} TPC and {} ITS tracks in {} iterations", nValidatedTotal, mNMatchesControl, mTPCWork.size(), mITSWork.size(), iter); + LOGP(info, "Validated {} matches out of {} for {} TPC and {} ITS tracks in {} iterations", mNMatches, mNMatchesControl, mTPCWork.size(), mITSWork.size(), iter); } //______________________________________________ @@ -1247,40 +1253,51 @@ void MatchTPCITS::print() const } //______________________________________________ -void MatchTPCITS::refitWinners() +void MatchTPCITS::refitWinners(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector>& calib) { ///< refit winning tracks - mTimer[SWRefit].Start(false); + if (mMCTruthON) { + matchLabels.reserve(mNMatches); + } + if (mVDriftCalibOn) { + calib.reserve(mNCalibPrelim * 1.2 + 1); + } + auto nmEst = mNMatches; + if (mUseFT0 && Params::Instance().runAfterBurner) { + nmEst += mNMatches + mNMatches * mAB2MatchGuess; + if (nmEst < 1) { + nmEst = mTPCWork.size() / 2; + LOGP(warn, "No track-to-track matches were found, preliminary estimate of AB yield set {}", nmEst); + } + } + matchedTracks.reserve(nmEst); + LOG(debug) << "Refitting winner matches"; mWinnerChi2Refit.resize(mITSWork.size(), -1.f); int iITS; for (int iTPC = 0; iTPC < (int)mTPCWork.size(); iTPC++) { - if (!refitTrackTPCITS(iTPC, iITS)) { + if (isDisabledTPC(mTPCWork[iTPC]) || !refitTrackTPCITS(iTPC, iITS, matchedTracks, matchLabels, calib)) { continue; } - mWinnerChi2Refit[iITS] = mMatchedTracks.back().getChi2Refit(); + mWinnerChi2Refit[iITS] = matchedTracks.back().getChi2Refit(); } mTimer[SWRefit].Stop(); } //______________________________________________ -bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS) +bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS, pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector>& calib) { ///< refit in inward direction the pair of TPC and ITS tracks const float maxStep = 2.f; // max propagation step (TODO: tune) const auto& tTPC = mTPCWork[iTPC]; - if (isDisabledTPC(tTPC)) { - return false; // no match - } const auto& tpcMatchRec = mMatchRecordsTPC[tTPC.matchID]; iITS = tpcMatchRec.partnerID; const auto& tITS = mITSWork[iITS]; const auto& itsTrOrig = mITSTracksArray[tITS.sourceID]; - mMatchedTracks.emplace_back(tTPC, tITS); // create a copy of TPC track at xRef - auto& trfit = mMatchedTracks.back(); + auto& trfit = matchedTracks.emplace_back(tTPC, tITS); // create a copy of TPC track at xRef trfit.getParamOut().setUserField(0); // reset eventual clones flag // in continuos mode the Z of TPC track is meaningless, unless it is CE crossing // track (currently absent, TODO) @@ -1297,7 +1314,7 @@ bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS) float timeC = tTPC.getCorrectedTime(deltaT) + mParams->globalTimeBiasMUS; /// precise time estimate, optionally corrected for bias if (timeC < 0) { // RS TODO similar check is needed for other edge of TF if (timeC + std::min(timeErr, mParams->tfEdgeTimeToleranceMUS * mTPCTBinMUSInv) < 0) { - mMatchedTracks.pop_back(); // destroy failed track + matchedTracks.pop_back(); // destroy failed track return false; } timeC = 0.; @@ -1338,7 +1355,7 @@ bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS) if (nclRefit != ncl) { LOGP(debug, "Refit in ITS failed after ncl={}, match between TPC track #{} and ITS track #{}", nclRefit, tTPC.sourceID, tITS.sourceID); LOGP(debug, "{:s}", trfit.asString()); - mMatchedTracks.pop_back(); // destroy failed track + matchedTracks.pop_back(); // destroy failed track return false; } @@ -1360,7 +1377,7 @@ bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS) if (!tracOut.getXatLabR(o2::constants::geom::XTPCInnerRef, xtogo, mBz, o2::track::DirOutward) || !propagator->PropagateToXBxByBz(tracOut, xtogo, MaxSnp, 10., mUseMatCorrFlag, &tofL)) { LOG(debug) << "Propagation to inner TPC boundary X=" << xtogo << " failed, Xtr=" << tracOut.getX() << " snp=" << tracOut.getSnp(); - mMatchedTracks.pop_back(); // destroy failed track + matchedTracks.pop_back(); // destroy failed track return false; } if (mVDriftCalibOn) { @@ -1373,13 +1390,13 @@ bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS) LOGP(alarm, "Impossible imposed timebin {} for TPC track time0:{}, dBwd:{} dFwd:{} TB | ZShift:{}, TShift:{}", tImposed, mTPCTracksArray[tTPC.sourceID].getTime0(), mTPCTracksArray[tTPC.sourceID].getDeltaTBwd(), mTPCTracksArray[tTPC.sourceID].getDeltaTFwd(), trfit.getZ() - tTPC.getZ(), deltaT); LOGP(info, "Trc: {}", mTPCTracksArray[tTPC.sourceID].asString()); - mMatchedTracks.pop_back(); // destroy failed track + matchedTracks.pop_back(); // destroy failed track return false; } int retVal = mTPCRefitter->RefitTrackAsTrackParCov(tracOut, mTPCTracksArray[tTPC.sourceID].getClusterRef(), tImposed, &chi2Out, true, false); // outward refit if (retVal < 0) { LOG(debug) << "Refit failed"; - mMatchedTracks.pop_back(); // destroy failed track + matchedTracks.pop_back(); // destroy failed track return false; } auto posEnd = tracOut.getXYZGlo(); @@ -1413,7 +1430,7 @@ bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS) trfit.setRefITS({unsigned(tITS.sourceID), o2::dataformats::GlobalTrackID::ITS}); if (mMCTruthON) { // store MC info: we assign TPC track label and declare the match fake if the ITS and TPC labels are different (their fake flag is ignored) - auto& lbl = mOutLabels.emplace_back(mTPCLblWork[iTPC]); + auto& lbl = matchLabels.emplace_back(mTPCLblWork[iTPC]); lbl.setFakeFlag(mITSLblWork[iITS] != mTPCLblWork[iTPC]); } @@ -1445,7 +1462,7 @@ bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS) } } if (fillVDCalib) { - mTglITSTPC.emplace_back(tITS.getTgl(), tTPC.getTgl(), minDiffFT0); + calib.emplace_back(tITS.getTgl(), tTPC.getTgl(), minDiffFT0); } #ifdef _ALLOW_DEBUG_TREES_ if (mDBGOut) { @@ -1466,14 +1483,14 @@ bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS) } //______________________________________________ -bool MatchTPCITS::refitABTrack(int iITSAB, const TPCABSeed& seed) +bool MatchTPCITS::refitABTrack(int iITSAB, const TPCABSeed& seed, pmr::vector& matchedTracks, pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs) { ///< refit AfterBurner track const float maxStep = 2.f; // max propagation step (TODO: tune) const auto& tTPC = mTPCWork[seed.tpcWID]; const auto& winLink = seed.getLink(seed.winLinkID); - auto& newtr = mMatchedTracks.emplace_back(winLink, winLink); // create a copy of winner param at innermost ITS cluster + auto& newtr = matchedTracks.emplace_back(winLink, winLink); // create a copy of winner param at innermost ITS cluster auto& tracOut = newtr.getParamOut(); auto& tofL = newtr.getLTIntegralOut(); auto geom = o2::its::GeometryTGeo::Instance(); @@ -1482,13 +1499,13 @@ bool MatchTPCITS::refitABTrack(int iITSAB, const TPCABSeed& seed) propagator->estimateLTFast(tofL, winLink); // guess about initial value for the track integral from the origin // refit track outward in the ITS - const auto& itsClRefs = mABTrackletRefs[iITSAB]; + const auto& itsClRefs = ABTrackletRefs[iITSAB]; int nclRefit = 0, ncl = itsClRefs.getNClusters(); float chi2 = 0.f; // NOTE: the ITS cluster absolute indices are stored from inner to outer layers for (int icl = itsClRefs.getFirstEntry(); icl < itsClRefs.getEntriesBound(); icl++) { - const auto& clus = mITSClustersArray[mABTrackletClusterIDs[icl]]; + const auto& clus = mITSClustersArray[ABTrackletClusterIDs[icl]]; float alpha = geom->getSensorRefAlpha(clus.getSensorID()), x = clus.getX(); if (!tracOut.rotate(alpha) || // note: here we also calculate the L,T integral @@ -1506,7 +1523,7 @@ bool MatchTPCITS::refitABTrack(int iITSAB, const TPCABSeed& seed) if (nclRefit != ncl) { LOGP(debug, "AfterBurner refit in ITS failed after ncl={}, match between TPC track #{} and ITS tracklet #{}", nclRefit, tTPC.sourceID, iITSAB); LOGP(debug, "{:s}", tracOut.asString()); - mMatchedTracks.pop_back(); // destroy failed track + matchedTracks.pop_back(); // destroy failed track return false; } // perform TPC refit with interaction time constraint @@ -1517,7 +1534,7 @@ bool MatchTPCITS::refitABTrack(int iITSAB, const TPCABSeed& seed) if (!tracOut.getXatLabR(o2::constants::geom::XTPCInnerRef, xtogo, mBz, o2::track::DirOutward) || !propagator->PropagateToXBxByBz(tracOut, xtogo, MaxSnp, 10., mUseMatCorrFlag, &tofL)) { LOG(debug) << "Propagation to inner TPC boundary X=" << xtogo << " failed, Xtr=" << tracOut.getX() << " snp=" << tracOut.getSnp(); - mMatchedTracks.pop_back(); // destroy failed track + matchedTracks.pop_back(); // destroy failed track return false; } float chi2Out = 0; @@ -1525,7 +1542,7 @@ bool MatchTPCITS::refitABTrack(int iITSAB, const TPCABSeed& seed) int retVal = mTPCRefitter->RefitTrackAsTrackParCov(tracOut, mTPCTracksArray[tTPC.sourceID].getClusterRef(), timeC * mTPCTBinMUSInv, &chi2Out, true, false); // outward refit if (retVal < 0) { LOG(debug) << "Refit failed"; - mMatchedTracks.pop_back(); // destroy failed track + matchedTracks.pop_back(); // destroy failed track return false; } auto posEnd = tracOut.getXYZGlo(); @@ -1699,9 +1716,10 @@ int MatchTPCITS::prepareInteractionTimes() } //______________________________________________ -void MatchTPCITS::runAfterBurner() +void MatchTPCITS::runAfterBurner(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector& ABTrackletLabels, pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs) { mTimer[SWABSeeds].Start(false); + mNABRefsClus = 0; prepareABSeeds(); int nIntCand = mInteractions.size(), nABSeeds = mTPCABSeeds.size(); LOGP(info, "AfterBurner will check {} seeds from {} TPC tracks and {} interaction candidates with {} threads", nABSeeds, mTPCABIndexCache.size(), nIntCand, mNThreads); // TMP @@ -1780,23 +1798,35 @@ void MatchTPCITS::runAfterBurner() ABSeed.validate(bestID); ABSeed.flagLinkUsedClusters(bestID, mABClusterLinkIndex); mABWinnersIDs.push_back(tTPC.matchID = candAB[i].seedID); + mNABRefsClus += ABSeed.getNLayers(); nwin++; // RSTMP LOG(info) << "Iter: " << iter << " validated seed " << i << "[" << candAB[i].seedID << "/" << candAB[i].chi2 << "] for TPC track " << ABSeed.tpcWID << " last lr: " << int(ABSeed.lowestLayer) << " Ncont: " << int(link.nContLayers); } mTimer[SWABWinners].Stop(); mTimer[SWABRefit].Start(false); - refitABWinners(); + refitABWinners(matchedTracks, matchLabels, ABTrackletLabels, ABTrackletClusterIDs, ABTrackletRefs); mTimer[SWABRefit].Stop(); } //______________________________________________ -void MatchTPCITS::refitABWinners() +void MatchTPCITS::refitABWinners(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector& ABTrackletLabels, + pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs) { - mABTrackletClusterIDs.reserve(mABWinnersIDs.size() * (o2::its::RecoGeomHelper::getNLayers() - mParams->lowestLayerAB)); - mABTrackletRefs.reserve(mABWinnersIDs.size()); + ABTrackletClusterIDs.reserve(mABWinnersIDs.size() * mNABRefsClus); + ABTrackletRefs.reserve(mABWinnersIDs.size()); if (mMCTruthON) { - mABTrackletLabels.reserve(mABWinnersIDs.size()); + ABTrackletLabels.reserve(mABWinnersIDs.size()); } + if (matchedTracks.capacity() < mABWinnersIDs.size() + matchedTracks.size()) { + LOGP(warn, "need to expand matched tracks container from {} to {}", matchedTracks.capacity(), mABWinnersIDs.size() + matchedTracks.size()); + matchedTracks.reserve(mABWinnersIDs.size() + matchedTracks.size()); + } + float frac = matchedTracks.size() ? float(mABWinnersIDs.size()) / matchedTracks.size() : 0.; + if (frac > mAB2MatchGuess) { + LOGP(warn, "increasing guessed ratio of AB to full matches from {} to {}", mAB2MatchGuess, frac * 1.1); + mAB2MatchGuess = frac * 1.1; + } + std::map labelOccurence; auto accountClusterLabel = [&labelOccurence, itsClLabs = mITSClsLabels](int clID) { auto labels = itsClLabs->getLabels(clID); @@ -1809,13 +1839,13 @@ void MatchTPCITS::refitABWinners() for (auto wid : mABWinnersIDs) { const auto& ABSeed = mTPCABSeeds[wid]; - int start = mABTrackletClusterIDs.size(); + int start = ABTrackletClusterIDs.size(); int lID = ABSeed.winLinkID, ncl = 0; - auto& clref = mABTrackletRefs.emplace_back(start, ncl); + auto& clref = ABTrackletRefs.emplace_back(start, ncl); while (lID > MinusOne) { const auto& winL = ABSeed.getLink(lID); if (winL.clID > MinusOne) { - mABTrackletClusterIDs.push_back(winL.clID); + ABTrackletClusterIDs.push_back(winL.clID); ncl++; clref.pattern |= 0x1 << winL.layerID; if (mMCTruthON) { @@ -1824,9 +1854,9 @@ void MatchTPCITS::refitABWinners() } lID = winL.parentID; } - if (!refitABTrack(mABTrackletRefs.size() - 1, ABSeed)) { // on failure, destroy added tracklet reference - mABTrackletRefs.pop_back(); - mABTrackletClusterIDs.resize(start); + if (!refitABTrack(ABTrackletRefs.size() - 1, ABSeed, matchedTracks, ABTrackletClusterIDs, ABTrackletRefs)) { // on failure, destroy added tracklet reference + ABTrackletRefs.pop_back(); + ABTrackletClusterIDs.resize(start); // RSS if (mMCTruthON) { labelOccurence.clear(); } @@ -1846,14 +1876,14 @@ void MatchTPCITS::refitABWinners() lab.setFakeFlag(); } labelOccurence.clear(); - mABTrackletLabels.push_back(lab); // ITSAB tracklet label - auto& lblGlo = mOutLabels.emplace_back(mTPCLblWork[ABSeed.tpcWID]); + ABTrackletLabels.push_back(lab); // ITSAB tracklet label + auto& lblGlo = matchLabels.emplace_back(mTPCLblWork[ABSeed.tpcWID]); lblGlo.setFakeFlag(lab != lblGlo); LOG(debug) << "ABWinner ncl=" << ncl << " mcLBAB " << lab << " mcLBGlo " << lblGlo << " chi2=" << ABSeed.getLink(ABSeed.winLinkID).chi2Norm() << " pT = " << ABSeed.track.getPt(); } // build MC label } - LOG(info) << "AfterBurner validated " << mABTrackletRefs.size() << " tracks"; + LOG(info) << "AfterBurner validated " << ABTrackletRefs.size() << " tracks"; } //______________________________________________ diff --git a/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx index 48600e5eb0d38..819a6cd231560 100644 --- a/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx @@ -100,19 +100,18 @@ void TPCITSMatchingDPL::run(ProcessingContext& pc) recoData.collectData(pc, *mDataRequest.get()); updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions - mMatching.run(recoData); - - pc.outputs().snapshot(Output{"GLO", "TPCITS", 0, Lifetime::Timeframe}, mMatching.getMatchedTracks()); - pc.outputs().snapshot(Output{"GLO", "TPCITSAB_REFS", 0, Lifetime::Timeframe}, mMatching.getABTrackletRefs()); - pc.outputs().snapshot(Output{"GLO", "TPCITSAB_CLID", 0, Lifetime::Timeframe}, mMatching.getABTrackletClusterIDs()); - if (mUseMC) { - pc.outputs().snapshot(Output{"GLO", "TPCITS_MC", 0, Lifetime::Timeframe}, mMatching.getMatchLabels()); - pc.outputs().snapshot(Output{"GLO", "TPCITSAB_MC", 0, Lifetime::Timeframe}, mMatching.getABTrackletLabels()); - } + static pmr::vector dummyMCLab, dummyMCLabAB; + static pmr::vector> dummyCalib; + + auto& matchedTracks = pc.outputs().make>(Output{"GLO", "TPCITS", 0, Lifetime::Timeframe}); + auto& ABTrackletRefs = pc.outputs().make>(Output{"GLO", "TPCITSAB_REFS", 0, Lifetime::Timeframe}); + auto& ABTrackletClusterIDs = pc.outputs().make>(Output{"GLO", "TPCITSAB_CLID", 0, Lifetime::Timeframe}); + auto& matchLabels = mUseMC ? pc.outputs().make>(Output{"GLO", "TPCITS_MC", 0, Lifetime::Timeframe}) : dummyMCLab; + auto& ABTrackletLabels = mUseMC ? pc.outputs().make>(Output{"GLO", "TPCITSAB_MC", 0, Lifetime::Timeframe}) : dummyMCLabAB; + auto& calib = mCalibMode ? pc.outputs().make>>(Output{"GLO", "TPCITS_VDTGL", 0, Lifetime::Timeframe}) : dummyCalib; + + mMatching.run(recoData, matchedTracks, ABTrackletRefs, ABTrackletClusterIDs, matchLabels, ABTrackletLabels, calib); - if (mCalibMode) { - pc.outputs().snapshot(Output{"GLO", "TPCITS_VDTGL", 0, Lifetime::Timeframe}, mMatching.getTglITSTPC()); - } mTimer.Stop(); } From acc1785568390eb7d467dd8a33b8179e83b42609 Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 12 Oct 2023 01:01:20 +0200 Subject: [PATCH 276/324] Optimize ITS/TPC mathing memory usage --- Detectors/GlobalTracking/CMakeLists.txt | 1 + .../include/GlobalTracking/MatchTPCITS.h | 41 +-- .../GlobalTracking/MatchTPCITSParams.h | 1 - Detectors/GlobalTracking/src/MatchTPCITS.cxx | 235 +++++++++++++++--- 4 files changed, 219 insertions(+), 59 deletions(-) diff --git a/Detectors/GlobalTracking/CMakeLists.txt b/Detectors/GlobalTracking/CMakeLists.txt index f681ac1b84f46..bd5fb4f9976d1 100644 --- a/Detectors/GlobalTracking/CMakeLists.txt +++ b/Detectors/GlobalTracking/CMakeLists.txt @@ -8,6 +8,7 @@ # In applying this license CERN does not waive the privileges and immunities # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +# add_compile_options(-O0 -g -fPIC) o2_add_library(GlobalTracking TARGETVARNAME targetName diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h index db2f362070492..506ca2222aca2 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h @@ -263,6 +263,8 @@ struct TPCABSeed { linkID = link.parentID; } } + size_t sizeInternal() const { return sizeof(ABTrackLink) * trackLinks.size(); } + size_t capInternal() const { return sizeof(ABTrackLink) * trackLinks.capacity(); } }; struct InteractionCandidate : public o2::InteractionRecord { @@ -289,18 +291,15 @@ struct ITSChipClustersRefs { clusterID.clear(); std::memset(chipRefs.data(), 0, chipRefs.size() * sizeof(ClusRange)); // reset chip->cluster references } + size_t sizeInternal() const { return sizeof(int) * clusterID.size(); } + size_t capInternal() const { return sizeof(int) * clusterID.capacity(); } }; -#if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) - class MatchTPCITS { public: using ITSCluster = o2::BaseCluster; using ClusRange = o2::dataformats::RangeReference; - using MCLabContCl = o2::dataformats::MCTruthContainer; - using MCLabContTr = std::vector; - using MCLabSpan = gsl::span; using TPCTransform = o2::gpu::TPCFastTransform; using BracketF = o2::math_utils::Bracket; using BracketIR = o2::math_utils::Bracket; @@ -316,6 +315,7 @@ class MatchTPCITS static constexpr int MaxSeedsPerLayer = 50; // TODO static constexpr int NITSLayers = o2::its::RecoGeomHelper::getNLayers(); ///< perform matching for provided input +#if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) void run(const o2::globaltracking::RecoContainer& inp, pmr::vector& matchedTracks, pmr::vector& ABTrackletRefs, @@ -325,7 +325,18 @@ class MatchTPCITS pmr::vector>& calib); void refitWinners(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector>& calib); bool refitTrackTPCITS(int iTPC, int& iITS, pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector>& calib); - + void reportSizes(pmr::vector& matchedTracks, + pmr::vector& ABTrackletRefs, + pmr::vector& ABTrackletClusterIDs, + pmr::vector& matchLabels, + pmr::vector& ABTrackletLabels, + pmr::vector>& calib); + bool runAfterBurner(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector& ABTrackletLabels, pmr::vector& ABTrackletClusterIDs, + pmr::vector& ABTrackletRefs, pmr::vector>& calib); + void refitABWinners(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector& ABTrackletLabels, pmr::vector& ABTrackletClusterIDs, + pmr::vector& ABTrackletRefs, pmr::vector>& calib); + bool refitABTrack(int iITSAB, const TPCABSeed& seed, pmr::vector& matchedTracks, pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs); +#endif // CLING void setSkipTPCOnly(bool v) { mSkipTPCOnly = v; } void setCosmics(bool v) { mCosmics = v; } bool isCosmics() const { return mCosmics; } @@ -516,14 +527,11 @@ class MatchTPCITS } // ========================= AFTERBURNER ========================= - void runAfterBurner(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector& ABTrackletLabels, pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs); int prepareABSeeds(); void processABSeed(int sid, const ITSChipClustersRefs& itsChipClRefs); int followABSeed(const o2::track::TrackParCov& seed, const ITSChipClustersRefs& itsChipClRefs, int seedID, int lrID, TPCABSeed& ABSeed); int registerABTrackLink(TPCABSeed& ABSeed, const o2::track::TrackParCov& trc, int clID, int parentID, int lr, int laddID, float chi2Cl); bool isBetter(float chi2A, float chi2B) { return chi2A < chi2B; } // RS FIMXE TODO - void refitABWinners(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector& ABTrackletLabels, pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs); - bool refitABTrack(int iITSAB, const TPCABSeed& seed, pmr::vector& matchedTracks, pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs); void accountForOverlapsAB(int lrSeed); float correctTPCTrack(o2::track::TrackParCov& trc, const TrackLocTPC& tTPC, const InteractionCandidate& cand) const; // RS FIXME will be needed for refit //================================================================ @@ -608,9 +616,9 @@ class MatchTPCITS const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices - const MCLabContCl* mITSClsLabels = nullptr; ///< input ITS Cluster MC labels - MCLabSpan mITSTrkLabels; ///< input ITS Track MC labels - MCLabSpan mTPCTrkLabels; ///< input TPC Track MC labels + const o2::dataformats::MCTruthContainer* mITSClsLabels = nullptr; ///< input ITS Cluster MC labels + gsl::span mITSTrkLabels; ///< input ITS Track MC labels + gsl::span mTPCTrkLabels; ///< input TPC Track MC labels /// <<<----- size_t mNMatches = 0; @@ -622,16 +630,16 @@ class MatchTPCITS std::vector mInteractionMUSLUT; ///< LUT for interactions in 1MUS bins ///< container for record the match of TPC track to single ITS track - std::vector mMatchRecordsTPC; + std::vector mMatchRecordsTPC; // RSS DEQ ///< container for reference to MatchRecord involving particular ITS track - std::vector mMatchRecordsITS; + std::vector mMatchRecordsITS; // RSS DEQ //// std::vector mITSROFofTPCBin; ///< aux structure for mapping of TPC time-bins on ITS ROFs std::vector mITSROFTimes; ///< min/max times of ITS ROFs in \mus std::vector mTPCWork; ///< TPC track params prepared for matching std::vector mITSWork; ///< ITS track params prepared for matching - MCLabContTr mTPCLblWork; ///< TPC track labels - MCLabContTr mITSLblWork; ///< ITS track labels + std::vector mTPCLblWork; ///< TPC track labels + std::vector mITSLblWork; ///< ITS track labels std::vector mWinnerChi2Refit; ///< vector of refitChi2 for winners // ------------------------------ @@ -710,5 +718,4 @@ inline bool MatchTPCITS::isDisabledTPC(const TrackLocTPC& t) const { return t.ma } // namespace globaltracking } // namespace o2 -#endif // cling #endif diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h index 6718c48e42570..7bdd883336859 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h @@ -71,7 +71,6 @@ struct MatchTPCITSParams : public o2::conf::ConfigurableParamHelperverbosity > 0) { + reportSizes(matchedTracks, ABTrackletRefs, ABTrackletClusterIDs, matchLabels, ABTrackletLabels, calib); } - #ifdef _ALLOW_DEBUG_TREES_ if (mDBGOut && isDebugFlag(WinnerMatchesTree)) { dumpWinnerMatches(); @@ -165,8 +169,8 @@ void MatchTPCITS::clear() } if (mMCTruthON) { - mITSROFTimes.clear(); mTPCLblWork.clear(); + mITSLblWork.clear(); } } @@ -197,7 +201,6 @@ void MatchTPCITS::init() mTimer[i].Reset(); } mParams = &Params::Instance(); - mAB2MatchGuess = mParams->AB2MatchGuess; YMaxAtXMatchingRef = mParams->XMatchingRef * 0.17632698; ///< max Y in the sector at reference X mParams->printKeyValues(); mFT0Params = &o2::ft0::InteractionTag::Instance(); @@ -298,7 +301,7 @@ void MatchTPCITS::selectBestMatches() //______________________________________________ bool MatchTPCITS::validateTPCMatch(int iTPC) { - const auto& tTPC = mTPCWork[iTPC]; + auto& tTPC = mTPCWork[iTPC]; auto& rcTPC = mMatchRecordsTPC[tTPC.matchID]; // best TPC->ITS match // check if it is consistent with corresponding ITS->TPC match auto& tITS = mITSWork[rcTPC.partnerID]; // partner ITS track @@ -345,6 +348,7 @@ bool MatchTPCITS::validateTPCMatch(int iTPC) nextITS = rcITSrem.nextRecID; } rcITS.nextRecID = Validated; + tTPC.gid.setBit(0); // Flag full match return true; } return false; @@ -448,14 +452,14 @@ bool MatchTPCITS::prepareTPCData() mTPCTrkLabels = inp.getTPCTracksMCLabels(); } - int ntr = mTPCTracksArray.size(); - mMatchRecordsTPC.reserve(mParams->maxMatchCandidates * ntr); // number of records might be actually more than N tracks! - mTPCWork.reserve(ntr); + int ntr = mTPCTracksArray.size(), ntrW = 0.7 * ntr; + mMatchRecordsTPC.reserve(mParams->maxMatchCandidates * ntrW); // number of records might be actually more than N tracks! + mTPCWork.reserve(ntrW); if (mMCTruthON) { - mTPCLblWork.reserve(ntr); + mTPCLblWork.reserve(ntrW); } for (int sec = o2::constants::math::NSectors; sec--;) { - mTPCSectIndexCache[sec].reserve(100 + 1.2 * ntr / o2::constants::math::NSectors); + mTPCSectIndexCache[sec].reserve(100 + 1.2 * ntrW / o2::constants::math::NSectors); } auto creator = [this](auto& trk, GTrackID gid, float time0, float terr) { @@ -1257,27 +1261,20 @@ void MatchTPCITS::refitWinners(pmr::vector& matche { ///< refit winning tracks mTimer[SWRefit].Start(false); + matchedTracks.reserve(mNMatches + mABWinnersIDs.size()); if (mMCTruthON) { - matchLabels.reserve(mNMatches); + matchLabels.reserve(mNMatches + mABWinnersIDs.size()); } if (mVDriftCalibOn) { calib.reserve(mNCalibPrelim * 1.2 + 1); } - auto nmEst = mNMatches; - if (mUseFT0 && Params::Instance().runAfterBurner) { - nmEst += mNMatches + mNMatches * mAB2MatchGuess; - if (nmEst < 1) { - nmEst = mTPCWork.size() / 2; - LOGP(warn, "No track-to-track matches were found, preliminary estimate of AB yield set {}", nmEst); - } - } - matchedTracks.reserve(nmEst); LOG(debug) << "Refitting winner matches"; mWinnerChi2Refit.resize(mITSWork.size(), -1.f); int iITS; for (int iTPC = 0; iTPC < (int)mTPCWork.size(); iTPC++) { - if (isDisabledTPC(mTPCWork[iTPC]) || !refitTrackTPCITS(iTPC, iITS, matchedTracks, matchLabels, calib)) { + const auto& tTPC = mTPCWork[iTPC]; + if (isDisabledTPC(tTPC) || !tTPC.gid.testBit(0) || !refitTrackTPCITS(iTPC, iITS, matchedTracks, matchLabels, calib)) { continue; } mWinnerChi2Refit[iITS] = matchedTracks.back().getChi2Refit(); @@ -1716,7 +1713,8 @@ int MatchTPCITS::prepareInteractionTimes() } //______________________________________________ -void MatchTPCITS::runAfterBurner(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector& ABTrackletLabels, pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs) +bool MatchTPCITS::runAfterBurner(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector& ABTrackletLabels, + pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs, pmr::vector>& calib) { mTimer[SWABSeeds].Start(false); mNABRefsClus = 0; @@ -1725,7 +1723,7 @@ void MatchTPCITS::runAfterBurner(pmr::vector& matc LOGP(info, "AfterBurner will check {} seeds from {} TPC tracks and {} interaction candidates with {} threads", nABSeeds, mTPCABIndexCache.size(), nIntCand, mNThreads); // TMP mTimer[SWABSeeds].Stop(); if (!nIntCand || !mTPCABSeeds.size()) { - return; + return false; } mTimer[SWABMatch].Start(false); std::vector itsChipClRefsBuff(mNThreads); @@ -1804,15 +1802,19 @@ void MatchTPCITS::runAfterBurner(pmr::vector& matc } mTimer[SWABWinners].Stop(); mTimer[SWABRefit].Start(false); - refitABWinners(matchedTracks, matchLabels, ABTrackletLabels, ABTrackletClusterIDs, ABTrackletRefs); + refitABWinners(matchedTracks, matchLabels, ABTrackletLabels, ABTrackletClusterIDs, ABTrackletRefs, calib); mTimer[SWABRefit].Stop(); + return true; } //______________________________________________ void MatchTPCITS::refitABWinners(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector& ABTrackletLabels, - pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs) + pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs, pmr::vector>& calib) { - ABTrackletClusterIDs.reserve(mABWinnersIDs.size() * mNABRefsClus); + // refit normal matches + refitWinners(matchedTracks, matchLabels, calib); + + ABTrackletClusterIDs.reserve(mNABRefsClus); ABTrackletRefs.reserve(mABWinnersIDs.size()); if (mMCTruthON) { ABTrackletLabels.reserve(mABWinnersIDs.size()); @@ -1821,11 +1823,6 @@ void MatchTPCITS::refitABWinners(pmr::vector& matc LOGP(warn, "need to expand matched tracks container from {} to {}", matchedTracks.capacity(), mABWinnersIDs.size() + matchedTracks.size()); matchedTracks.reserve(mABWinnersIDs.size() + matchedTracks.size()); } - float frac = matchedTracks.size() ? float(mABWinnersIDs.size()) / matchedTracks.size() : 0.; - if (frac > mAB2MatchGuess) { - LOGP(warn, "increasing guessed ratio of AB to full matches from {} to {}", mAB2MatchGuess, frac * 1.1); - mAB2MatchGuess = frac * 1.1; - } std::map labelOccurence; auto accountClusterLabel = [&labelOccurence, itsClLabs = mITSClsLabels](int clID) { @@ -2424,6 +2421,168 @@ int MatchTPCITS::preselectChipClusters(std::vector& clVecOut, const ClusRan return clVecOut.size(); } +//__________________________________________________________ +void MatchTPCITS::reportSizes(pmr::vector& matchedTracks, + pmr::vector& ABTrackletRefs, + pmr::vector& ABTrackletClusterIDs, + pmr::vector& matchLabels, + pmr::vector& ABTrackletLabels, + pmr::vector>& calib) +{ + size_t sizTotShm = 0, capTotShm = 0, sizTot = 0, capTot = 0, siz = 0, cap = 0, cnt = 0, cntCap = 0; + { + siz = matchedTracks.size() * sizeof(o2::dataformats::TrackTPCITS); + cap = matchedTracks.capacity() * sizeof(o2::dataformats::TrackTPCITS); + sizTotShm += siz; + capTotShm += cap; + LOGP(info, "Size SHM, matchedTracks : size {:9} cap {:9}", siz, cap); + // + siz = ABTrackletRefs.size() * sizeof(o2::itsmft::TrkClusRef); + cap = ABTrackletRefs.capacity() * sizeof(o2::itsmft::TrkClusRef); + sizTotShm += siz; + capTotShm += cap; + LOGP(info, "Size SHM, ABTrackletRefs : size {:9} cap {:9}", siz, cap); + // + siz = ABTrackletClusterIDs.size() * sizeof(int); + cap = ABTrackletClusterIDs.capacity() * sizeof(int); + sizTotShm += siz; + capTotShm += cap; + LOGP(info, "Size SHM, ABTrackletClusterIDs : size {:9} cap {:9}", siz, cap); + // + siz = matchLabels.size() * sizeof(o2::MCCompLabel); + cap = matchLabels.capacity() * sizeof(o2::MCCompLabel); + sizTotShm += siz; + capTotShm += cap; + LOGP(info, "Size SHM, matchLabels : size {:9} cap {:9}", siz, cap); + // + siz = ABTrackletLabels.size() * sizeof(o2::MCCompLabel); + cap = ABTrackletLabels.capacity() * sizeof(o2::MCCompLabel); + sizTotShm += siz; + capTotShm += cap; + LOGP(info, "Size SHM, ABTrackletLabels : size {:9} cap {:9}", siz, cap); + // + siz = calib.size() * sizeof(o2::dataformats::Triplet); + cap = calib.capacity() * sizeof(o2::dataformats::Triplet); + sizTotShm += siz; + capTotShm += cap; + LOGP(info, "Size SHM, calib : size {:9} cap {:9}", siz, cap); + } + { + siz = mITSClustersArray.size() * sizeof(ITSCluster); + cap = mITSClustersArray.capacity() * sizeof(ITSCluster); + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mITSClustersArray : size {:9} cap {:9}", siz, cap); + // + siz = mMatchRecordsTPC.size() * sizeof(MatchRecord); + cap = mMatchRecordsTPC.capacity() * sizeof(MatchRecord); + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mMatchRecordsTPC : size {:9} cap {:9}", siz, cap); + // + siz = mMatchRecordsITS.size() * sizeof(MatchRecord); + cap = mMatchRecordsITS.capacity() * sizeof(MatchRecord); + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mMatchRecordsITS : size {:9} cap {:9}", siz, cap); + // + siz = mITSROFTimes.size() * sizeof(BracketF); + cap = mITSROFTimes.capacity() * sizeof(BracketF); + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mITSROFTimes : size {:9} cap {:9}", siz, cap); + // + siz = mTPCWork.size() * sizeof(TrackLocTPC); + cap = mTPCWork.capacity() * sizeof(TrackLocTPC); + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mTPCWork : size {:9} cap {:9}", siz, cap); + // + siz = mITSWork.size() * sizeof(TrackLocITS); + cap = mITSWork.capacity() * sizeof(TrackLocITS); + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mITSWork : size {:9} cap {:9}", siz, cap); + // + siz = mWinnerChi2Refit.size() * sizeof(float); + cap = mWinnerChi2Refit.capacity() * sizeof(float); + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mWinnerChi2Refit : size {:9} cap {:9}", siz, cap); + // + siz = mTPCABSeeds.size() * sizeof(float); + cap = mTPCABSeeds.capacity() * sizeof(float); + cnt = 0; + cntCap = 0; + for (const auto& a : mTPCABSeeds) { + siz += a.sizeInternal(); + cap += a.capInternal(); + cnt += a.trackLinks.size(); + cntCap += a.trackLinks.capacity(); + } + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mTPCABSeeds : size {:9} cap {:9} | internals size:{}/capacity:{} for {} elements", siz, cap, cnt, cntCap, mTPCABSeeds.size()); + // + siz = mTPCABIndexCache.size() * sizeof(int); + cap = mTPCABIndexCache.capacity() * sizeof(int); + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mTPCABIndexCache : size {:9} cap {:9}", siz, cap); + // + siz = mABWinnersIDs.size() * sizeof(int); + cap = mABWinnersIDs.capacity() * sizeof(int); + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mABWinnersIDs : size {:9} cap {:9}", siz, cap); + // + siz = mABClusterLinkIndex.size() * sizeof(int); + cap = mABClusterLinkIndex.capacity() * sizeof(int); + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mABClusterLinkIndex : size {:9} cap {:9}", siz, cap); + // + for (int is = 0; is < o2::constants::math::NSectors; is++) { + siz += mTPCSectIndexCache[is].size() * sizeof(int); + cap += mTPCSectIndexCache[is].capacity() * sizeof(int); + } + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mTPCSectIndexCache : size {:9} cap {:9}", siz, cap); + // + for (int is = 0; is < o2::constants::math::NSectors; is++) { + siz += mITSSectIndexCache[is].size() * sizeof(int); + cap += mITSSectIndexCache[is].capacity() * sizeof(int); + } + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mITSSectIndexCache : size {:9} cap {:9}", siz, cap); + // + for (int is = 0; is < o2::constants::math::NSectors; is++) { + siz += mTPCTimeStart[is].size() * sizeof(int); + cap += mTPCTimeStart[is].capacity() * sizeof(int); + } + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mTPCTimeStart : size {:9} cap {:9}", siz, cap); + // + for (int is = 0; is < o2::constants::math::NSectors; is++) { + siz += mITSTimeStart[is].size() * sizeof(int); + cap += mITSTimeStart[is].capacity() * sizeof(int); + } + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mITSTimeStart : size {:9} cap {:9}", siz, cap); + // + siz = mITSTrackROFContMapping.size() * sizeof(int); + cap = mITSTrackROFContMapping.capacity() * sizeof(int); + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, ITSTrackROFContMapping: size {:9} cap {:9}", siz, cap); + } + LOGP(info, "TotalSizes/Capacities: SHM: {}/{} Heap: {}/{}", sizTotShm, capTotShm, sizTot, capTot); +} + //__________________________________________________________ void MatchTPCITS::setNThreads(int n) { @@ -2461,14 +2620,11 @@ void MatchTPCITS::fillTPCITSmatchTree(int itsID, int tpcID, int rejFlag, float c if (chi2 < 0.) { // need to recalculate chi2 = getPredictedChi2NoZ(trackITS, trackTPC); } - o2::MCCompLabel lblITS, lblTPC; (*mDBGOut) << "match" << "tf=" << mTFCount << "chi2Match=" << chi2 << "its=" << trackITS << "tpc=" << trackTPC << "tcorr=" << tCorr; if (mMCTruthON) { - lblITS = mITSLblWork[itsID]; - lblTPC = mTPCLblWork[tpcID]; (*mDBGOut) << "match" - << "itsLbl=" << lblITS << "tpcLbl=" << lblTPC; + << "itsLbl=" << mITSLblWork[itsID] << "tpcLbl=" << mTPCLblWork[tpcID]; } (*mDBGOut) << "match" << "rejFlag=" << rejFlag << "\n"; @@ -2496,12 +2652,9 @@ void MatchTPCITS::dumpWinnerMatches() (*mDBGOut) << "matchWin" << "tf=" << mTFCount << "chi2Match=" << itsMatchRec.chi2 << "chi2Refit=" << mWinnerChi2Refit[iits] << "its=" << tITS << "tpc=" << tTPC; - o2::MCCompLabel lblITS, lblTPC; if (mMCTruthON) { - lblITS = mITSLblWork[iits]; - lblTPC = mTPCLblWork[itpc]; (*mDBGOut) << "matchWin" - << "itsLbl=" << lblITS << "tpcLbl=" << lblTPC; + << "itsLbl=" << mITSLblWork[iits] << "tpcLbl=" << mTPCLblWork[itpc]; } (*mDBGOut) << "matchWin" << "\n"; From 3236727306bdd7cf612b17b5e168cf8496395bc2 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 12 Oct 2023 11:06:57 +0200 Subject: [PATCH 277/324] GPU: Minor optimization --- GPU/GPUTracking/SliceTracker/GPUTPCSliceData.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCSliceData.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCSliceData.cxx index b46edf1f91d35..48d88272d42a1 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCSliceData.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCSliceData.cxx @@ -392,9 +392,9 @@ GPUdii() int GPUTPCSliceData::InitFromClusterData(int nBlocks, int nThreads, int mHitData[globalBinsortedIndex].y = (cahit)yy; } - if (iThread == 0) { + if (iThread == 0 && !mem->param.par.continuousTracking) { const float maxAbsZ = CAMath::Max(CAMath::Abs(tmpMinMax[2]), CAMath::Abs(tmpMinMax[3])); - if (maxAbsZ > 300 && !mem->param.par.continuousTracking) { + if (maxAbsZ > 300) { mem->errorCodes.raiseError(GPUErrors::ERROR_SLICEDATA_Z_OVERFLOW, iSlice, (unsigned int)maxAbsZ); return 1; } From e24893233f1803e9907bda5d9708a09bc20e331e Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 15 Oct 2023 23:46:51 +0200 Subject: [PATCH 278/324] dpl-workflow: Use new CTF coding by default on EPNs --- prodtests/full-system-test/dpl-workflow.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 0e228ee911e2f..1add2f9a28d65 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -32,6 +32,7 @@ fi # entropy encoding/decoding mode, default "" is equivalent to '--ans-version compat' (compatible with < 09/2023 data), # use '--ans-version 1.0 --ctf-dict none' for the new per-TF dictionary mode +[[ $EPNSYNCMODE == 1 && -z ${RANS_OPT:-} ]] && RANS_OPT="--ans-version 1.0 --ctf-dict none" : ${RANS_OPT:=""} workflow_has_parameter CTF && export SAVECTF=1 From 1ca06c97e9e14d6ad08d381cb974e4b6699d763e Mon Sep 17 00:00:00 2001 From: Roberta Ferioli <142217183+Roberta-Ferioli@users.noreply.github.com> Date: Tue, 17 Oct 2023 08:36:00 +0200 Subject: [PATCH 279/324] ITS-Study: create pt resolution, add efficiency of sec study (#11763) * create Ptresolution, add efficiency of sec study * Fix format * Add Pt res study at TrackChech * Add Pt resolution at check study * ITS-Study: add some study on efficiency of secondary tracks, add fake clusters of secondary analysis * fix formatting * fix formatting * ITS-Study: change structure, add Fake cluster study * ITS-Study:add fake clusters identification * [WIP] ITS-Study: completed study on fake clusters * ITS-Study:Completed the study on secondary tracks and fake clusters, start study on Pt resolution * ITS-Study: completed secondary tracks efficiency study, started studies on fake clusters and Pt resolution * Update Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx * Update Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx * Update Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx * Update Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx * Update Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx * Update Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx * Update Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx --------- Co-authored-by: Matteo Concas --- .../studies/src/ITSStudiesConfigParam.cxx | 1 + .../postprocessing/studies/src/TrackCheck.cxx | 1054 +++++++++++++++-- .../standalone-postprocessing-workflow.cxx | 4 +- 3 files changed, 972 insertions(+), 87 deletions(-) diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSStudiesConfigParam.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSStudiesConfigParam.cxx index 8a0f4c5ab3f4b..7652f175434da 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSStudiesConfigParam.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSStudiesConfigParam.cxx @@ -24,6 +24,7 @@ static auto& sImpactParameterParamsITS = o2::its::study::ITSImpactParameterParam O2ParamImpl(o2::its::study::ITSAvgClusSizeParamConfig); O2ParamImpl(o2::its::study::ITSCheckTracksParamConfig); O2ParamImpl(o2::its::study::ITSImpactParameterParamConfig); + } // namespace study } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx index c0476681e8c86..194b6bbaec363 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx @@ -24,10 +24,18 @@ #include "DetectorsBase/GRPGeomHelper.h" #include +#include +#include +#include #include #include #include #include +#include +#include +#include +#include +#include namespace o2 { @@ -50,11 +58,16 @@ class TrackCheckStudy : public Task float phi; int mother; int first; - unsigned short clusters = 0u; + float vx; + float vy; + float vz; + int unsigned short clusters = 0u; unsigned char isReco = 0u; unsigned char isFake = 0u; bool isPrimary = 0u; unsigned char storedStatus = 2; /// not stored = 2, fake = 1, good = 0 + const char* prodProcessName; + int prodProcess; o2::its::TrackITS track; }; @@ -69,6 +82,7 @@ class TrackCheckStudy : public Task LOGP(info, "Read MCKine reader with {} sources", mKineReader->getNSources()); } } + ~TrackCheckStudy() final = default; void init(InitContext&) final; void run(ProcessingContext&) final; @@ -76,6 +90,7 @@ class TrackCheckStudy : public Task void finaliseCCDB(ConcreteDataMatcher&, void*) final; void initialiseRun(o2::globaltracking::RecoContainer&); void process(); + void setEfficiencyGraph(std::unique_ptr&, const char*, const char*, const int, const double, const double, const int, const double); private: void updateTimeDependentParams(ProcessingContext& pc); @@ -88,6 +103,7 @@ class TrackCheckStudy : public Task gsl::span mTracks; gsl::span mTracksMCLabels; gsl::span mClusters; + gsl::span mInputITSidxs; const o2::dataformats::MCLabelContainer* mClustersMCLCont; // Data @@ -102,31 +118,99 @@ class TrackCheckStudy : public Task // Histos std::unique_ptr mGoodPt; std::unique_ptr mGoodEta; + std::unique_ptr mGoodPtSec; + std::unique_ptr mGoodEtaSec; std::unique_ptr mGoodChi2; std::unique_ptr mFakePt; std::unique_ptr mFakeEta; + std::unique_ptr mFakePtSec; + std::unique_ptr mFakeEtaSec; std::unique_ptr mMultiFake; std::unique_ptr mFakeChi2; - std::unique_ptr mClonePt; std::unique_ptr mCloneEta; std::unique_ptr mDenominatorPt; std::unique_ptr mDenominatorEta; + std::unique_ptr mDenominatorPtSec; + std::unique_ptr mDenominatorEtaSec; + + std::unique_ptr processvsZ; // TH2D with production process + std::unique_ptr processvsRad; + std::unique_ptr processvsRadOther; + std::unique_ptr processvsRadNotTracked; + std::unique_ptr processvsEtaNotTracked; - std::unique_ptr mEffPt; + std::unique_ptr mEffPt; // Eff vs Pt primary std::unique_ptr mEffFakePt; std::unique_ptr mEffClonesPt; - - std::unique_ptr mEffEta; + std::unique_ptr mEffEta; // Eff vs Eta primary std::unique_ptr mEffFakeEta; std::unique_ptr mEffClonesEta; - // Canvas & decorations + std::unique_ptr mEffPtSec; // Eff vs Pt secondary + std::unique_ptr mEffFakePtSec; + std::unique_ptr mEffEtaSec; // Eff vs Eta secondary + std::unique_ptr mEffFakeEtaSec; + + std::unique_ptr mPtResolution; // Pt resolution for both primary and secondary + std::unique_ptr mPtResolution2D; + std::unique_ptr mPtResolutionSec; + std::unique_ptr mPtResolutionPrim; + std::unique_ptr g1; + + const char* ParticleName[7] = {"e^{-/+}", "#pi^{-/+}", "p", "^{2}H", "^{3}He", "_{#Lambda}^{3}H", "k^{+/-}"}; + const int PdgcodeClusterFake[7] = {11, 211, 2212, 1000010020, 100002030, 1010010030, 321}; + const char* name[3] = {"_{#Lambda}^{3}H", "#Lambda", "k^{0}_{s}"}; + const char* particleToanalize[4] = {"IperT", "Lambda", "k0s", "Tot"}; // [3]=Total of secondary particle + const int PDG[3] = {1010010030, 3122, 310}; + const char* ProcessName[50]; + int colorArr[4] = {kGreen, kRed, kBlue, kOrange}; + + std::vector> histLength, histLength1Fake, histLength2Fake, histLength3Fake, histLengthNoCl, histLength1FakeNoCl, histLength2FakeNoCl, histLength3FakeNoCl; // FakeCluster Study + std::vector stackLength, stackLength1Fake, stackLength2Fake, stackLength3Fake; + std::vector legends, legends1Fake, legends2Fake, legends3Fake; + std::vector> mClusterFake; + std::vector>> mGoodPts, mFakePts, mTotPts, mGoodEtas, mTotEtas, mFakeEtas; + std::vector>> mEffGoodPts, mEffFakePts, mEffGoodEtas, mEffFakeEtas; + std::vector> mGoodRad, mFakeRad, mTotRad, mGoodZ, mFakeZ, mTotZ; + std::vector> mEffGoodRad, mEffFakeRad, mEffGoodZ, mEffFakeZ; + // Canvas & decorations std::unique_ptr mCanvasPt; + std::unique_ptr mCanvasPtSec; + std::unique_ptr mCanvasPt2; + std::unique_ptr mCanvasPt2fake; std::unique_ptr mCanvasEta; + std::unique_ptr mCanvasEtaSec; + std::unique_ptr mCanvasRad; + std::unique_ptr mCanvasZ; + std::unique_ptr mCanvasRadD; + std::unique_ptr mCanvasZD; + std::unique_ptr mCanvasPtRes; + std::unique_ptr mCanvasPtRes2; + std::unique_ptr mCanvasPtRes3; + std::unique_ptr mCanvasPtRes4; std::unique_ptr mLegendPt; std::unique_ptr mLegendEta; + std::unique_ptr mLegendPtSec; + std::unique_ptr mLegendEtaSec; + std::unique_ptr mLegendPtRes; + std::unique_ptr mLegendPtRes2; + std::unique_ptr mLegendZ; + std::unique_ptr mLegendRad; + std::unique_ptr mLegendZD; + std::unique_ptr mLegendRadD; + std::vector Histo; + + float rLayer0 = 2.34; // middle radius + float rLayer1 = 3.15; + float rLayer2 = 3.93; + float rLayer3 = 19.605; + + double sigma[100]; + double sigmaerr[100]; + double meanPt[100]; + double aa[100]; // Debug output tree std::unique_ptr mDBGOut; @@ -146,13 +230,19 @@ void TrackCheckStudy::init(InitContext& ic) for (int i{0}; i <= pars.effHistBins; i++) { xbins[i] = pars.effPtCutLow * std::exp(i * a); } - + for (int yy = 0; yy < 50; yy++) { + ProcessName[yy] = " "; + } mGoodPt = std::make_unique("goodPt", ";#it{p}_{T} (GeV/#it{c});Efficiency (fake-track rate)", pars.effHistBins, xbins.data()); mGoodEta = std::make_unique("goodEta", ";#eta;Number of tracks", 60, -3, 3); + mGoodPtSec = std::make_unique("goodPtSec", ";#it{p}_{T} (GeV/#it{c});Efficiency (fake-track rate)", pars.effHistBins, xbins.data()); + mGoodEtaSec = std::make_unique("goodEtaSec", ";#eta;Number of tracks", 60, -3, 3); mGoodChi2 = std::make_unique("goodChi2", ";#it{p}_{T} (GeV/#it{c});Efficiency (fake-track rate)", 200, 0, 100); mFakePt = std::make_unique("fakePt", ";#it{p}_{T} (GeV/#it{c});Fak", pars.effHistBins, xbins.data()); mFakeEta = std::make_unique("fakeEta", ";#eta;Number of tracks", 60, -3, 3); + mFakePtSec = std::make_unique("fakePtSec", ";#it{p}_{T} (GeV/#it{c});Fak", pars.effHistBins, xbins.data()); + mFakeEtaSec = std::make_unique("fakeEtaSec", ";#eta;Number of tracks", 60, -3, 3); mFakeChi2 = std::make_unique("fakeChi2", ";#it{p}_{T} (GeV/#it{c});Fak", 200, 0, 100); mMultiFake = std::make_unique("multiFake", ";#it{p}_{T} (GeV/#it{c});Fak", pars.effHistBins, xbins.data()); @@ -162,13 +252,170 @@ void TrackCheckStudy::init(InitContext& ic) mDenominatorPt = std::make_unique("denominatorPt", ";#it{p}_{T} (GeV/#it{c});Den", pars.effHistBins, xbins.data()); mDenominatorEta = std::make_unique("denominatorEta", ";#eta;Number of tracks", 60, -3, 3); + mDenominatorPtSec = std::make_unique("denominatorPtSec", ";#it{p}_{T} (GeV/#it{c});Den", pars.effHistBins, xbins.data()); + mDenominatorEtaSec = std::make_unique("denominatorEtaSec", ";#eta;Number of tracks", 60, -3, 3); + + processvsZ = std::make_unique("Process", ";z_{SV} [cm]; production process", 100, -50, 50., 50, 0, 50); + processvsRad = std::make_unique("ProcessR", ";decay radius [cm]; production process", 100, 0, 25., 50, 0, 50); + processvsRadOther = std::make_unique("ProcessRO", ";decay radius [cm]; production process", 200, 0, 25., 50, 0, 50); + processvsRadNotTracked = std::make_unique("ProcessRNoT", ";decay radius [cm]; production process", 200, 0, 25., 50, 0, 50); + processvsEtaNotTracked = std::make_unique("ProcessENoT", ";#eta; production process", 60, -3, 3, 50, 0, 50); + + mGoodPts.resize(4); + mFakePts.resize(4); + mTotPts.resize(4); + mGoodEtas.resize(4); + mFakeEtas.resize(4); + mTotEtas.resize(4); + mGoodRad.resize(4); + mFakeRad.resize(4); + mTotRad.resize(4); + mGoodZ.resize(4); + mFakeZ.resize(4); + mTotZ.resize(4); + mClusterFake.resize(4); + for (int i = 0; i < 4; i++) { + mGoodPts[i].resize(4); + mFakePts[i].resize(4); + mTotPts[i].resize(4); + mGoodEtas[i].resize(4); + mFakeEtas[i].resize(4); + mTotEtas[i].resize(4); + } + for (int ii = 0; ii < 4; ii++) { + + mGoodRad[ii] = std::make_unique(Form("goodRad_%s", particleToanalize[ii]), ";z_{SV} [cm];Number of tracks", 100, 0., 20.); + mFakeRad[ii] = std::make_unique(Form("FakeRad_%s", particleToanalize[ii]), ";#eta;Number of tracks", 100, 0., 20.); + mTotRad[ii] = std::make_unique(Form("TotRad_%s", particleToanalize[ii]), ";#eta;Number of tracks", 100, 0., 20.); + + mGoodZ[ii] = std::make_unique(Form("goodZ_%s", particleToanalize[ii]), ";z_{SV} [cm];Number of tracks", 100, -50., 50.); + mFakeZ[ii] = std::make_unique(Form("FakeZ_%s", particleToanalize[ii]), ";z_{SV} [cm];Number of tracks", 100, -50., 50.); + mTotZ[ii] = std::make_unique(Form("TotZ_%s", particleToanalize[ii]), ";z_{SV} [cm];Number of tracks", 100, -50., 50.); + mClusterFake[ii] = std::make_unique(Form("Clusters_fake_%s", ParticleName[ii]), ";particle generating fake cluster; production process", 7, 0., 7., 50, 0, 50); + + mGoodRad[ii]->Sumw2(); + mFakeRad[ii]->Sumw2(); + mTotRad[ii]->Sumw2(); + mGoodZ[ii]->Sumw2(); + mFakeZ[ii]->Sumw2(); + mTotZ[ii]->Sumw2(); + + for (int yy = 0; yy < 4; yy++) { // divided by layer + mGoodPts[ii][yy] = std::make_unique(Form("goodPts_%s_%d", particleToanalize[ii], yy), ";#it{p}_{T} (GeV/#it{c});Efficiency (fake-track rate)", pars.effHistBins, xbins.data()); + mFakePts[ii][yy] = std::make_unique(Form("FakePts_%s_%d", particleToanalize[ii], yy), ";#it{p}_{T} (GeV/#it{c});Efficiency (fake-track rate)", pars.effHistBins, xbins.data()); + mTotPts[ii][yy] = std::make_unique(Form("TotPts_%s_%d", particleToanalize[ii], yy), ";#it{p}_{T} (GeV/#it{c});Efficiency (fake-track rate)", pars.effHistBins, xbins.data()); + + mGoodEtas[ii][yy] = std::make_unique(Form("goodEtas_%s_%d", particleToanalize[ii], yy), ";#eta;Number of tracks", 60, -3, 3); + mFakeEtas[ii][yy] = std::make_unique(Form("FakeEtas_%s_%d", particleToanalize[ii], yy), ";#eta;Number of tracks", 60, -3, 3); + mTotEtas[ii][yy] = std::make_unique(Form("TotEtas_%s_%d", particleToanalize[ii], yy), ";#eta;Number of tracks", 60, -3, 3); + + mGoodPts[ii][yy]->Sumw2(); + mFakePts[ii][yy]->Sumw2(); + mTotPts[ii][yy]->Sumw2(); + mGoodEtas[ii][yy]->Sumw2(); + mFakeEtas[ii][yy]->Sumw2(); + mTotEtas[ii][yy]->Sumw2(); + } + } + + mPtResolution = std::make_unique("PtResolution", ";#it{p}_{T} ;Den", 100, -1, 1); + mPtResolutionSec = std::make_unique("PtResolutionSec", ";#it{p}_{T} ;Den", 100, -1, 1); + mPtResolutionPrim = std::make_unique("PtResolutionPrim", ";#it{p}_{T} ;Den", 100, -1, 1); + mPtResolution2D = std::make_unique("#it{p}_{T} Resolution vs #it{p}_{T}", ";#it{p}_{T} (GeV/#it{c});#Delta p_{T}/p_{T_{MC}", 100, 0, 10, 100, -1, 1); + + mPtResolution->Sumw2(); + mPtResolutionSec->Sumw2(); + mPtResolutionPrim->Sumw2(); mGoodPt->Sumw2(); mGoodEta->Sumw2(); + mGoodPtSec->Sumw2(); + mGoodEtaSec->Sumw2(); + mFakePt->Sumw2(); + mFakePtSec->Sumw2(); + mFakeEta->Sumw2(); mMultiFake->Sumw2(); mClonePt->Sumw2(); mDenominatorPt->Sumw2(); + + histLength.resize(4); // fake clusters study + histLength1Fake.resize(4); + histLength2Fake.resize(4); + histLength3Fake.resize(4); + histLengthNoCl.resize(4); + histLength1FakeNoCl.resize(4); + histLength2FakeNoCl.resize(4); + histLength3FakeNoCl.resize(4); + stackLength.resize(4); + stackLength1Fake.resize(4); + stackLength2Fake.resize(4); + stackLength3Fake.resize(4); + for (int yy = 0; yy < 4; yy++) { + histLength[yy].resize(3); + histLength1Fake[yy].resize(3); + histLength2Fake[yy].resize(3); + histLength3Fake[yy].resize(3); + histLengthNoCl[yy].resize(3); + histLength1FakeNoCl[yy].resize(3); + histLength2FakeNoCl[yy].resize(3); + histLength3FakeNoCl[yy].resize(3); + } + legends.resize(4); + legends1Fake.resize(4); + legends2Fake.resize(4); + legends3Fake.resize(4); + + for (int iH{4}; iH < 8; ++iH) { + // check distributions on layers of fake clusters for tracks of different lengths. + // Different histograms if the correct cluster exist or not + for (int jj = 0; jj < 3; jj++) { + histLength[iH - 4][jj] = new TH1I(Form("trk_len_%d_%s", iH, name[jj]), Form("#exists cluster %s", name[jj]), 7, -.5, 6.5); + histLength[iH - 4][jj]->SetFillColor(colorArr[jj] - 9); + histLength[iH - 4][jj]->SetLineColor(colorArr[jj] - 9); + histLengthNoCl[iH - 4][jj] = new TH1I(Form("trk_len_%d_nocl_%s", iH, name[jj]), Form("#slash{#exists} cluster %s", name[jj]), 7, -.5, 6.5); + histLengthNoCl[iH - 4][jj]->SetFillColor(colorArr[jj] + 1); + histLengthNoCl[iH - 4][jj]->SetLineColor(colorArr[jj] + 1); + if (jj == 0) + stackLength[iH - 4] = new THStack(Form("stack_trk_len_%d", iH), Form("trk_len=%d", iH)); + stackLength[iH - 4]->Add(histLength[iH - 4][jj]); + stackLength[iH - 4]->Add(histLengthNoCl[iH - 4][jj]); + + histLength1Fake[iH - 4][jj] = new TH1I(Form("trk_len_%d_1f_%s", iH, name[jj]), Form("#exists cluster %s", name[jj]), 7, -.5, 6.5); + histLength1Fake[iH - 4][jj]->SetFillColor(colorArr[jj] - 9); + histLength1Fake[iH - 4][jj]->SetLineColor(colorArr[jj] - 9); + histLength1FakeNoCl[iH - 4][jj] = new TH1I(Form("trk_len_%d_1f_nocl_%s", iH, name[jj]), Form("#slash{#exists} cluster %s", name[jj]), 7, -.5, 6.5); + histLength1FakeNoCl[iH - 4][jj]->SetFillColor(colorArr[jj] + 1); + histLength1FakeNoCl[iH - 4][jj]->SetLineColor(colorArr[jj] + 1); + if (jj == 0) + stackLength1Fake[iH - 4] = new THStack(Form("stack_trk_len_%d_1f", iH), Form("trk_len=%d, 1 Fake", iH)); + stackLength1Fake[iH - 4]->Add(histLength1Fake[iH - 4][jj]); + stackLength1Fake[iH - 4]->Add(histLength1FakeNoCl[iH - 4][jj]); + + histLength2Fake[iH - 4][jj] = new TH1I(Form("trk_len_%d_2f_%s", iH, name[jj]), Form("#exists cluster %s", name[jj]), 7, -.5, 6.5); + histLength2Fake[iH - 4][jj]->SetFillColor(colorArr[jj] - 9); + histLength2Fake[iH - 4][jj]->SetLineColor(colorArr[jj] - 9); + histLength2FakeNoCl[iH - 4][jj] = new TH1I(Form("trk_len_%d_2f_nocl_%s", iH, name[jj]), Form("#slash{#exists} cluster %s", name[jj]), 7, -.5, 6.5); + histLength2FakeNoCl[iH - 4][jj]->SetFillColor(colorArr[jj] + 1); + histLength2FakeNoCl[iH - 4][jj]->SetLineColor(colorArr[jj] + 1); + if (jj == 0) + stackLength2Fake[iH - 4] = new THStack(Form("stack_trk_len_%d_2f", iH), Form("trk_len=%d, 2 Fake", iH)); + stackLength2Fake[iH - 4]->Add(histLength2Fake[iH - 4][jj]); + stackLength2Fake[iH - 4]->Add(histLength2FakeNoCl[iH - 4][jj]); + + histLength3Fake[iH - 4][jj] = new TH1I(Form("trk_len_%d_3f_%s", iH, name[jj]), Form("#exists cluster %s", name[jj]), 7, -.5, 6.5); + histLength3Fake[iH - 4][jj]->SetFillColor(colorArr[jj] - 9); + histLength3Fake[iH - 4][jj]->SetLineColor(colorArr[jj] - 9); + + histLength3FakeNoCl[iH - 4][jj] = new TH1I(Form("trk_len_%d_3f_nocl_%s", iH, name[jj]), Form("#slash{#exists} cluster %s", name[jj]), 7, -.5, 6.5); + histLength3FakeNoCl[iH - 4][jj]->SetFillColor(colorArr[jj] + 1); + histLength3FakeNoCl[iH - 4][jj]->SetLineColor(colorArr[jj] + 1); + if (jj == 0) + stackLength3Fake[iH - 4] = new THStack(Form("stack_trk_len_%d_3f", iH), Form("trk_len=%d, 3 Fake", iH)); + stackLength3Fake[iH - 4]->Add(histLength3Fake[iH - 4][jj]); + stackLength3Fake[iH - 4]->Add(histLength3FakeNoCl[iH - 4][jj]); + } + } } void TrackCheckStudy::run(ProcessingContext& pc) @@ -188,6 +435,7 @@ void TrackCheckStudy::initialiseRun(o2::globaltracking::RecoContainer& recoData) mTracksMCLabels = recoData.getITSTracksMCLabels(); mClusters = recoData.getITSClusters(); mClustersMCLCont = recoData.getITSClustersMCLabels(); + mInputITSidxs = recoData.getITSTracksClusterRefs(); LOGP(info, "** Found in {} rofs:\n\t- {} clusters with {} labels\n\t- {} tracks with {} labels", mTracksROFRecords.size(), mClusters.size(), mClustersMCLCont->getIndexedSize(), mTracks.size(), mTracksMCLabels.size()); @@ -209,7 +457,13 @@ void TrackCheckStudy::process() mParticleInfo[iSource][iEvent][iPart].pt = part.GetPt(); mParticleInfo[iSource][iEvent][iPart].phi = part.GetPhi(); mParticleInfo[iSource][iEvent][iPart].eta = part.GetEta(); + mParticleInfo[iSource][iEvent][iPart].vx = part.Vx(); + mParticleInfo[iSource][iEvent][iPart].vy = part.Vy(); + mParticleInfo[iSource][iEvent][iPart].vz = part.Vz(); mParticleInfo[iSource][iEvent][iPart].isPrimary = part.isPrimary(); + mParticleInfo[iSource][iEvent][iPart].mother = part.getMotherTrackId(); + mParticleInfo[iSource][iEvent][iPart].prodProcessName = part.getProdProcessAsString(); + mParticleInfo[iSource][iEvent][iPart].prodProcess = part.getProcess(); } } } @@ -232,6 +486,22 @@ void TrackCheckStudy::process() } LOGP(info, "** Analysing tracks ... "); int unaccounted{0}, good{0}, fakes{0}, total{0}; + // ***secondary tracks*** + int nPartForSpec[4][4]; // total number [particle 0=IperT, 1=Lambda, 2=k, 3=Other][n layer] + int nPartGoodorFake[4][4][2]; // number of good or fake [particle 0=IperT, 1=Lambda, 2=k, 3=Other][n layer][good=1 fake=0] + for (int n = 0; n < 4; n++) { + for (int m = 0; m < 4; m++) { + nPartForSpec[n][m] = 0; + for (int h = 0; h < 2; h++) { + nPartGoodorFake[n][m][h] = 0; + } + } + } + int nlayer = 999; + int ngoodfake = 0; + int totsec = 0; + int totsecCont = 0; + for (auto iTrack{0}; iTrack < mTracks.size(); ++iTrack) { auto& lab = mTracksMCLabels[iTrack]; if (!lab.isSet() || lab.isNoise()) { @@ -262,43 +532,242 @@ void TrackCheckStudy::process() LOGP(info, "\t- Total number of tracks not corresponding to particles: {} ({:.2f} %)", unaccounted, unaccounted * 100. / mTracks.size()); LOGP(info, "\t- Total number of fakes: {} ({:.2f} %)", fakes, fakes * 100. / mTracks.size()); LOGP(info, "\t- Total number of good: {} ({:.2f} %)", good, good * 100. / mTracks.size()); - LOGP(info, "** Filling histograms ... "); + LOGP(info, "** Filling histograms ... "); + int evID = 0; + int trackID = 0; + int totP{0}, goodP{0}, fakeP{0}; // Currently process only sourceID = 0, to be extended later if needed for (auto& evInfo : mParticleInfo[0]) { + trackID = 0; for (auto& part : evInfo) { - if ((part.clusters & 0x7f) != mMask) { + + if (strcmp(ProcessName[part.prodProcess], " ")) + ProcessName[part.prodProcess] = part.prodProcessName; + if ((part.clusters & 0x7f) == mMask) { // part.clusters != 0x3f && part.clusters != 0x3f << 1 && // part.clusters != 0x1f && part.clusters != 0x1f << 1 && part.clusters != 0x1f << 2 && // part.clusters != 0x0f && part.clusters != 0x0f << 1 && part.clusters != 0x0f << 2 && part.clusters != 0x0f << 3) { - continue; - } - if (!part.isPrimary) { - continue; - } - mDenominatorPt->Fill(part.pt); - mDenominatorEta->Fill(part.eta); - if (part.isReco) { - mGoodPt->Fill(part.pt); - mGoodEta->Fill(part.eta); - if (part.isReco > 1) { - for (int _i{0}; _i < part.isReco - 1; ++_i) { - mClonePt->Fill(part.pt); - mCloneEta->Fill(part.eta); + // continue; + + if (part.isPrimary) { // **Primary particle** + totP++; + mDenominatorPt->Fill(part.pt); + mDenominatorEta->Fill(part.eta); + if (part.isReco) { + mGoodPt->Fill(part.pt); + mGoodEta->Fill(part.eta); + goodP++; + if (part.isReco > 1) { + for (int _i{0}; _i < part.isReco - 1; ++_i) { + mClonePt->Fill(part.pt); + mCloneEta->Fill(part.eta); + } + } + } + if (part.isFake) { + mFakePt->Fill(part.pt); + mFakeEta->Fill(part.eta); + fakeP++; + if (part.isFake > 1) { + for (int _i{0}; _i < part.isFake - 1; ++_i) { + mMultiFake->Fill(part.pt); + } + } } } } - if (part.isFake) { - mFakePt->Fill(part.pt); - mFakeEta->Fill(part.eta); - if (part.isFake > 1) { - for (int _i{0}; _i < part.isFake - 1; ++_i) { - mMultiFake->Fill(part.pt); + + // **Secondary particle** + nlayer = 999; + ngoodfake = 2; + if (!part.isPrimary) { + int TrackID, EvID, SrcID; + int pdgcode = mParticleInfo[0][evID][part.mother].pdg; + int idxPart = 999; + float rad = sqrt(pow(part.vx, 2) + pow(part.vy, 2)); + totsec++; + + if ((rad < rLayer0) && (part.clusters == 0x7f || part.clusters == 0x3f || part.clusters == 0x1f || part.clusters == 0x0f)) // layer 0 + nlayer = 0; + if (rad < rLayer1 && rad > rLayer0 && (part.clusters == 0x1e || part.clusters == 0x3e || part.clusters == 0x7e)) // layer 1 + nlayer = 1; + if (rad < rLayer2 && rad > rLayer1 && (part.clusters == 0x7c || part.clusters == 0x3c)) // layer 2 + nlayer = 2; + if (rad < rLayer3 && rad > rLayer2 && part.clusters == 0x78) // layer 3 + nlayer = 3; + if (nlayer == 0 || nlayer == 1 || nlayer == 2 || nlayer == 3) { // check if track is trackeable + + totsecCont++; + processvsZ->Fill(part.vz, part.prodProcess); + processvsRad->Fill(rad, part.prodProcess); + mDenominatorPtSec->Fill(part.pt); + mDenominatorEtaSec->Fill(part.eta); + mTotRad[3]->Fill(rad); + mTotZ[3]->Fill(part.vz); + mTotPts[nlayer][3]->Fill(part.pt); + mTotEtas[nlayer][3]->Fill(part.eta); + mTotPts[nlayer][3]->Fill(part.pt); + mTotEtas[nlayer][3]->Fill(part.eta); + if (pdgcode == PDG[0] || pdgcode == -1 * PDG[0]) + idxPart = 0; // IperT + if (pdgcode == PDG[1] || pdgcode == -1 * PDG[1]) + idxPart = 1; // Lambda + if (pdgcode == PDG[2] || pdgcode == -1 * PDG[2]) + idxPart = 2; // K0s + if (part.isReco) { + ngoodfake = 1; + mGoodPts[3][nlayer]->Fill(part.pt); + mGoodEtas[3][nlayer]->Fill(part.eta); + mGoodPtSec->Fill(part.pt); + mGoodEtaSec->Fill(part.eta); + mGoodRad[3]->Fill(rad); + mGoodZ[3]->Fill(part.vz); + } + if (part.isFake) { + ngoodfake = 0; + mFakePts[3][nlayer]->Fill(part.pt); + mFakeEtas[3][nlayer]->Fill(part.eta); + mFakePtSec->Fill(part.pt); + mFakeEtaSec->Fill(part.eta); + mFakeRad[3]->Fill(rad); + mFakeZ[3]->Fill(part.vz); + } + if (idxPart < 3) // to change if the number of analysing particle changes + { + mTotRad[idxPart]->Fill(rad); + mTotZ[idxPart]->Fill(part.vz); + mTotPts[idxPart][nlayer]->Fill(part.pt); + mTotEtas[idxPart][nlayer]->Fill(part.eta); + if (part.isReco) { + mGoodRad[idxPart]->Fill(rad); + mGoodZ[idxPart]->Fill(part.vz); + mGoodPts[idxPart][nlayer]->Fill(part.pt); + mGoodEtas[idxPart][nlayer]->Fill(part.eta); + } + if (part.isFake) { + mFakeRad[idxPart]->Fill(rad); + mFakeZ[idxPart]->Fill(part.vz); + mFakePts[idxPart][nlayer]->Fill(part.pt); + mFakeEtas[idxPart][nlayer]->Fill(part.eta); + } + } + + if (pdgcode != 1010010030 && pdgcode != 3122 && pdgcode != 310 && pdgcode != -1010010030 && pdgcode != -310 && pdgcode != -3122) { + idxPart = 3; + processvsRadOther->Fill(rad, part.prodProcess); + } + + if (!part.isFake && !part.isReco) { + processvsEtaNotTracked->Fill(part.eta, part.prodProcess); + processvsRadNotTracked->Fill(rad, part.prodProcess); + } + if (ngoodfake == 1 || ngoodfake == 0) + nPartGoodorFake[idxPart][nlayer][ngoodfake]++; + nPartForSpec[idxPart][nlayer]++; + + // Analysing fake clusters + int nCl{0}; + for (unsigned int bit{0}; bit < sizeof(part.clusters) * 8; ++bit) { + nCl += bool(part.clusters & (1 << bit)); + } + if (nCl < 3) { + continue; + } + if (idxPart < 3) { + auto& track = part.track; + auto len = track.getNClusters(); + int nclu = track.getNumberOfClusters(); + int firstclu = track.getFirstClusterEntry(); + for (int iLayer{0}; iLayer < 7; ++iLayer) { + if (track.hasHitOnLayer(iLayer)) { + if (track.isFakeOnLayer(iLayer)) { + // Reco track has fake cluster + if (part.clusters & (0x1 << iLayer)) { // Correct cluster exists + histLength[len - 4][idxPart]->Fill(iLayer); + if (track.getNFakeClusters() == 1) { + histLength1Fake[len - 4][idxPart]->Fill(iLayer); + } + if (track.getNFakeClusters() == 2) { + histLength2Fake[len - 4][idxPart]->Fill(iLayer); + } + if (track.getNFakeClusters() == 3) { + histLength3Fake[len - 4][idxPart]->Fill(iLayer); + } + } else { + + histLengthNoCl[len - 4][idxPart]->Fill(iLayer); + if (track.getNFakeClusters() == 1) { + histLength1FakeNoCl[len - 4][idxPart]->Fill(iLayer); + } + if (track.getNFakeClusters() == 2) { + histLength2FakeNoCl[len - 4][idxPart]->Fill(iLayer); + } + if (track.getNFakeClusters() == 3) { + histLength3FakeNoCl[len - 4][idxPart]->Fill(iLayer); + } + } + auto labs = mClustersMCLCont->getLabels(mInputITSidxs[firstclu - 1 - iLayer + track.getFirstClusterLayer() + nclu]); + + for (auto& lab : labs) { + if (!lab.isValid()) { + continue; // We want to skip channels related to noise, e.g. sID = 99: QED + } + + bool fakec; + const_cast(lab).get(TrackID, EvID, SrcID, fakec); + double intHisto = 0; + for (int hg = 0; hg < 7; hg++) { + if (mParticleInfo[SrcID][EvID][TrackID].pdg == PdgcodeClusterFake[hg] || mParticleInfo[SrcID][EvID][TrackID].pdg == -1 * (PdgcodeClusterFake[hg])) + intHisto = hg + 0.5; + } + if (idxPart < 3) + mClusterFake[idxPart]->Fill(intHisto, mParticleInfo[SrcID][EvID][TrackID].prodProcess); + } + } + } + } } } + nlayer = 999; } + trackID++; } + evID++; } + + int totgood{0}, totfake{0}, totI{0}, totL{0}, totK{0}, totO{0}; + for (int xx = 0; xx < 4; xx++) { + for (int yy = 0; yy < 4; yy++) { + totgood = totgood + nPartGoodorFake[xx][yy][1]; + totfake = totfake + nPartGoodorFake[xx][yy][0]; + if (xx == 0) + totI = totI + nPartForSpec[0][yy]; + if (xx == 1) + totL = totL + nPartForSpec[1][yy]; + if (xx == 2) + totK = totK + nPartForSpec[2][yy]; + if (xx == 3) + totO = totO + nPartForSpec[3][yy]; + } + } + LOGP(info, "number of primary tracks: {}, good:{}, fake:{}", totP, goodP, fakeP); + int goodI = nPartGoodorFake[0][0][1] + nPartGoodorFake[0][1][1] + nPartGoodorFake[0][2][1] + nPartGoodorFake[0][3][1]; + int goodL = nPartGoodorFake[1][0][1] + nPartGoodorFake[1][1][1] + nPartGoodorFake[1][2][1] + nPartGoodorFake[1][3][1]; + int goodK = nPartGoodorFake[2][0][1] + nPartGoodorFake[2][1][1] + nPartGoodorFake[2][2][1] + nPartGoodorFake[2][3][1]; + int fakeI = nPartGoodorFake[0][0][0] + nPartGoodorFake[0][1][0] + nPartGoodorFake[0][2][0] + nPartGoodorFake[0][3][0]; + int fakeL = nPartGoodorFake[1][0][0] + nPartGoodorFake[1][1][0] + nPartGoodorFake[1][2][0] + nPartGoodorFake[1][3][0]; + int fakeK = nPartGoodorFake[2][0][0] + nPartGoodorFake[2][1][0] + nPartGoodorFake[2][2][0] + nPartGoodorFake[2][3][0]; + LOGP(info, "** Some statistics on secondary tracks:"); + + LOGP(info, "\t- Total number of secondary tracks: {}", totsec); + LOGP(info, "\t- Total number of secondary trackeable tracks : {}", totsecCont); + LOGP(info, "\t- Total number of secondary trackeable tracks good: {}, fake: {}", totgood, totfake); + LOGP(info, "\t- Total number of secondary trackeable tracks from IperT: {} = {} %, Good={} % , fake={} %", totI, 100 * totI / totsecCont, 100 * goodI / totI, 100 * fakeI / totI); + LOGP(info, "\t- Total number of secondary trackeable tracks from Lam: {} = {} %, Good={} % , fake={} %", totL, 100 * totL / totsecCont, 100 * goodL / totL, 100 * fakeL / totL); + LOGP(info, "\t- Total number of secondary trackeable tracks from k: {} = {} %, Good={} % , fake={} %", totK, 100 * totK / totsecCont, 100 * goodK / totK, 100 * fakeK / totK); + LOGP(info, "\t- Total number of secondary trackeable tracks from Other: {} = {} %", totO, 100 * totO / totsecCont); + LOGP(info, "** Computing efficiencies ..."); mEffPt = std::make_unique(*mGoodPt, *mDenominatorPt); @@ -308,6 +777,76 @@ void TrackCheckStudy::process() mEffEta = std::make_unique(*mGoodEta, *mDenominatorEta); mEffFakeEta = std::make_unique(*mFakeEta, *mDenominatorEta); mEffClonesEta = std::make_unique(*mCloneEta, *mDenominatorEta); + + mEffPtSec = std::make_unique(*mGoodPtSec, *mDenominatorPtSec); + mEffFakePtSec = std::make_unique(*mFakePtSec, *mDenominatorPtSec); + + mEffEtaSec = std::make_unique(*mGoodEtaSec, *mDenominatorEtaSec); + mEffFakeEtaSec = std::make_unique(*mFakeEtaSec, *mDenominatorEtaSec); + + for (int ii = 0; ii < 4; ii++) { + for (int yy = 0; yy < 4; yy++) { + mEffGoodPts[ii][yy] = std::make_unique(*mGoodPts[ii][yy], *mTotPts[ii][yy]); + mEffFakePts[ii][yy] = std::make_unique(*mFakePts[ii][yy], *mTotPts[ii][yy]); + mEffGoodEtas[ii][yy] = std::make_unique(*mGoodEtas[ii][yy], *mTotEtas[ii][yy]); + mEffFakeEtas[ii][yy] = std::make_unique(*mFakeEtas[ii][yy], *mTotEtas[ii][yy]); + } + mEffGoodRad[ii] = std::make_unique(*mGoodRad[ii], *mTotRad[ii]); + mEffFakeRad[ii] = std::make_unique(*mFakeRad[ii], *mTotRad[ii]); + mEffGoodZ[ii] = std::make_unique(*mGoodZ[ii], *mTotZ[ii]); + mEffFakeZ[ii] = std::make_unique(*mFakeZ[ii], *mTotZ[ii]); + } + + LOGP(info, "** Analysing pT resolution..."); + for (auto iTrack{0}; iTrack < mTracks.size(); ++iTrack) { + auto& lab = mTracksMCLabels[iTrack]; + if (!lab.isSet() || lab.isNoise()) + continue; + int trackID, evID, srcID; + bool fake; + const_cast(lab).get(trackID, evID, srcID, fake); + bool pass{true}; + if (srcID == 99) + continue; // skip QED + mPtResolution->Fill((mParticleInfo[srcID][evID][trackID].pt - mTracks[iTrack].getPt()) / mParticleInfo[srcID][evID][trackID].pt); + mPtResolution2D->Fill(mParticleInfo[srcID][evID][trackID].pt, (mParticleInfo[srcID][evID][trackID].pt - mTracks[iTrack].getPt()) / mParticleInfo[srcID][evID][trackID].pt); + if (!mParticleInfo[srcID][evID][trackID].isPrimary) + mPtResolutionSec->Fill((mParticleInfo[srcID][evID][trackID].pt - mTracks[iTrack].getPt()) / mParticleInfo[srcID][evID][trackID].pt); + mPtResolutionPrim->Fill((mParticleInfo[srcID][evID][trackID].pt - mTracks[iTrack].getPt()) / mParticleInfo[srcID][evID][trackID].pt); + } + + for (int yy = 0; yy < 100; yy++) { + aa[yy] = 0.; + sigma[yy] = 0.; + sigmaerr[yy] = 0.; + meanPt[yy] = 0.; + } + + for (int yy = 0; yy < 100; yy++) { + TH1D* projh2X = mPtResolution2D->ProjectionY("projh2X", yy, yy + 1, ""); + TF1* f1 = new TF1("f1", "gaus", -0.2, 0.2); + projh2X->Fit("f1"); + if (f1->GetParameter(2) > 0. && f1->GetParameter(2) < 1. && f1->GetParameter(1) < 1.) { + sigma[yy] = f1->GetParameter(2); + sigmaerr[yy] = f1->GetParError(2); + meanPt[yy] = ((8. / 100.) * yy + (8. / 100.) * (yy + 1)) / 2; + aa[yy] = 0.0125; + } + } +} + +void TrackCheckStudy::setEfficiencyGraph(std::unique_ptr& eff, const char* name, const char* title, const int color, const double alpha = 1, const double linew = 2, const int markerStyle = kFullCircle, const double markersize = 1.7) +{ + eff->SetName(name); + eff->SetTitle(title); + eff->SetLineColor(color); + eff->SetLineColorAlpha(color, alpha); + eff->SetMarkerColor(color); + eff->SetMarkerColorAlpha(color, alpha); + eff->SetLineWidth(linew); + eff->SetMarkerStyle(markerStyle); + eff->SetMarkerSize(markersize); + eff->SetDirectory(gDirectory); } void TrackCheckStudy::updateTimeDependentParams(ProcessingContext& pc) @@ -324,73 +863,108 @@ void TrackCheckStudy::updateTimeDependentParams(ProcessingContext& pc) void TrackCheckStudy::endOfStream(EndOfStreamContext& ec) { TFile fout(mOutFileName.c_str(), "recreate"); - mEffPt->SetName("Good_pt"); - mEffPt->SetTitle(";#it{p}_{T} (GeV/#it{c});efficiency primary particle"); - mEffPt->SetLineColor(kAzure + 4); - mEffPt->SetLineColorAlpha(kAzure + 4, 0.65); - mEffPt->SetLineWidth(2); - mEffPt->SetMarkerColorAlpha(kAzure + 4, 0.65); - mEffPt->SetMarkerStyle(kFullCircle); - mEffPt->SetMarkerSize(1.35); - mEffPt->SetDirectory(gDirectory); + + setEfficiencyGraph(mEffPt, "Good_pt", ";#it{p}_{T} (GeV/#it{c});efficiency primary particle", kAzure + 4, 0.65); fout.WriteTObject(mEffPt.get()); - mEffFakePt->SetName("Fake_pt"); - mEffFakePt->SetTitle(";#it{p}_{T} (GeV/#it{c});efficiency primary particle"); - mEffFakePt->SetLineColor(kRed + 1); - mEffFakePt->SetLineColorAlpha(kRed + 1, 0.65); - mEffFakePt->SetLineWidth(2); - mEffFakePt->SetMarkerColorAlpha(kRed + 1, 0.65); - mEffFakePt->SetMarkerStyle(kFullCircle); - mEffFakePt->SetMarkerSize(1.35); - mEffFakePt->SetDirectory(gDirectory); + setEfficiencyGraph(mEffFakePt, "Fake_pt", ";#it{p}_{T} (GeV/#it{c});efficiency primary particle", kRed, 0.65); fout.WriteTObject(mEffFakePt.get()); - mEffClonesPt->SetName("Clone_pt"); - mEffClonesPt->SetTitle(";#it{p}_{T} (GeV/#it{c});efficiency primary particle"); - mEffClonesPt->SetLineColor(kGreen + 2); - mEffClonesPt->SetLineColorAlpha(kGreen + 2, 0.65); - mEffClonesPt->SetLineWidth(2); - mEffClonesPt->SetMarkerColorAlpha(kGreen + 2, 0.65); + setEfficiencyGraph(mEffPtSec, "Good_ptSec", ";#it{p}_{T} (GeV/#it{c});efficiency secondary particle", kOrange + 7); + fout.WriteTObject(mEffPtSec.get()); + + setEfficiencyGraph(mEffFakePtSec, "Fake_ptSec", ";#it{p}_{T} (GeV/#it{c});efficiency secondary particle", kGray + 2); + fout.WriteTObject(mEffFakePtSec.get()); - mEffClonesPt->SetMarkerStyle(kFullCircle); - mEffClonesPt->SetMarkerSize(1.35); - mEffClonesPt->SetDirectory(gDirectory); + setEfficiencyGraph(mEffClonesPt, "Clone_pt", ";#it{p}_{T} (GeV/#it{c});efficiency primary particle", kGreen + 2, 0.65); fout.WriteTObject(mEffClonesPt.get()); - mEffEta->SetName("Good_eta"); - mEffEta->SetTitle(";#eta;efficiency primary particle"); - mEffEta->SetLineColor(kAzure + 4); - mEffEta->SetLineColorAlpha(kAzure + 4, 0.65); - mEffEta->SetLineWidth(2); - mEffEta->SetMarkerColorAlpha(kAzure + 4, 0.65); - mEffEta->SetMarkerStyle(kFullCircle); - mEffEta->SetMarkerSize(1.35); - mEffEta->SetDirectory(gDirectory); + setEfficiencyGraph(mEffEta, "Good_eta", ";#eta;efficiency primary particle", kAzure + 4, 0.65); fout.WriteTObject(mEffEta.get()); - mEffFakeEta->SetName("Fake_eta"); - mEffFakeEta->SetTitle(";#eta;efficiency primary particle"); - mEffFakeEta->SetLineColor(kRed + 1); - mEffFakeEta->SetLineColorAlpha(kRed + 1, 0.65); - mEffFakeEta->SetLineWidth(2); - mEffFakeEta->SetMarkerColorAlpha(kRed + 1, 0.65); - mEffFakeEta->SetMarkerStyle(kFullCircle); - mEffFakeEta->SetMarkerSize(1.35); - mEffFakeEta->SetDirectory(gDirectory); + setEfficiencyGraph(mEffFakeEta, "Fake_eta", ";#eta;efficiency primary particle", kRed + 1, 0.65); fout.WriteTObject(mEffFakeEta.get()); - mEffClonesEta->SetName("Clone_eta"); - mEffClonesEta->SetTitle(";#eta;efficiency primary particle"); - mEffClonesEta->SetLineColor(kGreen + 2); - mEffClonesEta->SetLineColorAlpha(kGreen + 2, 0.65); - mEffClonesEta->SetLineWidth(2); - mEffClonesEta->SetMarkerColorAlpha(kGreen + 2, 0.65); - mEffClonesEta->SetMarkerStyle(kFullCircle); - mEffClonesEta->SetMarkerSize(1.35); - mEffClonesEta->SetDirectory(gDirectory); + setEfficiencyGraph(mEffEtaSec, "Good_etaSec", ";#eta;efficiency secondary particle", kOrange + 7); + fout.WriteTObject(mEffEtaSec.get()); + + setEfficiencyGraph(mEffFakeEtaSec, "Fake_etaSec", ";#eta;efficiency secondary particle", kGray + 2); + fout.WriteTObject(mEffFakeEtaSec.get()); + + setEfficiencyGraph(mEffClonesEta, "Clone_eta", ";#it{p}_{T} (GeV/#it{c});efficiency primary particle", kGreen + 2, 0.65); fout.WriteTObject(mEffClonesEta.get()); + for (int aa = 0; aa < 4; aa++) { + setEfficiencyGraph(mEffGoodRad[aa], Form("Good_Rad_%s", particleToanalize[aa]), ";Radius [cm];efficiency secondary particle", colorArr[aa]); + fout.WriteTObject(mEffGoodRad[aa].get()); + + setEfficiencyGraph(mEffGoodRad[aa], Form("Fake_Rad_%s", particleToanalize[aa]), ";Radius [cm];efficiency secondary particle", colorArr[aa] - 9); + fout.WriteTObject(mEffGoodRad[aa].get()); + + setEfficiencyGraph(mEffGoodZ[aa], Form("Good_Z_%s", particleToanalize[aa]), ";Z_{sv} [cm];efficiency secondary particle", colorArr[aa]); + fout.WriteTObject(mEffGoodZ[aa].get()); + + setEfficiencyGraph(mEffGoodZ[aa], Form("Fake_Z_%s", particleToanalize[aa]), ";Z_{sv} [cm];efficiency secondary particle", colorArr[aa] - 9); + fout.WriteTObject(mEffGoodZ[aa].get()); + + for (int bb = 0; bb < 4; bb++) { + setEfficiencyGraph(mEffGoodPts[aa][bb], Form("EffPtGood_%sl%d", particleToanalize[aa], bb), Form("Good Sec Tracks_%s, L%d" + ";#it{p}_{T} (GeV/#it{c});efficiency secondary particle ", + particleToanalize[aa], bb), + colorArr[aa]); + setEfficiencyGraph(mEffFakePts[aa][bb], Form("EffPtFake_%sl%d", particleToanalize[aa], bb), Form("Fake Sec Tracks_%s, L%d" + ";#it{p}_{T} (GeV/#it{c});efficiency secondary particle ", + particleToanalize[aa], bb), + colorArr[aa]); + setEfficiencyGraph(mEffGoodEtas[aa][bb], Form("EffEtaGood_%sl%d", particleToanalize[aa], bb), Form("Good Sec Tracks_%s, L%d" + ";#eta ;efficiency secondary particle ", + particleToanalize[aa], bb), + colorArr[aa]); + setEfficiencyGraph(mEffFakeEtas[aa][bb], Form("EffEtaFake_%sl%d", particleToanalize[aa], bb), Form("Fake Sec Tracks_%s, L%d" + ";#eta ;efficiency secondary particle ", + particleToanalize[aa], bb), + colorArr[aa]); + + fout.WriteTObject(mEffGoodPts[aa][bb].get()); + fout.WriteTObject(mEffFakePts[aa][bb].get()); + fout.WriteTObject(mEffGoodEtas[aa][bb].get()); + fout.WriteTObject(mEffFakeEtas[aa][bb].get()); + } + for (int i = 0; i < 3; i++) { + fout.WriteTObject(histLength[aa][i], Form("trk_len_%d_%s", 4 + aa, name[i])); + fout.WriteTObject(histLength1Fake[aa][i], Form("trk_len_%d_1f_%s", 4 + aa, name[i])); + fout.WriteTObject(histLength2Fake[aa][i], Form("trk_len_%d_2f_%s", 4 + aa, name[i])); + fout.WriteTObject(histLength3Fake[aa][i], Form("trk_len_%d_3f_%s", 4 + aa, name[i])); + fout.WriteTObject(histLengthNoCl[aa][i], Form("trk_len_%d_nocl_%s", 4 + aa, name[i])); + fout.WriteTObject(histLength1FakeNoCl[aa][i], Form("trk_len_%d_1f_nocl_%s", 4 + aa, name[i])); + fout.WriteTObject(histLength2FakeNoCl[aa][i], Form("trk_len_%d_2f_nocl_%s", 4 + aa, name[i])); + fout.WriteTObject(histLength3FakeNoCl[aa][i], Form("trk_len_%d_3f_nocl_%s", 4 + aa, name[i])); + } + } + + for (int j = 0; j < 4; j++) { + for (int i = 1; i <= 7; i++) { + mClusterFake[j]->GetXaxis()->SetBinLabel(i, ParticleName[i - 1]); + + for (int i = 1; i <= 50; i++) { + mClusterFake[j]->GetYaxis()->SetBinLabel(i, ProcessName[i - 1]); + if (j == 0) { + processvsZ->GetYaxis()->SetBinLabel(i, ProcessName[i - 1]); + processvsRad->GetYaxis()->SetBinLabel(i, ProcessName[i - 1]); + processvsRadOther->GetYaxis()->SetBinLabel(i, ProcessName[i - 1]); + processvsRadNotTracked->GetYaxis()->SetBinLabel(i, ProcessName[i - 1]); + processvsEtaNotTracked->GetYaxis()->SetBinLabel(i, ProcessName[i - 1]); + } + } + fout.WriteTObject(mClusterFake[j].get()); + } + } + fout.WriteTObject(processvsZ.get()); + fout.WriteTObject(processvsRad.get()); + fout.WriteTObject(processvsRadOther.get()); + fout.WriteTObject(processvsRadNotTracked.get()); + fout.WriteTObject(processvsEtaNotTracked.get()); + // Paint the histograms // todo: delegate to a dedicated helper gStyle->SetTitleSize(0.035, "xy"); @@ -414,13 +988,26 @@ void TrackCheckStudy::endOfStream(EndOfStreamContext& ec) mEffFakePt->Draw("pz same"); mEffClonesPt->Draw("pz same"); mLegendPt = std::make_unique(0.19, 0.8, 0.40, 0.96); - mLegendPt->SetHeader(Form("%zu events PbPb min bias", mKineReader->getNEvents(0)), "C"); + mLegendPt->SetHeader(Form("%zu events PP min bias", mKineReader->getNEvents(0)), "C"); mLegendPt->AddEntry("Good_pt", "good (100% cluster purity)", "lep"); mLegendPt->AddEntry("Fake_pt", "fake", "lep"); mLegendPt->AddEntry("Clone_pt", "clone", "lep"); mLegendPt->Draw(); mCanvasPt->SaveAs("eff_pt.png"); + mCanvasPtSec = std::make_unique("cPtSec", "cPtSec", 1600, 1200); + mCanvasPtSec->cd(); + mCanvasPtSec->SetLogx(); + mCanvasPtSec->SetGrid(); + mEffPtSec->Draw("pz"); + mEffFakePtSec->Draw("pz same"); + mLegendPtSec = std::make_unique(0.19, 0.8, 0.40, 0.96); + mLegendPtSec->SetHeader(Form("%zu events PP min bias", mKineReader->getNEvents(0)), "C"); + mLegendPtSec->AddEntry("Good_ptSec", "good (100% cluster purity)", "lep"); + mLegendPtSec->AddEntry("Fake_tSec", "fake", "lep"); + mLegendPtSec->Draw(); + mCanvasPtSec->SaveAs("eff_ptSec.png"); + mCanvasEta = std::make_unique("cEta", "cEta", 1600, 1200); mCanvasEta->cd(); mCanvasEta->SetGrid(); @@ -428,16 +1015,313 @@ void TrackCheckStudy::endOfStream(EndOfStreamContext& ec) mEffFakeEta->Draw("pz same"); mEffClonesEta->Draw("pz same"); mLegendEta = std::make_unique(0.19, 0.8, 0.40, 0.96); - mLegendEta->SetHeader(Form("%zu events PbPb min bias", mKineReader->getNEvents(0)), "C"); + mLegendEta->SetHeader(Form("%zu events PP min bias", mKineReader->getNEvents(0)), "C"); mLegendEta->AddEntry("Good_eta", "good (100% cluster purity)", "lep"); mLegendEta->AddEntry("Fake_eta", "fake", "lep"); mLegendEta->AddEntry("Clone_eta", "clone", "lep"); mLegendEta->Draw(); mCanvasEta->SaveAs("eff_eta.png"); + mCanvasEtaSec = std::make_unique("cEtaSec", "cEtaSec", 1600, 1200); + mCanvasEtaSec->cd(); + mCanvasEtaSec->SetGrid(); + mEffEtaSec->Draw("pz"); + mEffFakeEtaSec->Draw("pz same"); + mLegendEtaSec = std::make_unique(0.19, 0.8, 0.40, 0.96); + mLegendEtaSec->SetHeader(Form("%zu events PP min bias", mKineReader->getNEvents(0)), "C"); + mLegendEtaSec->AddEntry("Good_etaSec", "good (100% cluster purity)", "lep"); + mLegendEtaSec->AddEntry("Fake_etaSec", "fake", "lep"); + mLegendEtaSec->Draw(); + mCanvasEtaSec->SaveAs("eff_EtaSec.png"); + + mCanvasRad = std::make_unique("cRad", "cRad", 1600, 1200); + mCanvasRad->cd(); + mCanvasRad->SetGrid(); + mEffGoodRad[3]->Draw("pz"); + mEffFakeRad[3]->Draw("pz same"); + mCanvasRad->SetLogy(); + mLegendRad = std::make_unique(0.8, 0.4, 0.95, 0.6); + mLegendRad->SetHeader(Form("%zu events PP ", mKineReader->getNEvents(0)), "C"); + mLegendRad->AddEntry(Form("Good_Rad_%s", particleToanalize[3]), "good", "lep"); + mLegendRad->AddEntry(Form("Fake_Rad_%s", particleToanalize[3]), "fake", "lep"); + mLegendRad->Draw(); + mCanvasRad->SaveAs("eff_rad_sec.png"); + + mCanvasZ = std::make_unique("cZ", "cZ", 1600, 1200); + mCanvasZ->cd(); + mCanvasZ->SetGrid(); + mCanvasZ->SetLogy(); + mEffGoodZ[3]->Draw("pz"); + mEffFakeZ[3]->Draw("pz same"); + mCanvasZ->SetLogy(); + mLegendZ = std::make_unique(0.8, 0.4, 0.95, 0.6); + mLegendZ->SetHeader(Form("%zu events PP ", mKineReader->getNEvents(0)), "C"); + mLegendZ->AddEntry(Form("Good_Z_%s", particleToanalize[3]), "good", "lep"); + mLegendZ->AddEntry(Form("Fake_Z_%s", particleToanalize[3]), "fake", "lep"); + mLegendZ->Draw(); + mCanvasZ->SaveAs("eff_Z_sec.png"); + ; + + mCanvasRadD = std::make_unique("cRadD", "cRadD", 1600, 1200); + mCanvasRadD->cd(); + mCanvasRadD->SetGrid(); + mCanvasRadD->SetLogy(); + mLegendRadD = std::make_unique(0.8, 0.64, 0.95, 0.8); + mLegendRadD->SetHeader(Form("%zu events PP ", mKineReader->getNEvents(0)), "C"); + for (int i = 0; i < 3; i++) { + if (i == 0) + mEffGoodRad[i]->Draw("pz"); + else { + mEffGoodRad[i]->Draw("pz same"); + mEffFakeRad[i]->Draw("pz same"); + mLegendRadD->AddEntry(Form("Good_Rad%s", particleToanalize[i]), Form("%s_good", name[i]), "lep"); + mLegendRadD->AddEntry(Form("Fake_Rad%s", particleToanalize[i]), Form("%s_fake", name[i]), "lep"); + } + } + mLegendRadD->Draw(); + mCanvasRadD->SaveAs("eff_RadD_sec.png"); + + mCanvasZD = std::make_unique("cZD", "cZD", 1600, 1200); + mCanvasZD->cd(); + mCanvasZD->SetGrid(); + mCanvasZD->SetLogy(); + mLegendZD = std::make_unique(0.8, 0.64, 0.95, 0.8); + mLegendZD->SetHeader(Form("%zu events PP ", mKineReader->getNEvents(0)), "C"); + for (int i = 0; i < 3; i++) { + if (i == 0) + mEffGoodZ[i]->Draw("pz"); + else { + mEffGoodZ[i]->Draw("pz same"); + mEffFakeZ[i]->Draw("pz same"); + mLegendZD->AddEntry(Form("Good_Z%s", particleToanalize[i]), Form("%s_good", name[i]), "lep"); + mLegendZD->AddEntry(Form("Fake_Z%s", particleToanalize[i]), Form("%s_fake", name[i]), "lep"); + } + } + mLegendZD->Draw(); + mCanvasZD->SaveAs("eff_ZD_sec.png"); + + mPtResolution->SetName("#it{p}_{T} resolution"); + mPtResolution->SetTitle(";#Delta p_{T}/p_{T_{MC}} ;Entries"); + mPtResolution->SetFillColor(kAzure + 4); + mPtResolutionPrim->SetFillColor(kRed); + mPtResolutionSec->SetFillColor(kOrange); + mPtResolutionPrim->SetTitle(";#Delta p_{T}/p_{T_{MC}} ;Entries"); + mPtResolutionSec->SetTitle(";#Delta #it{p}_{T}/#it{p}_{T_{MC}} ;Entries"); + mPtResolution2D->SetTitle(";#it{p}_{T_{MC}} [GeV];#Delta #it{p}_{T}/#it{p}_{T_{MC}}"); + + fout.WriteTObject(mPtResolution.get()); + fout.WriteTObject(mPtResolutionPrim.get()); + fout.WriteTObject(mPtResolutionSec.get()); + fout.WriteTObject(mPtResolution2D.get()); + + mCanvasPtRes = std::make_unique("cPtr", "cPtr", 1600, 1200); + mCanvasPtRes->cd(); + mPtResolution->Draw("HIST"); + mLegendPtRes = std::make_unique(0.19, 0.8, 0.40, 0.96); + mLegendPtRes->SetHeader(Form("%zu events PP min bias", mKineReader->getNEvents(0)), "C"); + mLegendPtRes->AddEntry("mPtResolution", "All events", "lep"); + mLegendPtRes->Draw(); + mCanvasPtRes->SaveAs("ptRes.png"); + + mCanvasPtRes2 = std::make_unique("cPtr2", "cPtr2", 1600, 1200); + mCanvasPtRes2->cd(); + mPtResolution2D->Draw(); + mCanvasPtRes2->SaveAs("ptRes2.png"); + + mCanvasPtRes3 = std::make_unique("cPtr3", "cPtr3", 1600, 1200); + mCanvasPtRes3->cd(); + + TGraphErrors* g1 = new TGraphErrors(100, meanPt, sigma, aa, sigmaerr); + g1->SetMarkerStyle(8); + g1->SetMarkerColor(kGreen); + g1->GetXaxis()->SetTitle(" #it{p}_{T} [GeV]"); + g1->GetYaxis()->SetTitle("#sigma #Delta #it{p}_{T}/#it{p}_{T_{MC}}"); + g1->GetYaxis()->SetLimits(0, 1); + g1->GetXaxis()->SetLimits(0, 10.); + g1->Draw("AP"); + g1->GetYaxis()->SetRangeUser(0, 1); + g1->GetXaxis()->SetRangeUser(0, 10.); + mCanvasPtRes3->SaveAs("ptRes3.png"); + + mCanvasPtRes4 = std::make_unique("cPt4", "cPt4", 1600, 1200); + mCanvasPtRes4->cd(); + mPtResolutionPrim->SetName("mPtResolutionPrim"); + mPtResolutionSec->SetName("mPtResolutionSec"); + mPtResolutionPrim->Draw("same hist"); + mPtResolutionSec->Draw("same hist"); + mLegendPtRes2 = std::make_unique(0.19, 0.8, 0.40, 0.96); + + mLegendPtRes2->SetHeader(Form("%zu events PP", mKineReader->getNEvents(0)), "C"); + mLegendPtRes2->AddEntry("mPtResolutionPrim", "Primary events", "f"); + mLegendPtRes2->AddEntry("mPtResolutionSec", "Secondary events", "f"); + mLegendPtRes2->Draw("same"); + mLegendPtRes2->SaveAs("ptRes4.png"); + + auto canvas = new TCanvas("fc_canvas", "Fake clusters", 1600, 1000); + canvas->Divide(4, 2); + for (int iH{0}; iH < 4; ++iH) { + canvas->cd(iH + 1); + stackLength[iH]->Draw(); + stackLength[iH]->GetXaxis()->SetTitle("Layer"); + gPad->BuildLegend(); + } + for (int iH{0}; iH < 4; ++iH) { + canvas->cd(iH + 5); + stackLength1Fake[iH]->Draw(); + stackLength1Fake[iH]->GetXaxis()->SetTitle("Layer"); + gPad->BuildLegend(); + } + + canvas->SaveAs("fakeClusters2.png", "recreate"); + + auto canvas2 = new TCanvas("fc_canvas2", "Fake clusters", 1600, 1000); + canvas2->Divide(4, 2); + + for (int iH{0}; iH < 4; ++iH) { + canvas2->cd(iH + 1); + stackLength2Fake[iH]->Draw(); + stackLength2Fake[iH]->GetXaxis()->SetTitle("Layer"); + gPad->BuildLegend(); + } + for (int iH{0}; iH < 4; ++iH) { + canvas2->cd(iH + 5); + stackLength3Fake[iH]->Draw(); + stackLength3Fake[iH]->GetXaxis()->SetTitle("Layer"); + gPad->BuildLegend(); + } + canvas2->SaveAs("fakeClusters3.png", "recreate"); + + auto canvasPtfake = new TCanvas("canvasPtfake", "Fake pt", 1600, 1000); + canvasPtfake->Divide(2, 2); + + for (int iH{0}; iH < 4; ++iH) { + canvasPtfake->cd(iH + 1); + for (int v = 0; v < 4; v++) { + if (v == 0) + canvasPtfake->cd(iH + 1); + if (v == 0) + mEffFakePts[v][iH]->Draw(); + else + mEffFakePts[v][iH]->Draw("same"); + } + gPad->BuildLegend(); + gPad->SetGrid(); + gPad->SetTitle(Form("#it{p}_{T}, Fake Tracks, layer %d", iH)); + gPad->SetName(Form("#it{p}_{T}, Fake Tracks, layer %d", iH)); + } + canvasPtfake->SaveAs("PtforPartFake.png", "recreate"); + + auto canvasPtGood = new TCanvas("canvasPtGood", "Good pt", 1600, 1000); + canvasPtGood->Divide(2, 2); + + for (int iH{0}; iH < 4; ++iH) { + canvasPtGood->cd(iH + 1); + for (int v = 0; v < 4; v++) { + if (v == 0) + canvasPtGood->cd(iH + 1); + if (v == 0) + mEffGoodPts[v][iH]->Draw(); + else + mEffGoodPts[v][iH]->Draw("same"); + } + gPad->BuildLegend(); + gPad->SetGrid(); + gPad->SetTitle(Form("#it{p}_{T}, Good Tracks, layer %d", iH)); + gPad->SetName(Form("#it{p}_{T}, Good Tracks, layer %d", iH)); + } + + auto canvasEtafake = new TCanvas("canvasEtafake", "Fake Eta", 1600, 1000); + canvasEtafake->Divide(2, 2); + + for (int iH{0}; iH < 4; ++iH) { + canvasEtafake->cd(iH + 1); + for (int v = 0; v < 4; v++) { + if (v == 0) + canvasEtafake->cd(iH + 1); + if (v == 0) + mEffFakeEtas[v][iH]->Draw(); + else + mEffFakeEtas[v][iH]->Draw("same"); + } + gPad->BuildLegend(); + gPad->SetGrid(); + gPad->SetTitle(Form("#eta, Fake Tracks, layer %d", iH)); + gPad->SetName(Form("#eta, Fake Tracks, layer %d", iH)); + } + auto canvasEtaGood = new TCanvas("canvasEtaGood", "Good Eta", 1600, 1000); + canvasEtaGood->Divide(2, 2); + + for (int iH{0}; iH < 4; ++iH) { + canvasEtaGood->cd(iH + 1); + for (int v = 0; v < 4; v++) { + if (v == 0) + canvasEtaGood->cd(iH + 1); + if (v == 0) + mEffGoodEtas[v][iH]->Draw(); + else + mEffGoodEtas[v][iH]->Draw("same"); + } + gPad->BuildLegend(); + gPad->SetGrid(); + gPad->SetTitle(Form("#eta, Good Tracks, layer %d", iH)); + gPad->SetName(Form("#eta, Good Tracks, layer %d", iH)); + } + + auto canvasI = new TCanvas("canvasI", "canvasI", 1600, 1000); + canvasI->cd(); + mClusterFake[0]->Draw("COLZ"); + canvasI->SaveAs("Iper2D.png", "recreate"); + + auto canvasL = new TCanvas("canvasL", "canvasL", 1600, 1000); + canvasL->cd(); + mClusterFake[1]->Draw("COLZ"); + canvasL->SaveAs("Lam2D.png", "recreate"); + + auto canvasK = new TCanvas("canvasK", "canvasK", 1600, 1000); + canvasK->cd(); + mClusterFake[2]->Draw("COLZ"); + canvasK->SaveAs("K2D.png", "recreate"); + + auto canvasZProd = new TCanvas("canvasZProd", "canvasZProd", 1600, 1000); + canvasZProd->cd(); + processvsZ->Draw("COLZ"); + canvasZProd->SaveAs("prodvsZ.png", "recreate"); + auto canvasRadProd = new TCanvas("canvasRadProd", "canvasRadProd", 1600, 1000); + canvasRadProd->cd(); + processvsRad->Draw("COLZ"); + canvasRadProd->SaveAs("prodvsRad.png", "recreate"); + auto canvasRadProdO = new TCanvas("canvasRadProdO", "canvasRadProdO", 1600, 1000); + canvasRadProdO->cd(); + processvsRadOther->Draw("COLZ"); + canvasRadProdO->SaveAs("prodvsRadO.png", "recreate"); + auto canvasRadProNOTr = new TCanvas("canvasRadProNOTr", "canvasRadProNOTr", 1600, 1000); + canvasRadProNOTr->cd(); + processvsRadNotTracked->Draw("COLZ"); + canvasRadProNOTr->SaveAs("prodvsRadNoTr.png", "recreate"); + auto canvasEtaProNOTr = new TCanvas("canvasEtaProNOTr", "canvasEtaProNOTr", 1600, 1000); + canvasEtaProNOTr->cd(); + processvsEtaNotTracked->Draw("COLZ"); + canvasEtaProNOTr->SaveAs("prodvsEtaNoTr.png", "recreate"); + fout.cd(); mCanvasPt->Write(); mCanvasEta->Write(); + mCanvasPtSec->Write(); + mCanvasEtaSec->Write(); + mCanvasPtRes->Write(); + mCanvasPtRes2->Write(); + mCanvasPtRes3->Write(); + mCanvasPtRes4->Write(); + mCanvasRad->Write(); + mCanvasZ->Write(); + mCanvasRadD->Write(); + mCanvasZD->Write(); + canvas->Write(); + canvas2->Write(); + canvasPtfake->Write(); + canvasI->Write(); + canvasL->Write(); + canvasK->Write(); fout.Close(); } diff --git a/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx b/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx index 75eef5a561b91..d760d2aeb075d 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx @@ -65,8 +65,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) GID::mask_t srcCls = allowedSourcesClus & GID::getSourcesMask(configcontext.options().get("cluster-sources")); o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC, srcCls, srcTrc); - o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, useMC); - o2::globaltracking::InputHelper::addInputSpecsSVertex(configcontext, specs); + // o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, useMC); + // o2::globaltracking::InputHelper::addInputSpecsSVertex(configcontext, specs); std::shared_ptr mcKinematicsReader; if (useMC) { From 50fd48985d0125fffbabf0a17dd23b4fa3fdbf63 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:45:18 +0200 Subject: [PATCH 280/324] DPL: test matcher behaviour Since at some point there was a doubt that EMCAL messages where wrongly matched, here is the unit test to demonstrate myself it's not actually the case. --- .../Core/test/test_DataDescriptorMatcher.cxx | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Framework/Core/test/test_DataDescriptorMatcher.cxx b/Framework/Core/test/test_DataDescriptorMatcher.cxx index e83b3d2dc06a1..8b74f7d9f6b6b 100644 --- a/Framework/Core/test/test_DataDescriptorMatcher.cxx +++ b/Framework/Core/test/test_DataDescriptorMatcher.cxx @@ -669,3 +669,27 @@ TEST_CASE("DataQuery") REQUIRE(result5[0].metadata[2].name == "key3"); REQUIRE(result5[0].metadata[2].defaultValue.get() == "value3"); } + +// Make sure that 10 and 1 subspect are matched differently + +TEST_CASE("MatchSubspec") +{ + DataHeader header0; + header0.dataOrigin = "EMC"; + header0.dataDescription = "CELLSTRGR"; + header0.subSpecification = 10; + VariableContext context; + + DataDescriptorMatcher matcher{ + DataDescriptorMatcher::Op::And, + OriginValueMatcher{"EMC"}, + std::make_unique( + DataDescriptorMatcher::Op::And, + DescriptionValueMatcher{"CELLSTRGR"}, + std::make_unique( + DataDescriptorMatcher::Op::And, + SubSpecificationTypeValueMatcher{1}, + ConstantValueMatcher{true}))}; + + REQUIRE(matcher.match(header0, context) == false); +} From 57bfcc6204bca46331849d36ca9d7dc265454b2b Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Mon, 16 Oct 2023 15:28:20 +0200 Subject: [PATCH 281/324] DPL Analysis: make sure slice index with start==end is tested --- Framework/Core/test/test_ASoA.cxx | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Framework/Core/test/test_ASoA.cxx b/Framework/Core/test/test_ASoA.cxx index 52496d3f40eab..e6a537dab3dc9 100644 --- a/Framework/Core/test/test_ASoA.cxx +++ b/Framework/Core/test/test_ASoA.cxx @@ -869,22 +869,23 @@ TEST_CASE("TestAdvancedIndices") int references[] = {19, 2, 0, 13, 4, 6, 5, 5, 11, 9, 3, 8, 16, 14, 1, 18, 12, 18, 2, 7}; int slice[2] = {-1, -1}; std::vector pset; - std::array withSlices = {3, 13, 19}; + std::array withSlices = {3, 6, 13, 19}; + std::array, 4> bounds = {std::pair{1, 5}, std::pair{3, 3}, std::pair{11, 11}, std::pair{10, 18}}; std::array withSets = {0, 1, 13, 14}; - int sizes[] = {3, 1, 5, 4}; - int c1 = 0; - int c2 = 0; + unsigned int sizes[] = {3, 1, 5, 4}; + unsigned int c1 = 0; + unsigned int c2 = 0; for (auto i = 0; i < 20; ++i) { pset.clear(); slice[0] = -1; slice[1] = -1; if (c1 < withSlices.size() && i == withSlices[c1]) { - slice[0] = i - 2; - slice[1] = i - 1; + slice[0] = bounds[c1].first; + slice[1] = bounds[c1].second; ++c1; } if (c2 < withSets.size() && i == withSets[c2]) { - for (auto z = 0; z < sizes[c2]; ++z) { + for (auto z = 0U; z < sizes[c2]; ++z) { pset.push_back(i + 1 + z); } ++c2; @@ -906,10 +907,12 @@ TEST_CASE("TestAdvancedIndices") auto ops = p.pointSeq_as(); if (i == withSlices[c1]) { auto it = ops.begin(); - REQUIRE(ops.size() == 2); - REQUIRE(it.globalIndex() == i - 2); - ++it; - REQUIRE(it.globalIndex() == i - 1); + REQUIRE(ops.size() == bounds[c1].second - bounds[c1].first + 1); + REQUIRE(it.globalIndex() == bounds[c1].first); + for (auto j = 1; j < ops.size(); ++j) { + ++it; + } + REQUIRE(it.globalIndex() == bounds[c1].second); ++c1; } else { REQUIRE(ops.size() == 0); From 0a95a6fe2063b96fb875f13d7f4c5b94601e3e54 Mon Sep 17 00:00:00 2001 From: Matteo Concas Date: Tue, 17 Oct 2023 10:25:55 +0200 Subject: [PATCH 282/324] GPU: CMake enable_language(HIP) (#11860) * Enable HIP language and start porting benchmarks * Use dedicated fucntion to define symbols upon gpuarch * Remove ROOT dependency from benchmark * Move hipification into dedicated files * Cleanup ongoing * Filter out IGP architectures * Fix wrong linking options, add arch override --- CMakeLists.txt | 4 +- .../ITS/tracking/GPU/cuda/CMakeLists.txt | 2 - .../ITSMFT/ITS/tracking/GPU/hip/.gitignore | 3 +- .../ITS/tracking/GPU/hip/CMakeLists.txt | 45 +++-------- GPU/GPUTracking/Base/cuda/CMakeLists.txt | 15 +--- GPU/GPUTracking/Base/hip/CMakeLists.txt | 13 +--- GPU/GPUbenchmark/Shared/Kernels.h | 3 +- GPU/GPUbenchmark/Shared/Utils.h | 68 ++--------------- GPU/GPUbenchmark/cuda/Kernels.cu | 8 +- GPU/GPUbenchmark/cuda/benchmark.cu | 20 ++--- GPU/GPUbenchmark/hip/.gitignore | 3 +- GPU/GPUbenchmark/hip/CMakeLists.txt | 35 ++------- cmake/O2AddHipifiedExecutable.cmake | 76 +++++++++++++++++++ cmake/O2AddHipifiedLibrary.cmake | 71 +++++++++++++++++ dependencies/FindO2GPU.cmake | 37 +++++++++ 15 files changed, 228 insertions(+), 175 deletions(-) create mode 100644 cmake/O2AddHipifiedExecutable.cmake create mode 100644 cmake/O2AddHipifiedLibrary.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index a5ff713f8d05b..ca431a8b95be2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ # Preamble -cmake_minimum_required(VERSION 3.19 FATAL_ERROR) +cmake_minimum_required(VERSION 3.21.1 FATAL_ERROR) # it's important to specify accurately the list of languages. for instance C and # C++ as we _do_ have some C files to compile explicitely as C (e.g. gl3w.c) @@ -93,6 +93,8 @@ include(O2DataFile) include(O2TargetManPage) include(O2AddWorkflow) include(O2SetROOTPCMDependencies) +include(O2AddHipifiedExecutable) +include(O2AddHipifiedLibrary) # Main targets of the project in various subdirectories. Order matters. add_subdirectory(Common) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt index 6ab442f3d33b8..a389cb3dd4c11 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt @@ -12,7 +12,6 @@ # CUDA if(CUDA_ENABLED) find_package(CUDAToolkit) - message(STATUS "Building ITS CUDA tracker") o2_add_library(ITStrackingCUDA @@ -33,5 +32,4 @@ o2_add_library(ITStrackingCUDA set_property(TARGET ${targetName} PROPERTY CUDA_SEPARABLE_COMPILATION ON) target_compile_definitions(${targetName} PRIVATE GPUCA_O2_LIB $) - endif() \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/hip/.gitignore b/Detectors/ITSMFT/ITS/tracking/GPU/hip/.gitignore index 5854f8830a79b..74255eaece87c 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/hip/.gitignore +++ b/Detectors/ITSMFT/ITS/tracking/GPU/hip/.gitignore @@ -1,2 +1,3 @@ # Don't track generated hip sources -*.hip.cxx \ No newline at end of file +*.hip.cxx +*.hip \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt index cba23d5119e41..59911e57b3239 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt @@ -10,37 +10,17 @@ # or submit itself to any jurisdiction. if(HIP_ENABLED) - # Hipify-perl to generate HIP sources - set(HIPIFY_EXECUTABLE "/opt/rocm/bin/hipify-perl") - file(GLOB CUDA_SOURCES_FULL_PATH "../cuda/*.cu") - foreach(file ${CUDA_SOURCES_FULL_PATH}) - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${file}) - get_filename_component(CUDA_SOURCE ${file} NAME) - string(REPLACE ".cu" "" CUDA_SOURCE_NAME ${CUDA_SOURCE}) - add_custom_command( - OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${CUDA_SOURCE_NAME}.hip.cxx - COMMAND ${HIPIFY_EXECUTABLE} --quiet-warnings ${CMAKE_CURRENT_SOURCE_DIR}/../cuda/${CUDA_SOURCE} | sed '1{/\#include \"hip\\/hip_runtime.h\"/d}' > ${CMAKE_CURRENT_SOURCE_DIR}/${CUDA_SOURCE_NAME}.hip.cxx - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../cuda/${CUDA_SOURCE} - ) - endforeach() - - install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${baseTargetName} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - - set(CMAKE_CXX_COMPILER ${hip_HIPCC_EXECUTABLE}) - set(CMAKE_CXX_EXTENSIONS OFF) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${O2_HIP_CMAKE_CXX_FLAGS} -fgpu-rdc") - message(STATUS "Building ITS HIP tracker") - o2_add_library(ITStrackingHIP - SOURCES ClusterLinesGPU.hip.cxx - Context.hip.cxx - TimeFrameGPU.hip.cxx - Stream.hip.cxx - TrackerTraitsGPU.hip.cxx - TracerGPU.hip.cxx - VertexerTraitsGPU.hip.cxx - Utils.hip.cxx + set(CMAKE_HIP_FLAGS "${CMAKE_HIP_FLAGS} ${O2_HIP_CMAKE_CXX_FLAGS} -fgpu-rdc") + o2_add_hipified_library(ITStrackingHIP + SOURCES ../cuda/ClusterLinesGPU.cu + ../cuda/Context.cu + ../cuda/TimeFrameGPU.cu + ../cuda/Stream.cu + ../cuda/TrackerTraitsGPU.cu + ../cuda/TracerGPU.cu + ../cuda/VertexerTraitsGPU.cu + ../cuda/Utils.cu PUBLIC_INCLUDE_DIRECTORIES ../ PUBLIC_LINK_LIBRARIES O2::ITStracking hip::host @@ -48,11 +28,8 @@ if(HIP_ENABLED) hip::hipcub TARGETVARNAME targetName) - target_compile_definitions( - ${targetName} PRIVATE $) - if(O2_HIP_CMAKE_LINK_FLAGS) # Need to add gpu target also to link flags due to gpu-rdc option - target_link_options(${targetName} PUBLIC ${O2_HIP_CMAKE_LINK_FLAGS}) + target_link_options(${targetName} PRIVATE ${O2_HIP_CMAKE_LINK_FLAGS}) endif() endif() diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index 0330a60dac2af..f933f7e8c1822 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -50,7 +50,7 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") set(RTC_CUDA_ARCH "750") endif() separate_arguments(CUDARTC_FLAGS) - + # convenience variables if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") get_filename_component(GPUDIR ${CMAKE_SOURCE_DIR}/../ ABSOLUTE) @@ -78,7 +78,7 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") VERBATIM ) create_binary_resource(${CURTC_BIN}.command ${CURTC_BIN}.command.o) - + set(SRCS ${SRCS} ${CURTC_BIN}.src.o ${CURTC_BIN}.command.o) endif() # -------------------------------- End RTC ------------------------------------------------------- @@ -124,8 +124,6 @@ if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") install(TARGETS ${targetName} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib) install(FILES ${HDRS} DESTINATION include) - - endif() if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") @@ -136,14 +134,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") endif() target_link_libraries(${targetName} PRIVATE cuda cudart nvrtc) -target_compile_definitions(${targetName} PUBLIC GPUCA_GPULIBRARY=CUDA) -if(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET STREQUAL "86") -target_compile_definitions(${targetName} PUBLIC GPUCA_GPUTYPE_AMPERE) -elseif(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET STREQUAL "75") -target_compile_definitions(${targetName} PUBLIC GPUCA_GPUTYPE_TURING) -else() -target_compile_definitions(${targetName} PUBLIC GPUCA_GPUTYPE_AMPERE) -endif() +set_target_cuda_arch(${targetName}) if(OpenMP_CXX_FOUND) # Must be private, depending libraries might be compiled by compiler not understanding -fopenmp diff --git a/GPU/GPUTracking/Base/hip/CMakeLists.txt b/GPU/GPUTracking/Base/hip/CMakeLists.txt index 7d0d651b1a3b5..ad3d2465ba76a 100644 --- a/GPU/GPUTracking/Base/hip/CMakeLists.txt +++ b/GPU/GPUTracking/Base/hip/CMakeLists.txt @@ -88,15 +88,4 @@ if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") install(TARGETS GPUTrackingHIP) endif() -if(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET MATCHES "gfx906") - message(STATUS "Using optimized HIP settings for MI50 GPU") - target_compile_definitions(${targetName} PUBLIC GPUCA_GPUTYPE_VEGA) -elseif(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET MATCHES "gfx908") - message(STATUS "Using optimized HIP settings for MI100 GPU") - target_compile_definitions(${targetName} PUBLIC GPUCA_GPUTYPE_MI2xx) -elseif(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET MATCHES "gfx90a") - message(STATUS "Using optimized HIP settings for MI210 GPU") - target_compile_definitions(${targetName} PUBLIC GPUCA_GPUTYPE_MI2xx) -else() - target_compile_definitions(${targetName} PUBLIC GPUCA_GPUTYPE_VEGA) -endif() +set_target_hip_arch(${targetName}) \ No newline at end of file diff --git a/GPU/GPUbenchmark/Shared/Kernels.h b/GPU/GPUbenchmark/Shared/Kernels.h index b16cfcde162ee..900b683f24219 100644 --- a/GPU/GPUbenchmark/Shared/Kernels.h +++ b/GPU/GPUbenchmark/Shared/Kernels.h @@ -32,7 +32,7 @@ class GPUbenchmark final { public: GPUbenchmark() = delete; // need for a configuration - GPUbenchmark(benchmarkOpts& opts, std::shared_ptr rWriter) : mResultWriter{rWriter}, mOptions{opts} + GPUbenchmark(benchmarkOpts& opts) : mOptions{opts} { } virtual ~GPUbenchmark() = default; @@ -82,7 +82,6 @@ class GPUbenchmark final private: gpuState mState; - std::shared_ptr mResultWriter; benchmarkOpts mOptions; }; diff --git a/GPU/GPUbenchmark/Shared/Utils.h b/GPU/GPUbenchmark/Shared/Utils.h index 6afa988bd9901..97d6788eb01de 100644 --- a/GPU/GPUbenchmark/Shared/Utils.h +++ b/GPU/GPUbenchmark/Shared/Utils.h @@ -27,8 +27,6 @@ #include #include #include -#include -#include #define KNRM "\x1B[0m" #define KRED "\x1B[31m" @@ -49,6 +47,11 @@ exit(EXIT_FAILURE); #endif +template +void discardResult(const T&) +{ +} + enum class Test { Read, Write, @@ -258,66 +261,5 @@ struct gpuState { size_t nMaxThreadsPerBlock; }; -// Interface class to stream results to root file -class ResultWriter -{ - public: - explicit ResultWriter(const std::string resultsTreeFilename = "benchmark_results.root"); - ~ResultWriter() = default; - void storeBenchmarkEntry(Test test, int chunk, float entry, float chunkSizeGB, int nLaunches); - void addBenchmarkEntry(const std::string bName, const std::string type, const int nChunks); - void snapshotBenchmark(); - void saveToFile(); - - private: - std::vector mTimeResults; - std::vector mTimeTrees; - std::vector mThroughputResults; - std::vector mThroughputTrees; - TFile* mOutfile; -}; - -inline ResultWriter::ResultWriter(const std::string resultsTreeFilename) -{ - mOutfile = TFile::Open(resultsTreeFilename.data(), "recreate"); -} - -inline void ResultWriter::addBenchmarkEntry(const std::string bName, const std::string type, const int nChunks) -{ - mTimeTrees.emplace_back(new TTree((bName + "_" + type).data(), (bName + "_" + type).data())); - mTimeResults.clear(); - mTimeResults.resize(nChunks); - mTimeTrees.back()->Branch("elapsed", &mTimeResults); - - mThroughputTrees.emplace_back(new TTree((bName + "_" + type + "_TP").data(), (bName + "_" + type + "_TP").data())); - mThroughputResults.clear(); - mThroughputResults.resize(nChunks); - mThroughputTrees.back()->Branch("throughput", &mThroughputResults); -} - -inline void ResultWriter::storeBenchmarkEntry(Test test, int chunk, float entry, float chunkSizeGB, int nLaunches) -{ - mTimeResults[chunk] = entry; - mThroughputResults[chunk] = computeThroughput(test, entry, chunkSizeGB, nLaunches); -} - -inline void ResultWriter::snapshotBenchmark() -{ - mTimeTrees.back()->Fill(); - mThroughputTrees.back()->Fill(); -} - -inline void ResultWriter::saveToFile() -{ - mOutfile->cd(); - for (auto t : mTimeTrees) { - t->Write(); - } - for (auto t : mThroughputTrees) { - t->Write(); - } - mOutfile->Close(); -} - } // namespace benchmark } // namespace o2 \ No newline at end of file diff --git a/GPU/GPUbenchmark/cuda/Kernels.cu b/GPU/GPUbenchmark/cuda/Kernels.cu index 8c2bddc7634ae..c455e8f6126f4 100644 --- a/GPU/GPUbenchmark/cuda/Kernels.cu +++ b/GPU/GPUbenchmark/cuda/Kernels.cu @@ -428,13 +428,14 @@ float GPUbenchmark::runSequential(void (*kernel)(chunk_t*, size_t, T... // Warm up (*kernel)<<>>(chunkPtr, getBufferCapacity(chunk.second, mOptions.prime), args...); - + GPUCHECK(cudaGetLastError()); GPUCHECK(cudaEventCreate(&start)); GPUCHECK(cudaEventCreate(&stop)); GPUCHECK(cudaEventRecord(start)); for (auto iLaunch{0}; iLaunch < nLaunches; ++iLaunch) { // Schedule all the requested kernel launches (*kernel)<<>>(chunkPtr, getBufferCapacity(chunk.second, mOptions.prime), args...); // NOLINT: clang-tidy false-positive + GPUCHECK(cudaGetLastError()); } GPUCHECK(cudaEventRecord(stop)); // record checkpoint GPUCHECK(cudaEventSynchronize(stop)); // synchronize executions @@ -653,7 +654,6 @@ void GPUbenchmark::initTest(Test test) template void GPUbenchmark::runTest(Test test, Mode mode, KernelConfig config) { - mResultWriter.get()->addBenchmarkEntry(getTestName(mode, test, config), getType(), mState.getMaxChunks()); auto dimGrid{mState.nMultiprocessors}; auto nBlocks{(config == KernelConfig::Single) ? 1 : (config == KernelConfig::Multi) ? dimGrid / mState.testChunks.size() : (config == KernelConfig::All) ? dimGrid @@ -770,7 +770,6 @@ void GPUbenchmark::runTest(Test test, Mode mode, KernelConfig config) } else { std::cout << "" << measurement << "\t" << iChunk << "\t" << throughput << "\t" << chunkSize << "\t" << result << std::endl; } - mResultWriter.get()->storeBenchmarkEntry(test, iChunk, result, chunk.second, mState.getNKernelLaunches()); } } else if (mode == Mode::Concurrent) { if (!mOptions.raw) { @@ -805,7 +804,6 @@ void GPUbenchmark::runTest(Test test, Mode mode, KernelConfig config) } else { std::cout << "" << measurement << "\t" << iChunk << "\t" << throughput << "\t" << chunkSize << "\t" << results[iChunk] << std::endl; } - mResultWriter.get()->storeBenchmarkEntry(test, iChunk, results[iChunk], chunk.second, mState.getNKernelLaunches()); } if (mState.testChunks.size() > 1) { if (!mOptions.raw) { @@ -850,9 +848,7 @@ void GPUbenchmark::runTest(Test test, Mode mode, KernelConfig config) } else { std::cout << "" << measurement << "\t" << 0 << "\t" << throughput << "\t" << tot << "\t" << result << std::endl; } - mResultWriter.get()->storeBenchmarkEntry(test, 0, result, tot, mState.getNKernelLaunches()); } - mResultWriter.get()->snapshotBenchmark(); } } diff --git a/GPU/GPUbenchmark/cuda/benchmark.cu b/GPU/GPUbenchmark/cuda/benchmark.cu index 603058ea5cf33..5cd87b5307ea4 100644 --- a/GPU/GPUbenchmark/cuda/benchmark.cu +++ b/GPU/GPUbenchmark/cuda/benchmark.cu @@ -11,6 +11,7 @@ /// /// \author mconcas@cern.ch /// +#include #include "../Shared/Kernels.h" #define VERSION "version 0.3" @@ -56,7 +57,7 @@ bool parseArgs(o2::benchmark::benchmarkOpts& conf, int argc, const char* argv[]) if (vm.count("extra")) { o2::benchmark::benchmarkOpts opts; - o2::benchmark::GPUbenchmark bm_dummy{opts, nullptr}; + o2::benchmark::GPUbenchmark bm_dummy{opts}; bm_dummy.printDevices(); return false; } @@ -173,39 +174,32 @@ bool parseArgs(o2::benchmark::benchmarkOpts& conf, int argc, const char* argv[]) return true; } -using o2::benchmark::ResultWriter; - int main(int argc, const char* argv[]) { + std::cout << "Started benchmark with pid: " << getpid() << std::endl; o2::benchmark::benchmarkOpts opts; if (!parseArgs(opts, argc, argv)) { return -1; } - std::shared_ptr writer = std::make_shared(std::to_string(opts.deviceId) + "_" + opts.outFileName + ".root"); - for (auto& dtype : opts.dtypes) { if (dtype == "char") { - o2::benchmark::GPUbenchmark bm_char{opts, writer}; + o2::benchmark::GPUbenchmark bm_char{opts}; bm_char.run(); } else if (dtype == "int") { - o2::benchmark::GPUbenchmark bm_int{opts, writer}; + o2::benchmark::GPUbenchmark bm_int{opts}; bm_int.run(); } else if (dtype == "ulong") { - o2::benchmark::GPUbenchmark bm_size_t{opts, writer}; + o2::benchmark::GPUbenchmark bm_size_t{opts}; bm_size_t.run(); } else if (dtype == "int4") { - o2::benchmark::GPUbenchmark bm_size_t{opts, writer}; + o2::benchmark::GPUbenchmark bm_size_t{opts}; bm_size_t.run(); } else { std::cerr << "Unkonwn data type: " << dtype << std::endl; exit(1); } } - - // save results - writer.get()->saveToFile(); - return 0; } diff --git a/GPU/GPUbenchmark/hip/.gitignore b/GPU/GPUbenchmark/hip/.gitignore index 14f27f00c53c2..d8bb96de21414 100644 --- a/GPU/GPUbenchmark/hip/.gitignore +++ b/GPU/GPUbenchmark/hip/.gitignore @@ -1 +1,2 @@ -*.hip.cxx \ No newline at end of file +*.hip.cxx +*.hip \ No newline at end of file diff --git a/GPU/GPUbenchmark/hip/CMakeLists.txt b/GPU/GPUbenchmark/hip/CMakeLists.txt index 3b85ac6d3554e..94cba1e0ce1ed 100644 --- a/GPU/GPUbenchmark/hip/CMakeLists.txt +++ b/GPU/GPUbenchmark/hip/CMakeLists.txt @@ -10,32 +10,11 @@ # or submit itself to any jurisdiction. message(STATUS "Building GPU HIP benchmark") -# Hipify-perl to generate HIP sources -set(HIPIFY_EXECUTABLE "/opt/rocm/bin/hipify-perl") -file(GLOB CUDA_SOURCES_FULL_PATH "../cuda/*.cu") -foreach(file ${CUDA_SOURCES_FULL_PATH}) - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${file}) - get_filename_component(CUDA_SOURCE ${file} NAME) - string(REPLACE ".cu" "" CUDA_SOURCE_NAME ${CUDA_SOURCE}) - add_custom_command( - OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${CUDA_SOURCE_NAME}.hip.cxx - COMMAND ${HIPIFY_EXECUTABLE} --quiet-warnings ${CMAKE_CURRENT_SOURCE_DIR}/../cuda/${CUDA_SOURCE} | sed '1{/\#include \"hip\\/hip_runtime.h\"/d}' > ${CMAKE_CURRENT_SOURCE_DIR}/${CUDA_SOURCE_NAME}.hip.cxx - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../cuda/${CUDA_SOURCE} - ) -endforeach() +set(CMAKE_HIP_FLAGS "${CMAKE_HIP_FLAGS} ${O2_HIP_CMAKE_CXX_FLAGS} -fgpu-rdc -isystem /opt/rocm/include -fPIC") -set(CMAKE_CXX_COMPILER ${HIP_HIPCC_EXECUTABLE}) -set(CMAKE_CXX_LINKER ${HIP_HIPCC_EXECUTABLE}) -set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${O2_HIP_CMAKE_CXX_FLAGS} -fgpu-rdc") -o2_add_executable(gpu-memory-benchmark-hip - SOURCES benchmark.hip.cxx - Kernels.hip.cxx - PUBLIC_LINK_LIBRARIES hip::host - Boost::program_options - ROOT::Tree - TARGETVARNAME targetName) -if(O2_HIP_CMAKE_LINK_FLAGS) - # Need to add gpu target also to link flags due to gpu-rdc option - target_link_options(${targetName} PUBLIC ${O2_HIP_CMAKE_LINK_FLAGS}) -endif() +o2_add_hipified_executable(gpu-memory-benchmark-hip + SOURCES ../cuda/benchmark.cu + ../cuda/Kernels.cu + PUBLIC_LINK_LIBRARIES hip::host + Boost::program_options + TARGETVARNAME targetName) \ No newline at end of file diff --git a/cmake/O2AddHipifiedExecutable.cmake b/cmake/O2AddHipifiedExecutable.cmake new file mode 100644 index 0000000000000..6f25e3b061cf5 --- /dev/null +++ b/cmake/O2AddHipifiedExecutable.cmake @@ -0,0 +1,76 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +include_guard() + +include(O2AddExecutable) + +function(o2_add_hipified_executable baseTargetName) + # Parse arguments in the same way o2_add_executable does + cmake_parse_arguments(PARSE_ARGV + 1 + A + "IS_TEST;NO_INSTALL;IS_BENCHMARK" + "COMPONENT_NAME;TARGETVARNAME" + "SOURCES;PUBLIC_LINK_LIBRARIES;JOB_POOL") + + # Process each .cu file to generate a .hip file + set(HIPIFY_EXECUTABLE "/opt/rocm/bin/hipify-perl") + set(HIP_SOURCES) + + foreach(file ${A_SOURCES}) + get_filename_component(ABS_CUDA_SORUCE ${file} ABSOLUTE) + if(file MATCHES "\\.cu$") + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${file}) + get_filename_component(CUDA_SOURCE ${file} NAME) + string(REPLACE ".cu" ".hip" HIP_SOURCE ${CUDA_SOURCE}) + set(OUTPUT_HIP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${HIP_SOURCE}") + list(APPEND HIP_SOURCES ${OUTPUT_HIP_FILE}) + + add_custom_command( + OUTPUT ${OUTPUT_HIP_FILE} + COMMAND ${HIPIFY_EXECUTABLE} --quiet-warnings ${ABS_CUDA_SORUCE} | sed '1{/\#include \"hip\\/hip_runtime.h\"/d}' > ${OUTPUT_HIP_FILE} + DEPENDS ${file} + ) + else() + list(APPEND HIP_SOURCES ${file}) + endif() + endforeach() + + # This is a bit cumbersome, but it seems the only suitable since cmake_parse_arguments is not capable to filter only the SOURCE variadic values + set(FORWARD_ARGS "") + if(A_IS_TEST) + list(APPEND FORWARD_ARGS "IS_TEST") + endif() + if(A_NO_INSTALL) + list(APPEND FORWARD_ARGS "NO_INSTALL") + endif() + if(A_IS_BENCHMARK) + list(APPEND FORWARD_ARGS "IS_BENCHMARK") + endif() + if(A_COMPONENT_NAME) + list(APPEND FORWARD_ARGS "COMPONENT_NAME" ${A_COMPONENT_NAME}) + endif() + if(A_TARGETVARNAME) + list(APPEND FORWARD_ARGS "TARGETVARNAME" ${A_TARGETVARNAME}) + endif() + if(A_PUBLIC_LINK_LIBRARIES) + list(APPEND FORWARD_ARGS "PUBLIC_LINK_LIBRARIES" ${A_PUBLIC_LINK_LIBRARIES}) + endif() + if(A_JOB_POOL) + list(APPEND FORWARD_ARGS "JOB_POOL" ${A_JOB_POOL}) + endif() + + # Call o2_add_executable with new sources + o2_add_executable("${baseTargetName}" + SOURCES ${HIP_SOURCES} + ${FORWARD_ARGS}) +endfunction() \ No newline at end of file diff --git a/cmake/O2AddHipifiedLibrary.cmake b/cmake/O2AddHipifiedLibrary.cmake new file mode 100644 index 0000000000000..0c75f8723a435 --- /dev/null +++ b/cmake/O2AddHipifiedLibrary.cmake @@ -0,0 +1,71 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +include_guard() + +include(O2AddLibrary) + +function(o2_add_hipified_library baseTargetName) + # Parse arguments in the same way o2_add_library does + cmake_parse_arguments(PARSE_ARGV + 1 + A + "" + "TARGETVARNAME" + "SOURCES;PUBLIC_INCLUDE_DIRECTORIES;PUBLIC_LINK_LIBRARIES;PRIVATE_INCLUDE_DIRECTORIES;PRIVATE_LINK_LIBRARIES" + ) + + # Process each .cu file to generate a .hip file + set(HIPIFY_EXECUTABLE "/opt/rocm/bin/hipify-perl") + set(HIP_SOURCES) + + foreach(file ${A_SOURCES}) + get_filename_component(ABS_CUDA_SORUCE ${file} ABSOLUTE) + if(file MATCHES "\\.cu$") + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${file}) + get_filename_component(CUDA_SOURCE ${file} NAME) + string(REPLACE ".cu" ".hip" HIP_SOURCE ${CUDA_SOURCE}) + set(OUTPUT_HIP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${HIP_SOURCE}") + list(APPEND HIP_SOURCES ${OUTPUT_HIP_FILE}) + + add_custom_command( + OUTPUT ${OUTPUT_HIP_FILE} + COMMAND ${HIPIFY_EXECUTABLE} --quiet-warnings ${ABS_CUDA_SORUCE} | sed '1{/\#include \"hip\\/hip_runtime.h\"/d}' > ${OUTPUT_HIP_FILE} + DEPENDS ${file} + ) + else() + list(APPEND HIP_SOURCES ${file}) + endif() + endforeach() + + # This is a bit cumbersome, but it seems the only suitable since cmake_parse_arguments is not capable to filter only the SOURCE variadic values + set(FORWARD_ARGS "") + if(A_TARGETVARNAME) + list(APPEND FORWARD_ARGS "TARGETVARNAME" ${A_TARGETVARNAME}) + endif() + if(A_PUBLIC_INCLUDE_DIRECTORIES) + list(APPEND FORWARD_ARGS "PUBLIC_INCLUDE_DIRECTORIES" ${A_PUBLIC_INCLUDE_DIRECTORIES}) + endif() + if(A_PUBLIC_LINK_LIBRARIES) + list(APPEND FORWARD_ARGS "PUBLIC_LINK_LIBRARIES" ${A_PUBLIC_LINK_LIBRARIES}) + endif() + if(A_PRIVATE_INCLUDE_DIRECTORIES) + list(APPEND FORWARD_ARGS "PRIVATE_INCLUDE_DIRECTORIES" ${A_PRIVATE_INCLUDE_DIRECTORIES}) + endif() + if(A_PRIVATE_LINK_LIBRARIES) + list(APPEND FORWARD_ARGS "PRIVATE_LINK_LIBRARIES" ${A_PRIVATE_LINK_LIBRARIES}) + endif() + + # Call o2_add_library with new sources + o2_add_library("${baseTargetName}" + SOURCES ${HIP_SOURCES} + ${FORWARD_ARGS}) +endfunction() \ No newline at end of file diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index 924a724aaa82d..1a504c9e5084e 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -26,6 +26,34 @@ string(TOUPPER "${ENABLE_OPENCL1}" ENABLE_OPENCL1) string(TOUPPER "${ENABLE_OPENCL2}" ENABLE_OPENCL2) string(TOUPPER "${ENABLE_HIP}" ENABLE_HIP) +function(set_target_cuda_arch target) + if(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET STREQUAL "86") + message(STATUS "Using optimized CUDA settings for Ampere GPU") + target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_AMPERE) + elseif(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET STREQUAL "75") + message(STATUS "Using optimized CUDA settings for Turing GPU") + target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_TURING) + else() + message(STATUS "Defaulting optimized CUDA settings for Ampere GPU") + target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_AMPERE) + endif() +endfunction() + +function(set_target_hip_arch target) + if(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET MATCHES "gfx906") + message(STATUS "Using optimized HIP settings for MI50 GPU") + target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_VEGA) + elseif(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET MATCHES "gfx908") + message(STATUS "Using optimized HIP settings for MI100 GPU") + target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_MI2xx) + elseif(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET MATCHES "gfx90a") + message(STATUS "Using optimized HIP settings for MI210 GPU") + target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_MI2xx) + else() + target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_VEGA) + endif() +endfunction() + # Detect and enable CUDA if(ENABLE_CUDA) set(CMAKE_CUDA_STANDARD 17) @@ -178,6 +206,8 @@ if(ENABLE_HIP) set(AMDGPU_TARGETS "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) set(GPU_TARGETS "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) endif() + include(CheckLanguage) + check_language(HIP) if(EXISTS "/opt/rocm/lib/cmake" AND (NOT DEFINED CMAKE_PREFIX_PATH OR NOT ${CMAKE_PREFIX_PATH} MATCHES "rocm") AND (NOT ENV{CMAKE_PREFIX_PATH} MATCHES "rocm")) set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};/opt/rocm/lib/cmake") endif() @@ -200,17 +230,23 @@ if(ENABLE_HIP) set_package_properties(rocprim PROPERTIES TYPE REQUIRED) set_package_properties(rocthrust PROPERTIES TYPE REQUIRED) endif() + if (CMAKE_HIP_COMPILER) + enable_language(HIP) + message(STATUS "HIP language enabled: ${CMAKE_HIP_COMPILER}") + endif() if(hip_FOUND AND hipcub_FOUND AND rocthrust_FOUND AND rocprim_FOUND AND hip_HIPCC_EXECUTABLE AND hip_HIPIFY_PERL_EXECUTABLE) set(HIP_ENABLED ON) set_target_properties(roc::rocthrust PROPERTIES IMPORTED_GLOBAL TRUE) message(STATUS "HIP Found (${hip_HIPCC_EXECUTABLE} version ${hip_VERSION})") set(O2_HIP_CMAKE_CXX_FLAGS "-fgpu-defer-diag -mllvm -amdgpu-enable-lower-module-lds=false -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -Wno-invalid-constexpr -Wno-ignored-optimization-argument -Wno-unused-private-field -Wno-pass-failed") set(O2_HIP_CMAKE_LINK_FLAGS "-Wno-pass-failed") + string(REGEX REPLACE "(gfx1[0-9]+;?)" "" CMAKE_HIP_ARCHITECTURES "${CMAKE_HIP_ARCHITECTURES}") # ROCm currently doesn’t support integrated graphics if(HIP_AMDGPUTARGET) foreach(HIP_ARCH ${HIP_AMDGPUTARGET}) set(O2_HIP_CMAKE_CXX_FLAGS "${O2_HIP_CMAKE_CXX_FLAGS} --offload-arch=${HIP_ARCH}") set(O2_HIP_CMAKE_LINK_FLAGS "${O2_HIP_CMAKE_LINK_FLAGS} --offload-arch=${HIP_ARCH}") endforeach() + set(CMAKE_HIP_ARCHITECTURES "${HIP_AMDGPUTARGET}") # If GPU build is enforced we override autodetection endif() if(NOT DEFINED GPUCA_NO_FAST_MATH OR NOT ${GPUCA_NO_FAST_MATH}) set(O2_HIP_CMAKE_CXX_FLAGS "${O2_HIP_CMAKE_CXX_FLAGS} -fgpu-flush-denormals-to-zero") # -ffast-math disabled, since apparently it leads to miscompilation and crashes in FollowLooper kernel @@ -219,6 +255,7 @@ if(ENABLE_HIP) string(REGEX REPLACE "(.*)bin/c\\+\\+\$" "\\1" HIP_GCC_TOOLCHAIN_PATH "${CMAKE_CXX_COMPILER}") set(O2_HIP_CMAKE_CXX_FLAGS "${O2_HIP_CMAKE_CXX_FLAGS} --gcc-toolchain=${HIP_GCC_TOOLCHAIN_PATH}") # -ffast-math disabled, since apparently it leads to miscompilation and crashes in FollowLooper kernel endif() + set(CMAKE_HIP_FLAGS "${CMAKE_HIP_FLAGS} ${O2_HIP_CMAKE_CXX_FLAGS}") else() set(HIP_ENABLED OFF) endif() From 1daca29e04d2dd2598c9a850254ed542e962e98f Mon Sep 17 00:00:00 2001 From: shahoian Date: Tue, 17 Oct 2023 17:05:06 +0200 Subject: [PATCH 283/324] Set Maurice as a codewonwer of MFT --- CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 908640415ed89..4fed61cf41a5c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -34,7 +34,7 @@ /DataFormats/Detectors/GlobalTracking @shahor02 /DataFormats/Detectors/GlobalTrackingWorkflow @shahor02 /DataFormats/Detectors/HMPID @gvolpe79 -/DataFormats/Detectors/ITSMFT @iouribelikov @robincaron13 @mconcas @shahor02 +/DataFormats/Detectors/ITSMFT @mcoquet642 @mconcas @shahor02 /DataFormats/Detectors/MUON @AliceO2Group/muon-experts /DataFormats/Detectors/PHOS @peressounko @kharlov /DataFormats/Detectors/Passive @sawenzel @benedikt-voelkel @@ -65,7 +65,7 @@ /Detectors/GlobalTracking @shahor02 /Detectors/GlobalTrackingWorkflow @shahor02 /Detectors/HMPID @gvolpe79 -/Detectors/ITSMFT @iouribelikov @robincaron13 @mconcas @shahor02 +/Detectors/ITSMFT @mcoquet642 @mconcas @shahor02 /Detectors/MUON @AliceO2Group/muon-experts /Detectors/PHOS @peressounko @kharlov /Detectors/Passive @sawenzel @benedikt-voelkel From f58fcba4c8a288f3b114b11c060a32713608883d Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Fri, 13 Oct 2023 16:08:21 +0200 Subject: [PATCH 284/324] Integrated currents: Adding check if any data has been received --- .../IntegratedClusterCalibrator.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h b/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h index 884997d54865e..82189ab6fdb9c 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h +++ b/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h @@ -641,7 +641,7 @@ class IntegratedClusters void merge(const IntegratedClusters* prev); /// \return always return true. To specify the number of time slot intervals to wait for one should use the --max-delay option - bool hasEnoughData() const { return true; } + bool hasEnoughData() const { return (mRemainingData != -1); } /// \return returns accumulated currents const auto& getCurrents() const& { return mCurrents; } @@ -665,12 +665,12 @@ class IntegratedClusters void setStartTime(long timeMS) { mCurrents.setStartTime(timeMS); } private: - DataT mCurrents; ///< buffer for integrated currents - o2::calibration::TFType mTFFirst{}; ///< first TF of currents - o2::calibration::TFType mTFLast{}; ///< last TF of currents - o2::calibration::TFType mRemainingData{}; ///< counter for received data - unsigned int mNValuesPerTF{}; ///< number of expected currents per TF (estimated from first received data) - bool mInitialize{true}; ///< flag if this object will be initialized when fill method is called + DataT mCurrents; ///< buffer for integrated currents + o2::calibration::TFType mTFFirst{}; ///< first TF of currents + o2::calibration::TFType mTFLast{}; ///< last TF of currents + o2::calibration::TFType mRemainingData = -1; ///< counter for received data + unsigned int mNValuesPerTF{}; ///< number of expected currents per TF (estimated from first received data) + bool mInitialize{true}; ///< flag if this object will be initialized when fill method is called /// init member when first data is received /// \param valuesPerTF number of expected values per TF From 1ab5d42a528612db79b1617f7f2c35b0d2ba305c Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 18 Oct 2023 08:42:07 +0200 Subject: [PATCH 285/324] Fix various codechecker issues --- .../postprocessing/studies/src/TrackCheck.cxx | 124 +++++++++++------- 1 file changed, 73 insertions(+), 51 deletions(-) diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx index 194b6bbaec363..87c76e492e0fa 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx @@ -37,11 +37,7 @@ #include #include -namespace o2 -{ -namespace its -{ -namespace study +namespace o2::its::study { using namespace o2::framework; using namespace o2::globaltracking; @@ -64,7 +60,7 @@ class TrackCheckStudy : public Task int unsigned short clusters = 0u; unsigned char isReco = 0u; unsigned char isFake = 0u; - bool isPrimary = 0u; + bool isPrimary = false; unsigned char storedStatus = 2; /// not stored = 2, fake = 1, good = 0 const char* prodProcessName; int prodProcess; @@ -376,8 +372,9 @@ void TrackCheckStudy::init(InitContext& ic) histLengthNoCl[iH - 4][jj] = new TH1I(Form("trk_len_%d_nocl_%s", iH, name[jj]), Form("#slash{#exists} cluster %s", name[jj]), 7, -.5, 6.5); histLengthNoCl[iH - 4][jj]->SetFillColor(colorArr[jj] + 1); histLengthNoCl[iH - 4][jj]->SetLineColor(colorArr[jj] + 1); - if (jj == 0) + if (jj == 0) { stackLength[iH - 4] = new THStack(Form("stack_trk_len_%d", iH), Form("trk_len=%d", iH)); + } stackLength[iH - 4]->Add(histLength[iH - 4][jj]); stackLength[iH - 4]->Add(histLengthNoCl[iH - 4][jj]); @@ -387,8 +384,9 @@ void TrackCheckStudy::init(InitContext& ic) histLength1FakeNoCl[iH - 4][jj] = new TH1I(Form("trk_len_%d_1f_nocl_%s", iH, name[jj]), Form("#slash{#exists} cluster %s", name[jj]), 7, -.5, 6.5); histLength1FakeNoCl[iH - 4][jj]->SetFillColor(colorArr[jj] + 1); histLength1FakeNoCl[iH - 4][jj]->SetLineColor(colorArr[jj] + 1); - if (jj == 0) + if (jj == 0) { stackLength1Fake[iH - 4] = new THStack(Form("stack_trk_len_%d_1f", iH), Form("trk_len=%d, 1 Fake", iH)); + } stackLength1Fake[iH - 4]->Add(histLength1Fake[iH - 4][jj]); stackLength1Fake[iH - 4]->Add(histLength1FakeNoCl[iH - 4][jj]); @@ -398,8 +396,9 @@ void TrackCheckStudy::init(InitContext& ic) histLength2FakeNoCl[iH - 4][jj] = new TH1I(Form("trk_len_%d_2f_nocl_%s", iH, name[jj]), Form("#slash{#exists} cluster %s", name[jj]), 7, -.5, 6.5); histLength2FakeNoCl[iH - 4][jj]->SetFillColor(colorArr[jj] + 1); histLength2FakeNoCl[iH - 4][jj]->SetLineColor(colorArr[jj] + 1); - if (jj == 0) + if (jj == 0) { stackLength2Fake[iH - 4] = new THStack(Form("stack_trk_len_%d_2f", iH), Form("trk_len=%d, 2 Fake", iH)); + } stackLength2Fake[iH - 4]->Add(histLength2Fake[iH - 4][jj]); stackLength2Fake[iH - 4]->Add(histLength2FakeNoCl[iH - 4][jj]); @@ -410,8 +409,9 @@ void TrackCheckStudy::init(InitContext& ic) histLength3FakeNoCl[iH - 4][jj] = new TH1I(Form("trk_len_%d_3f_nocl_%s", iH, name[jj]), Form("#slash{#exists} cluster %s", name[jj]), 7, -.5, 6.5); histLength3FakeNoCl[iH - 4][jj]->SetFillColor(colorArr[jj] + 1); histLength3FakeNoCl[iH - 4][jj]->SetLineColor(colorArr[jj] + 1); - if (jj == 0) + if (jj == 0) { stackLength3Fake[iH - 4] = new THStack(Form("stack_trk_len_%d_3f", iH), Form("trk_len=%d, 3 Fake", iH)); + } stackLength3Fake[iH - 4]->Add(histLength3Fake[iH - 4][jj]); stackLength3Fake[iH - 4]->Add(histLength3FakeNoCl[iH - 4][jj]); } @@ -485,7 +485,7 @@ void TrackCheckStudy::process() } } LOGP(info, "** Analysing tracks ... "); - int unaccounted{0}, good{0}, fakes{0}, total{0}; + int unaccounted{0}, good{0}, fakes{0}; // ***secondary tracks*** int nPartForSpec[4][4]; // total number [particle 0=IperT, 1=Lambda, 2=k, 3=Other][n layer] int nPartGoodorFake[4][4][2]; // number of good or fake [particle 0=IperT, 1=Lambda, 2=k, 3=Other][n layer][good=1 fake=0] @@ -511,7 +511,6 @@ void TrackCheckStudy::process() int trackID, evID, srcID; bool fake; const_cast(lab).get(trackID, evID, srcID, fake); - bool pass{true}; if (srcID == 99) { // skip QED unaccounted++; @@ -542,8 +541,9 @@ void TrackCheckStudy::process() trackID = 0; for (auto& part : evInfo) { - if (strcmp(ProcessName[part.prodProcess], " ")) + if (strcmp(ProcessName[part.prodProcess], " ")) { ProcessName[part.prodProcess] = part.prodProcessName; + } if ((part.clusters & 0x7f) == mMask) { // part.clusters != 0x3f && part.clusters != 0x3f << 1 && // part.clusters != 0x1f && part.clusters != 0x1f << 1 && part.clusters != 0x1f << 2 && @@ -588,14 +588,18 @@ void TrackCheckStudy::process() float rad = sqrt(pow(part.vx, 2) + pow(part.vy, 2)); totsec++; - if ((rad < rLayer0) && (part.clusters == 0x7f || part.clusters == 0x3f || part.clusters == 0x1f || part.clusters == 0x0f)) // layer 0 + if ((rad < rLayer0) && (part.clusters == 0x7f || part.clusters == 0x3f || part.clusters == 0x1f || part.clusters == 0x0f)) { // layer 0 nlayer = 0; - if (rad < rLayer1 && rad > rLayer0 && (part.clusters == 0x1e || part.clusters == 0x3e || part.clusters == 0x7e)) // layer 1 + } + if (rad < rLayer1 && rad > rLayer0 && (part.clusters == 0x1e || part.clusters == 0x3e || part.clusters == 0x7e)) { // layer 1 nlayer = 1; - if (rad < rLayer2 && rad > rLayer1 && (part.clusters == 0x7c || part.clusters == 0x3c)) // layer 2 + } + if (rad < rLayer2 && rad > rLayer1 && (part.clusters == 0x7c || part.clusters == 0x3c)) { // layer 2 nlayer = 2; - if (rad < rLayer3 && rad > rLayer2 && part.clusters == 0x78) // layer 3 + } + if (rad < rLayer3 && rad > rLayer2 && part.clusters == 0x78) { // layer 3 nlayer = 3; + } if (nlayer == 0 || nlayer == 1 || nlayer == 2 || nlayer == 3) { // check if track is trackeable totsecCont++; @@ -609,12 +613,15 @@ void TrackCheckStudy::process() mTotEtas[nlayer][3]->Fill(part.eta); mTotPts[nlayer][3]->Fill(part.pt); mTotEtas[nlayer][3]->Fill(part.eta); - if (pdgcode == PDG[0] || pdgcode == -1 * PDG[0]) + if (pdgcode == PDG[0] || pdgcode == -1 * PDG[0]) { idxPart = 0; // IperT - if (pdgcode == PDG[1] || pdgcode == -1 * PDG[1]) + } + if (pdgcode == PDG[1] || pdgcode == -1 * PDG[1]) { idxPart = 1; // Lambda - if (pdgcode == PDG[2] || pdgcode == -1 * PDG[2]) + } + if (pdgcode == PDG[2] || pdgcode == -1 * PDG[2]) { idxPart = 2; // K0s + } if (part.isReco) { ngoodfake = 1; mGoodPts[3][nlayer]->Fill(part.pt); @@ -662,8 +669,9 @@ void TrackCheckStudy::process() processvsEtaNotTracked->Fill(part.eta, part.prodProcess); processvsRadNotTracked->Fill(rad, part.prodProcess); } - if (ngoodfake == 1 || ngoodfake == 0) + if (ngoodfake == 1 || ngoodfake == 0) { nPartGoodorFake[idxPart][nlayer][ngoodfake]++; + } nPartForSpec[idxPart][nlayer]++; // Analysing fake clusters @@ -718,11 +726,13 @@ void TrackCheckStudy::process() const_cast(lab).get(TrackID, EvID, SrcID, fakec); double intHisto = 0; for (int hg = 0; hg < 7; hg++) { - if (mParticleInfo[SrcID][EvID][TrackID].pdg == PdgcodeClusterFake[hg] || mParticleInfo[SrcID][EvID][TrackID].pdg == -1 * (PdgcodeClusterFake[hg])) + if (mParticleInfo[SrcID][EvID][TrackID].pdg == PdgcodeClusterFake[hg] || mParticleInfo[SrcID][EvID][TrackID].pdg == -1 * (PdgcodeClusterFake[hg])) { intHisto = hg + 0.5; + } } - if (idxPart < 3) + if (idxPart < 3) { mClusterFake[idxPart]->Fill(intHisto, mParticleInfo[SrcID][EvID][TrackID].prodProcess); + } } } } @@ -741,14 +751,18 @@ void TrackCheckStudy::process() for (int yy = 0; yy < 4; yy++) { totgood = totgood + nPartGoodorFake[xx][yy][1]; totfake = totfake + nPartGoodorFake[xx][yy][0]; - if (xx == 0) + if (xx == 0) { totI = totI + nPartForSpec[0][yy]; - if (xx == 1) + } + if (xx == 1) { totL = totL + nPartForSpec[1][yy]; - if (xx == 2) + } + if (xx == 2) { totK = totK + nPartForSpec[2][yy]; - if (xx == 3) + } + if (xx == 3) { totO = totO + nPartForSpec[3][yy]; + } } } LOGP(info, "number of primary tracks: {}, good:{}, fake:{}", totP, goodP, fakeP); @@ -800,18 +814,20 @@ void TrackCheckStudy::process() LOGP(info, "** Analysing pT resolution..."); for (auto iTrack{0}; iTrack < mTracks.size(); ++iTrack) { auto& lab = mTracksMCLabels[iTrack]; - if (!lab.isSet() || lab.isNoise()) + if (!lab.isSet() || lab.isNoise()) { continue; + } int trackID, evID, srcID; bool fake; const_cast(lab).get(trackID, evID, srcID, fake); - bool pass{true}; - if (srcID == 99) + if (srcID == 99) { continue; // skip QED + } mPtResolution->Fill((mParticleInfo[srcID][evID][trackID].pt - mTracks[iTrack].getPt()) / mParticleInfo[srcID][evID][trackID].pt); mPtResolution2D->Fill(mParticleInfo[srcID][evID][trackID].pt, (mParticleInfo[srcID][evID][trackID].pt - mTracks[iTrack].getPt()) / mParticleInfo[srcID][evID][trackID].pt); - if (!mParticleInfo[srcID][evID][trackID].isPrimary) + if (!mParticleInfo[srcID][evID][trackID].isPrimary) { mPtResolutionSec->Fill((mParticleInfo[srcID][evID][trackID].pt - mTracks[iTrack].getPt()) / mParticleInfo[srcID][evID][trackID].pt); + } mPtResolutionPrim->Fill((mParticleInfo[srcID][evID][trackID].pt - mTracks[iTrack].getPt()) / mParticleInfo[srcID][evID][trackID].pt); } @@ -1069,9 +1085,9 @@ void TrackCheckStudy::endOfStream(EndOfStreamContext& ec) mLegendRadD = std::make_unique(0.8, 0.64, 0.95, 0.8); mLegendRadD->SetHeader(Form("%zu events PP ", mKineReader->getNEvents(0)), "C"); for (int i = 0; i < 3; i++) { - if (i == 0) + if (i == 0) { mEffGoodRad[i]->Draw("pz"); - else { + } else { mEffGoodRad[i]->Draw("pz same"); mEffFakeRad[i]->Draw("pz same"); mLegendRadD->AddEntry(Form("Good_Rad%s", particleToanalize[i]), Form("%s_good", name[i]), "lep"); @@ -1088,9 +1104,9 @@ void TrackCheckStudy::endOfStream(EndOfStreamContext& ec) mLegendZD = std::make_unique(0.8, 0.64, 0.95, 0.8); mLegendZD->SetHeader(Form("%zu events PP ", mKineReader->getNEvents(0)), "C"); for (int i = 0; i < 3; i++) { - if (i == 0) + if (i == 0) { mEffGoodZ[i]->Draw("pz"); - else { + } else { mEffGoodZ[i]->Draw("pz same"); mEffFakeZ[i]->Draw("pz same"); mLegendZD->AddEntry(Form("Good_Z%s", particleToanalize[i]), Form("%s_good", name[i]), "lep"); @@ -1131,7 +1147,7 @@ void TrackCheckStudy::endOfStream(EndOfStreamContext& ec) mCanvasPtRes3 = std::make_unique("cPtr3", "cPtr3", 1600, 1200); mCanvasPtRes3->cd(); - TGraphErrors* g1 = new TGraphErrors(100, meanPt, sigma, aa, sigmaerr); + auto* g1 = new TGraphErrors(100, meanPt, sigma, aa, sigmaerr); g1->SetMarkerStyle(8); g1->SetMarkerColor(kGreen); g1->GetXaxis()->SetTitle(" #it{p}_{T} [GeV]"); @@ -1197,12 +1213,14 @@ void TrackCheckStudy::endOfStream(EndOfStreamContext& ec) for (int iH{0}; iH < 4; ++iH) { canvasPtfake->cd(iH + 1); for (int v = 0; v < 4; v++) { - if (v == 0) + if (v == 0) { canvasPtfake->cd(iH + 1); - if (v == 0) + } + if (v == 0) { mEffFakePts[v][iH]->Draw(); - else + } else { mEffFakePts[v][iH]->Draw("same"); + } } gPad->BuildLegend(); gPad->SetGrid(); @@ -1217,12 +1235,14 @@ void TrackCheckStudy::endOfStream(EndOfStreamContext& ec) for (int iH{0}; iH < 4; ++iH) { canvasPtGood->cd(iH + 1); for (int v = 0; v < 4; v++) { - if (v == 0) + if (v == 0) { canvasPtGood->cd(iH + 1); - if (v == 0) + } + if (v == 0) { mEffGoodPts[v][iH]->Draw(); - else + } else { mEffGoodPts[v][iH]->Draw("same"); + } } gPad->BuildLegend(); gPad->SetGrid(); @@ -1236,12 +1256,14 @@ void TrackCheckStudy::endOfStream(EndOfStreamContext& ec) for (int iH{0}; iH < 4; ++iH) { canvasEtafake->cd(iH + 1); for (int v = 0; v < 4; v++) { - if (v == 0) + if (v == 0) { canvasEtafake->cd(iH + 1); - if (v == 0) + } + if (v == 0) { mEffFakeEtas[v][iH]->Draw(); - else + } else { mEffFakeEtas[v][iH]->Draw("same"); + } } gPad->BuildLegend(); gPad->SetGrid(); @@ -1254,12 +1276,14 @@ void TrackCheckStudy::endOfStream(EndOfStreamContext& ec) for (int iH{0}; iH < 4; ++iH) { canvasEtaGood->cd(iH + 1); for (int v = 0; v < 4; v++) { - if (v == 0) + if (v == 0) { canvasEtaGood->cd(iH + 1); - if (v == 0) + } + if (v == 0) { mEffGoodEtas[v][iH]->Draw(); - else + } else { mEffGoodEtas[v][iH]->Draw("same"); + } } gPad->BuildLegend(); gPad->SetGrid(); @@ -1353,6 +1377,4 @@ DataProcessorSpec getTrackCheckStudy(mask_t srcTracksMask, mask_t srcClustersMas Options{}}; } -} // namespace study -} // namespace its -} // namespace o2 \ No newline at end of file +} // namespace o2::its::study From 6c5fcab2ad3ac0c0f675df86dac370b7cbb431fa Mon Sep 17 00:00:00 2001 From: Francesco Mazzaschi <43742195+fmazzasc@users.noreply.github.com> Date: Wed, 18 Oct 2023 09:55:22 +0200 Subject: [PATCH 286/324] [Strangeness Tracking] Fix cascade invariant masses (#12091) * Fix cascade invariant masses * Please consider the following formatting changes --------- Co-authored-by: ALICE Action Bot --- .../include/StrangenessTracking/StrangenessTracker.h | 1 - .../Vertexing/StrangenessTracking/src/StrangenessTracker.cxx | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/StrangenessTracker.h b/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/StrangenessTracker.h index f6c8e81682fcc..c1b56c7c40110 100644 --- a/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/StrangenessTracker.h +++ b/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/StrangenessTracker.h @@ -290,7 +290,6 @@ class StrangenessTracker o2::base::PropagatorImpl::MatCorrType mCorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrNONE; // use mat correction std::vector> mDaughterTracks; // vector of daughter tracks (per thread) - StrangeTrack mStrangeTrack; // structure containing updated mother and daughter track refs ClusAttachments mStructClus; // # of attached tracks, 1 for mother, 2 for daughter ClassDefNV(StrangenessTracker, 1); diff --git a/Detectors/Vertexing/StrangenessTracking/src/StrangenessTracker.cxx b/Detectors/Vertexing/StrangenessTracking/src/StrangenessTracker.cxx index 97ce3d780faaa..e1ea987e6dbc8 100644 --- a/Detectors/Vertexing/StrangenessTracking/src/StrangenessTracker.cxx +++ b/Detectors/Vertexing/StrangenessTracking/src/StrangenessTracker.cxx @@ -207,8 +207,8 @@ void StrangenessTracker::processCascade(int iCasc, const Cascade& casc, const Ca std::array momV0, mombach; mFitter3Body[iThread].getTrack(0).getPxPyPzGlo(momV0); // V0 momentum at decay vertex mFitter3Body[iThread].getTrack(1).getPxPyPzGlo(mombach); // bachelor momentum at decay vertex - mStrangeTrack.mMasses[0] = calcMotherMass(momV0, mombach, PID::Lambda, PID::Pion); // Xi invariant mass at decay vertex - mStrangeTrack.mMasses[1] = calcMotherMass(momV0, mombach, PID::Lambda, PID::Kaon); // Omega invariant mass at decay vertex + strangeTrack.mMasses[0] = calcMotherMass(momV0, mombach, PID::Lambda, PID::Pion); // Xi invariant mass at decay vertex + strangeTrack.mMasses[1] = calcMotherMass(momV0, mombach, PID::Lambda, PID::Kaon); // Omega invariant mass at decay vertex LOG(debug) << "ITS Track matched with a Cascade decay topology ...."; LOG(debug) << "Number of ITS track clusters attached: " << itsTrack.getNumberOfClusters(); From 4e9772a78444e93351128f8aa3d02200d75a09c5 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 16 Oct 2023 14:20:22 +0200 Subject: [PATCH 287/324] DPL: Check for EoS on all channels before invoking control->endOfStream() --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 4cc861c0edb73..d675deee43a4b 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -54,6 +54,7 @@ namespace o2::framework { +// We do not allow to send EoS in online runs, until we receive (which is checked below) them upstream (to prevent premature shutdown of calibration) static bool gAllowEoSdefault = !(DefaultsHelpers::deploymentMode() == DeploymentMode::OnlineDDS || DefaultsHelpers::deploymentMode() == DeploymentMode::OnlineECS); static bool gAllowEoS = gAllowEoSdefault; @@ -815,7 +816,16 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, // * If a connection sends two EoS. // * If a connection sends an end of stream closes and another one opens. // Finally, if we didn't receive an EoS this time, out counting of the connected peers is off, so the best thing we can do is delay the EoS reporting - bool everyEoS = shouldstop || (numberOfEoS[ci] >= eosPeersCount[ci] && nEos); + bool everyEoS = shouldstop; + if (!shouldstop && nEos) { + everyEoS = true; + for (unsigned int i = 0; i < numberOfEoS.size(); i++) { + if (numberOfEoS[i] < eosPeersCount[i]) { + everyEoS = false; + break; + } + } + } if (everyEoS) { LOG(info) << "Received " << numberOfEoS[ci] << " end-of-stream from " << eosPeersCount[ci] << " peers, forwarding end-of-stream (shouldstop " << (int)shouldstop << ", nEos " << nEos << ", newRun " << (int)newRun << ")"; From b2358d84ebde2e6ce347cb96bd3bc14960df1781 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 16 Oct 2023 14:22:24 +0200 Subject: [PATCH 288/324] Revert "DPL: If in OnlineMode, input proxies should only send EoS if they receive it" This reverts commit ed52430476f2bdb566ae5738f62efefb4323df32. --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index d675deee43a4b..d1a45a95c6d98 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -29,8 +29,6 @@ #include "Framework/TimingInfo.h" #include "Framework/DeviceState.h" #include "Framework/Monitoring.h" -#include "Framework/DefaultsHelpers.h" -#include "Framework/DataTakingContext.h" #include "Headers/DataHeader.h" #include "Headers/Stack.h" #include "DecongestionService.h" @@ -54,10 +52,6 @@ namespace o2::framework { -// We do not allow to send EoS in online runs, until we receive (which is checked below) them upstream (to prevent premature shutdown of calibration) -static bool gAllowEoSdefault = !(DefaultsHelpers::deploymentMode() == DeploymentMode::OnlineDDS || DefaultsHelpers::deploymentMode() == DeploymentMode::OnlineECS); -static bool gAllowEoS = gAllowEoSdefault; - using DataHeader = o2::header::DataHeader; std::string formatExternalChannelConfiguration(InputChannelSpec const& spec) @@ -797,7 +791,6 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, if (newRun) { std::fill(numberOfEoS.begin(), numberOfEoS.end(), 0); std::fill(eosPeersCount.begin(), eosPeersCount.end(), 0); - gAllowEoS = gAllowEoSdefault; } numberOfEoS[ci] += nEos; if (numberOfEoS[ci]) { @@ -828,8 +821,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, } if (everyEoS) { - LOG(info) << "Received " << numberOfEoS[ci] << " end-of-stream from " << eosPeersCount[ci] << " peers, forwarding end-of-stream (shouldstop " << (int)shouldstop << ", nEos " << nEos << ", newRun " << (int)newRun << ")"; - gAllowEoS = true; + LOG(info) << "Received (on channel " << ci << ") " << numberOfEoS[ci] << " end-of-stream from " << eosPeersCount[ci] << " peers, forwarding end-of-stream (shouldstop " << (int)shouldstop << ", nEos " << nEos << ", newRun " << (int)newRun << ")"; // Mark all input channels as closed for (auto& info : deviceState->inputChannelInfos) { info.state = InputChannelState::Completed; @@ -957,9 +949,6 @@ DataProcessorSpec specifyFairMQDeviceOutputProxy(char const* name, // DPL implements an internal end of stream signal, which is propagated through // all downstream channels if a source is dry, make it available to other external // devices via a message of type {DPL/EOS/0} - if (!gAllowEoS) { - return; - } for (auto& channelInfo : device->GetChannels()) { auto& channelName = channelInfo.first; if (channelName != outputChannelName) { From c5b9e8af3a7402ceecdf104d0513618cf9024f2c Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 16 Oct 2023 22:10:17 +0200 Subject: [PATCH 289/324] DPL: add finaliseOutputs callback for services This is invoked after the processing is done (therefore no other outputs are expected from user code) but before the postProcessing (which is were data is actually sent to their consumers. --- Framework/Core/include/Framework/CallbackService.h | 5 +++++ .../Core/include/Framework/DataProcessingContext.h | 6 ++++++ Framework/Core/include/Framework/ServiceSpec.h | 5 ++++- Framework/Core/include/Framework/StreamContext.h | 4 ++++ Framework/Core/src/ContextHelpers.h | 6 ++++++ Framework/Core/src/DataProcessingContext.cxx | 8 ++++++++ Framework/Core/src/DataProcessingDevice.cxx | 9 +++++++++ Framework/Core/src/StreamContext.cxx | 11 +++++++++++ 8 files changed, 53 insertions(+), 1 deletion(-) diff --git a/Framework/Core/include/Framework/CallbackService.h b/Framework/Core/include/Framework/CallbackService.h index 91115e92af129..6243b15795fd3 100644 --- a/Framework/Core/include/Framework/CallbackService.h +++ b/Framework/Core/include/Framework/CallbackService.h @@ -71,6 +71,9 @@ class CallbackService NewTimeslice, /// Invoked before the processing callback PreProcessing, + /// Invoked after the processing callback and before the post processing + /// callback to allow for injecting data in the output stream. + FinaliseOutputs, /// Invoked after the processing callback, PostProcessing, /// Invoked whenever an object from CCDB is deserialised via ROOT. @@ -94,6 +97,7 @@ class CallbackService using RegionInfoCallback = std::function; using NewTimesliceCallback = std::function; using PreProcessingCallback = std::function; + using FinaliseOutputsCallback = std::function; using PostProcessingCallback = std::function; using CCDBDeserializedCallback = std::function; using DomainInfoUpdatedCallback = std::function; @@ -111,6 +115,7 @@ class CallbackService RegistryPair, // RegistryPair, // RegistryPair, // + RegistryPair, // RegistryPair, // RegistryPair, // RegistryPair, // diff --git a/Framework/Core/include/Framework/DataProcessingContext.h b/Framework/Core/include/Framework/DataProcessingContext.h index 2f7308a0ce810..d71ad203b1580 100644 --- a/Framework/Core/include/Framework/DataProcessingContext.h +++ b/Framework/Core/include/Framework/DataProcessingContext.h @@ -53,6 +53,9 @@ struct DataProcessorContext { void preStartCallbacks(ServiceRegistryRef); /// Invoke callbacks to be executed before every process method invokation void preProcessingCallbacks(ProcessingContext&); + /// Invoke callbacks to be executed after the outputs have been created + /// by the processing, but before the post processing callbacks. + void finaliseOutputsCallbacks(ProcessingContext&); /// Invoke callbacks to be executed after every process method invokation void postProcessingCallbacks(ProcessingContext&); /// Invoke callbacks to be executed before every dangling check @@ -91,6 +94,9 @@ struct DataProcessorContext { mutable std::vector preProcessingHandlers; /// Callback for services to be executed after every processing. /// The callback MUST BE REENTRANT and threadsafe. + mutable std::vector finaliseOutputsHandles; + /// Callback for services to be executed after every processing. + /// The callback MUST BE REENTRANT and threadsafe. mutable std::vector postProcessingHandlers; /// Callbacks for services to be executed before every dangling check mutable std::vector preDanglingHandles; diff --git a/Framework/Core/include/Framework/ServiceSpec.h b/Framework/Core/include/Framework/ServiceSpec.h index d30280a2e2f85..910620fcd0655 100644 --- a/Framework/Core/include/Framework/ServiceSpec.h +++ b/Framework/Core/include/Framework/ServiceSpec.h @@ -146,6 +146,9 @@ struct ServiceSpec { ServiceConfigureCallback configure = nullptr; /// Callback executed before actual processing happens. ServiceProcessingCallback preProcessing = nullptr; + /// Callback executed after the processing callback is completed + /// and the user provided outputs have been created. + ServiceProcessingCallback finaliseOutputs = nullptr; /// Callback executed once actual processing happened. ServiceProcessingCallback postProcessing = nullptr; /// Callback executed before the dangling inputs loop @@ -170,7 +173,7 @@ struct ServiceSpec { ServicePreSchedule preSchedule = nullptr; ServicePostSchedule postSchedule = nullptr; - ///Callback executed after each metric is received by the driver. + /// Callback executed after each metric is received by the driver. ServiceMetricHandling metricHandling = nullptr; /// Callback executed after a given input record has been successfully diff --git a/Framework/Core/include/Framework/StreamContext.h b/Framework/Core/include/Framework/StreamContext.h index 5e4dc5f1b325c..0ab353e147276 100644 --- a/Framework/Core/include/Framework/StreamContext.h +++ b/Framework/Core/include/Framework/StreamContext.h @@ -38,6 +38,9 @@ struct StreamContext { void preStartStreamCallbacks(ServiceRegistryRef); void preProcessingCallbacks(ProcessingContext& pcx); + /// Invoke callbacks to be executed after the outputs have been created + /// by the processing, but before the post processing callbacks. + void finaliseOutputsCallbacks(ProcessingContext&); void postProcessingCallbacks(ProcessingContext& pcx); /// Invoke callbacks to be executed before every EOS user callback invokation @@ -47,6 +50,7 @@ struct StreamContext { /// Callbacks for services to be executed before every process method invokation std::vector preProcessingHandles; + std::vector finaliseOutputsHandles; /// Callbacks for services to be executed after every process method invokation std::vector postProcessingHandles; diff --git a/Framework/Core/src/ContextHelpers.h b/Framework/Core/src/ContextHelpers.h index cb7af43d5006e..12ccfcca83fe1 100644 --- a/Framework/Core/src/ContextHelpers.h +++ b/Framework/Core/src/ContextHelpers.h @@ -41,6 +41,9 @@ void ContextHelpers::bindStreamService(DataProcessorContext& dpContext, StreamCo if (spec.preProcessing) { context.preProcessingHandles.push_back(ServiceProcessingHandle{spec, spec.preProcessing, service}); } + if (spec.finaliseOutputs) { + context.finaliseOutputsHandles.push_back(ServiceProcessingHandle{spec, spec.finaliseOutputs, service}); + } if (spec.postProcessing) { context.postProcessingHandles.push_back(ServiceProcessingHandle{spec, spec.postProcessing, service}); } @@ -59,6 +62,9 @@ void ContextHelpers::bindProcessorService(DataProcessorContext& dataProcessorCon if (spec.preProcessing) { dataProcessorContext.preProcessingHandlers.push_back(ServiceProcessingHandle{spec, spec.preProcessing, service}); } + if (spec.finaliseOutputs) { + dataProcessorContext.finaliseOutputsHandles.push_back(ServiceProcessingHandle{spec, spec.finaliseOutputs, service}); + } if (spec.postProcessing) { dataProcessorContext.postProcessingHandlers.push_back(ServiceProcessingHandle{spec, spec.postProcessing, service}); } diff --git a/Framework/Core/src/DataProcessingContext.cxx b/Framework/Core/src/DataProcessingContext.cxx index 281a92134b5f6..365975c706722 100644 --- a/Framework/Core/src/DataProcessingContext.cxx +++ b/Framework/Core/src/DataProcessingContext.cxx @@ -22,6 +22,14 @@ void DataProcessorContext::preProcessingCallbacks(ProcessingContext& ctx) } } +void DataProcessorContext::finaliseOutputsCallbacks(ProcessingContext& ctx) +{ + for (auto& handle : finaliseOutputsHandles) { + LOGP(debug, "Invoking postProcessingCallback for service {}", handle.spec.name); + handle.callback(ctx, handle.service); + } +} + /// Invoke callbacks to be executed before every dangling check void DataProcessorContext::postProcessingCallbacks(ProcessingContext& ctx) { diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index e3c29035e9d21..23bdc9e75806b 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -2304,6 +2304,15 @@ bool DataProcessingDevice::tryDispatchComputation(ServiceRegistryRef ref, std::v allocator.make(OutputRef{"dpl-summary", compile_time_hash(spec.name.c_str())}, 1); } + // Extra callback which allows a service to add extra outputs. + // This is needed e.g. to ensure that injected CCDB outputs are added + // before an end of stream. + { + ref.get().call(o2::framework::ServiceRegistryRef{ref}, (int)action.op); + dpContext.finaliseOutputsCallbacks(processContext); + streamContext.finaliseOutputsCallbacks(processContext); + } + { ZoneScopedN("service post processing"); ref.get().call(o2::framework::ServiceRegistryRef{ref}, (int)action.op); diff --git a/Framework/Core/src/StreamContext.cxx b/Framework/Core/src/StreamContext.cxx index e11e658f38558..c7f28a3dbde1a 100644 --- a/Framework/Core/src/StreamContext.cxx +++ b/Framework/Core/src/StreamContext.cxx @@ -35,6 +35,17 @@ void StreamContext::preProcessingCallbacks(ProcessingContext& pcx) } } +/// Invoke callbacks to be executed after every process method invokation +void StreamContext::finaliseOutputsCallbacks(ProcessingContext& pcx) +{ + for (auto& handle : finaliseOutputsHandles) { + LOG(debug) << "Invoking finaliseOutputsCallbacks for " << handle.service; + assert(handle.service); + assert(handle.callback); + handle.callback(pcx, handle.service); + } +} + /// Invoke callbacks to be executed after every process method invokation void StreamContext::postProcessingCallbacks(ProcessingContext& pcx) { From a234955ff1b33e7c3c2862ac2f9848f6f732fd44 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 16 Oct 2023 22:12:21 +0200 Subject: [PATCH 290/324] DPL: add injected CCDB messages in finaliseOutputs This is needed to avoid a race condition where outputs are sent after the end of stream. --- Framework/Core/src/CommonServices.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Core/src/CommonServices.cxx b/Framework/Core/src/CommonServices.cxx index 81b1216c90c9c..9d577ca5b990a 100644 --- a/Framework/Core/src/CommonServices.cxx +++ b/Framework/Core/src/CommonServices.cxx @@ -399,7 +399,7 @@ o2::framework::ServiceSpec CommonServices::ccdbSupportSpec() return ServiceHandle{.hash = TypeIdHelpers::uniqueId(), .instance = nullptr, .kind = ServiceKind::Serial}; }, .configure = noConfiguration(), - .postProcessing = [](ProcessingContext& pc, void* service) { + .finaliseOutputs = [](ProcessingContext& pc, void* service) { if (!service) { return; } From f55e77652200caec0dd04dc516f95c95f9cb7f53 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 18 Oct 2023 16:45:27 +0200 Subject: [PATCH 291/324] Make sure we notify DPL about non-DPL message sending This is needed to avoid skipping CCDB callbacks on the last timeframe. --- Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx | 4 ++++ Framework/Core/include/Framework/MessageContext.h | 1 + 2 files changed, 5 insertions(+) diff --git a/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx b/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx index 9a16e6622bcbf..a75254c490c6a 100644 --- a/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx +++ b/Detectors/Raw/TFReaderDD/src/TFReaderSpec.cxx @@ -264,6 +264,10 @@ void TFReaderSpec::run(o2f::ProcessingContext& ctx) nparts += msgIt.second->Size() / 2; device->Send(*msgIt.second.get(), msgIt.first); } + // FIXME: this is to pretend we did send some messages via DPL. + // we should really migrate everything to use FairMQDeviceProxy, + // however this is a small enough hack for now. + ctx.services().get().fakeDispatch(); tNow = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); deltaSending = mTFCounter ? tNow - tLastTF : 0; LOGP(info, "Sent TF {} of size {} with {} parts, {:.4f} s elapsed from previous TF.", mTFCounter, dataSize, nparts, double(deltaSending) * 1e-6); diff --git a/Framework/Core/include/Framework/MessageContext.h b/Framework/Core/include/Framework/MessageContext.h index 6d027da1ab5a7..4f6674576e8ef 100644 --- a/Framework/Core/include/Framework/MessageContext.h +++ b/Framework/Core/include/Framework/MessageContext.h @@ -528,6 +528,7 @@ class MessageContext o2::header::DataHeader* findMessageHeader(const Output& spec); o2::header::Stack* findMessageHeaderStack(const Output& spec); int countDeviceOutputs(bool excludeDPLOrigin = false); + void fakeDispatch() { mDidDispatch = true; } o2::framework::DataProcessingHeader* findMessageDataProcessingHeader(const Output& spec); std::pair findMessageHeaders(const Output& spec); From 2fe05e46ad94d23d724bf11b5b7375f8ae25c3d7 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:34:26 +0200 Subject: [PATCH 292/324] Add protection for passing a root file as a list of files --- Common/Utils/src/FileFetcher.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Common/Utils/src/FileFetcher.cxx b/Common/Utils/src/FileFetcher.cxx index 6492383d836f7..fd7d9d2be3c32 100644 --- a/Common/Utils/src/FileFetcher.cxx +++ b/Common/Utils/src/FileFetcher.cxx @@ -88,6 +88,15 @@ void FileFetcher::processInput(const std::vector& input) if (fs::is_directory(inp)) { processDirectory(inp); } else if (mSelRegex && !std::regex_match(inp, *mSelRegex.get())) { // provided selector does not match, treat as a txt file with list + // Avoid reading a multigiB data file as a list of inputs + // bringing down the system. + std::filesystem::path p(inp); + + if (std::filesystem::file_size(p) > 10000000) { + LOGP(error, "file list {} larger than 10MB. Is this a data file?", inp); + continue; + } + std::ifstream listFile(inp); if (!listFile.good()) { LOGP(error, "file {} pretends to be a list of inputs but does not exist", inp); From c1c50501d97159524cfee659659f3b699953ab80 Mon Sep 17 00:00:00 2001 From: Francesco Mazzaschi <43742195+fmazzasc@users.noreply.github.com> Date: Thu, 19 Oct 2023 10:26:49 +0200 Subject: [PATCH 293/324] Adding cluster size to track extra (#12044) * Add ITS cluster size to the AO2D * Add TracksExtra_001 * Update readerhelper * Add cluster sizes to AB * Remove its cluster map * Please consider the following formatting changes * Add table versioning * Fix comments Co-authored-by: Jan Fiete * Fix comments (2) Co-authored-by: Jan Fiete * Set old TrackExtra as default * Fix data descriptor for trackextra * Please consider the following formatting changes * Fix test * Clean commented code * Fix comment (3) Co-authored-by: Jan Fiete * Move dyn columns to versioning namespace * Update Framework/Core/include/Framework/AnalysisDataModel.h * Add braces + unsigned shorts * Move cluster sizes to uint8_t * Swap pattern and clsizes order --------- Co-authored-by: Maximiliano Puccio Co-authored-by: ALICE Action Bot Co-authored-by: Jan Fiete --- .../ITS/include/DataFormatsITS/TrackITS.h | 28 ++++++- .../include/DataFormatsITSMFT/TrkClusRef.h | 25 +++++- .../AODProducerWorkflowSpec.h | 1 + Detectors/AOD/src/AODProducerWorkflowSpec.cxx | 3 + .../include/GlobalTracking/MatchTPCITS.h | 77 ++++++++--------- Detectors/GlobalTracking/src/MatchTPCITS.cxx | 35 ++++++-- .../tracking/include/ITStracking/TimeFrame.h | 7 ++ .../ITSMFT/ITS/tracking/src/TimeFrame.cxx | 11 +++ .../ITSMFT/ITS/workflow/src/TrackerSpec.cxx | 1 + .../include/Framework/AnalysisDataModel.h | 84 +++++++++++++++++-- Framework/Core/src/AODReaderHelpers.cxx | 6 +- Framework/Core/test/test_AnalysisTask.cxx | 2 +- 12 files changed, 224 insertions(+), 56 deletions(-) diff --git a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h index 3cef7f45a9fb1..709e8aa3ee329 100644 --- a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h +++ b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h @@ -122,13 +122,39 @@ class TrackITS : public o2::track::TrackParCov void setNextROFbit(bool toggle = true) { setUserField((getUserField() & ~kNextROF) | (-toggle & kNextROF)); } bool hasHitInNextROF() const { return getUserField() & kNextROF; } + void setClusterSize(int l, int size) + { + if (l >= 8) { + return; + } + if (size > 15) { + size = 15; + } + mClusterSizes &= ~(0xf << (l * 4)); + mClusterSizes |= (size << (l * 4)); + } + + int getClusterSize(int l) + { + if (l >= 8) { + return 0; + } + return (mClusterSizes >> (l * 4)) & 0xf; + } + + int getClusterSizes() const + { + return mClusterSizes; + } + private: o2::track::TrackParCov mParamOut; ///< parameter at largest radius ClusRefs mClusRef; ///< references on clusters float mChi2 = 0.; ///< Chi2 for this track uint32_t mPattern = 0; ///< layers pattern + unsigned int mClusterSizes = 0u; - ClassDefNV(TrackITS, 5); + ClassDefNV(TrackITS, 6); }; class TrackITSExt : public TrackITS diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TrkClusRef.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TrkClusRef.h index 164fd850fd539..7a027c2a2156c 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TrkClusRef.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TrkClusRef.h @@ -25,12 +25,35 @@ namespace itsmft // can refer to max 15 indices in the vector of total length <268435456, i.e. 17895697 tracks in worst case struct TrkClusRef : public o2::dataformats::RangeRefComp<4> { using o2::dataformats::RangeRefComp<4>::RangeRefComp; + uint32_t clsizes = 0; ///< cluster sizes for each layer uint16_t pattern = 0; ///< layers pattern GPUd() int getNClusters() const { return getEntries(); } bool hasHitOnLayer(int i) { return pattern & (0x1 << i); } - ClassDefNV(TrkClusRef, 1); + void setClusterSize(int l, int size) + { + if (l >= 8) + return; + if (size > 15) + size = 15; + clsizes &= ~(0xf << (l * 4)); + clsizes |= (size << (l * 4)); + } + + int getClusterSize(int l) + { + if (l >= 8) + return 0; + return (clsizes >> (l * 4)) & 0xf; + } + + int getClusterSizes() const + { + return clsizes; + } + + ClassDefNV(TrkClusRef, 2); }; } // namespace itsmft diff --git a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h index 10c70ad2e77eb..854b487cbe78e 100644 --- a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h +++ b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h @@ -356,6 +356,7 @@ class AODProducerWorkflowDPL : public Task struct TrackExtraInfo { float tpcInnerParam = 0.f; uint32_t flags = 0; + uint32_t itsClusterSizes = 0u; uint8_t itsClusterMap = 0; uint8_t tpcNClsFindable = 0; int8_t tpcNClsFindableMinusFound = 0; diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index 6984ed3841e63..9c2f1d13eefaf 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -2729,6 +2729,9 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo dataRequest->requestStrangeTracks(useMC); LOGF(info, "requestStrangeTracks Finish"); } + if (src[GID::ITS]) { + dataRequest->requestClusters(GIndex::getSourcesMask("ITS"), false); + } if (src[GID::TPC]) { dataRequest->requestClusters(GIndex::getSourcesMask("TPC"), false); // no need to ask for TOF clusters as they are requested with TOF tracks } diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h index 506ca2222aca2..87cb8f6b8a44e 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h @@ -89,7 +89,7 @@ namespace tpc { class TrackTPC; class VDriftCorrFact; -} +} // namespace tpc namespace gpu { @@ -127,7 +127,7 @@ struct TrackLocTPC : public o2::track::TrackParCov { float timeErr = 0.f; ///< time sigma (makes sense for constrained tracks only) int sourceID = 0; ///< TPC track origin in o2::dataformats::GlobalTrackID gid{}; // global track source ID (TPC track may be part of it) - int matchID = MinusOne; ///< entry (non if MinusOne) of its matchTPC struct in the mMatchesTPC + int matchID = MinusOne; ///< entry (non if MinusOne) of its matchTPC struct in the mMatchesTPC Constraint_t constraint{Constrained}; float getCorrectedTime(float dt) const // return time0 corrected for extra drift (to match certain Z) @@ -148,9 +148,9 @@ struct TrackLocITS : public o2::track::TrackParCov { enum : uint16_t { CloneBefore = 0x1, CloneAfter = 0x2 }; o2::math_utils::Bracketf_t tBracket; ///< bracketing time in \mus - int sourceID = 0; ///< track origin id - int roFrame = MinusOne; ///< ITS readout frame assigned to this track - int matchID = MinusOne; ///< entry (non if MinusOne) of its matchCand struct in the mMatchesITS + int sourceID = 0; ///< track origin id + int roFrame = MinusOne; ///< ITS readout frame assigned to this track + int matchID = MinusOne; ///< entry (non if MinusOne) of its matchCand struct in the mMatchesITS bool hasCloneBefore() const { return getUserField() & CloneBefore; } bool hasCloneAfter() const { return getUserField() & CloneAfter; } int getCloneShift() const { return hasCloneBefore() ? -1 : (hasCloneAfter() ? 1 : 0); } @@ -536,13 +536,13 @@ class MatchTPCITS float correctTPCTrack(o2::track::TrackParCov& trc, const TrackLocTPC& tTPC, const InteractionCandidate& cand) const; // RS FIXME will be needed for refit //================================================================ - bool mInitDone = false; ///< flag init already done - bool mFieldON = true; ///< flag for field ON/OFF - bool mCosmics = false; ///< flag cosmics mode - bool mMCTruthON = false; ///< flag availability of MC truth - float mBz = 0; ///< nominal Bz - int mTFCount = 0; ///< internal TF counter for debugger - int mNThreads = 1; ///< number of OMP threads + bool mInitDone = false; ///< flag init already done + bool mFieldON = true; ///< flag for field ON/OFF + bool mCosmics = false; ///< flag cosmics mode + bool mMCTruthON = false; ///< flag availability of MC truth + float mBz = 0; ///< nominal Bz + int mTFCount = 0; ///< internal TF counter for debugger + int mNThreads = 1; ///< number of OMP threads o2::InteractionRecord mStartIR{0, 0}; ///< IR corresponding to the start of the TF ///========== Parameters to be set externally, e.g. from CCDB ==================== @@ -566,27 +566,27 @@ class MatchTPCITS ///< assigned time0 and its track Z position (converted from mTPCTimeEdgeZSafeMargin) float mTPCTimeEdgeTSafeMargin = 0.f; float mTPCExtConstrainedNSigmaInv = 0.f; // inverse for NSigmas for TPC time-interval from external constraint time sigma - int mITSROFrameLengthInBC = 0; ///< ITS RO frame in BC (for ITS cont. mode only) - float mITSROFrameLengthMUS = -1.; ///< ITS RO frame in \mus - float mITSTimeResMUS = -1.; ///< nominal ITS time resolution derived from ROF - float mITSROFrameLengthMUSInv = -1.; ///< ITS RO frame in \mus inverse - int mITSTimeBiasInBC = 0; ///< ITS RO frame shift in BCs, i.e. t_i = (I_ROF*mITSROFrameLengthInBC + mITSTimeBiasInBC)*BCLength_MUS - float mITSTimeBiasMUS = 0.; ///< ITS RO frame shift in \mus, i.e. t_i = (I_ROF*mITSROFrameLengthInBC)*BCLength_MUS + mITSTimeBiasMUS - float mTPCVDrift = -1.; ///< TPC drift speed in cm/microseconds - float mTPCVDriftInv = -1.; ///< inverse TPC nominal drift speed in cm/microseconds - float mTPCDriftTimeOffset = 0; ///< drift time offset in mus - float mTPCTBinMUS = 0.; ///< TPC time bin duration in microseconds - float mTPCTBinNS = 0.; ///< TPC time bin duration in ns - float mTPCTBinMUSInv = 0.; ///< inverse TPC time bin duration in microseconds - float mZ2TPCBin = 0.; ///< conversion coeff from Z to TPC time-bin - float mTPCBin2Z = 0.; ///< conversion coeff from TPC time-bin to Z - float mNTPCBinsFullDrift = 0.; ///< max time bin for full drift - float mTPCZMax = 0.; ///< max drift length - float mTPCmeanX0Inv = 1. / 31850.; ///< TPC gas 1/X0 + int mITSROFrameLengthInBC = 0; ///< ITS RO frame in BC (for ITS cont. mode only) + float mITSROFrameLengthMUS = -1.; ///< ITS RO frame in \mus + float mITSTimeResMUS = -1.; ///< nominal ITS time resolution derived from ROF + float mITSROFrameLengthMUSInv = -1.; ///< ITS RO frame in \mus inverse + int mITSTimeBiasInBC = 0; ///< ITS RO frame shift in BCs, i.e. t_i = (I_ROF*mITSROFrameLengthInBC + mITSTimeBiasInBC)*BCLength_MUS + float mITSTimeBiasMUS = 0.; ///< ITS RO frame shift in \mus, i.e. t_i = (I_ROF*mITSROFrameLengthInBC)*BCLength_MUS + mITSTimeBiasMUS + float mTPCVDrift = -1.; ///< TPC drift speed in cm/microseconds + float mTPCVDriftInv = -1.; ///< inverse TPC nominal drift speed in cm/microseconds + float mTPCDriftTimeOffset = 0; ///< drift time offset in mus + float mTPCTBinMUS = 0.; ///< TPC time bin duration in microseconds + float mTPCTBinNS = 0.; ///< TPC time bin duration in ns + float mTPCTBinMUSInv = 0.; ///< inverse TPC time bin duration in microseconds + float mZ2TPCBin = 0.; ///< conversion coeff from Z to TPC time-bin + float mTPCBin2Z = 0.; ///< conversion coeff from TPC time-bin to Z + float mNTPCBinsFullDrift = 0.; ///< max time bin for full drift + float mTPCZMax = 0.; ///< max drift length + float mTPCmeanX0Inv = 1. / 31850.; ///< TPC gas 1/X0 float mMinTPCTrackPtInv = 999.; ///< cutoff on TPC track inverse pT float mMinITSTrackPtInv = 999.; ///< cutoff on ITS track inverse pT - bool mVDriftCalibOn = false; ///< flag to produce VDrift calibration data + bool mVDriftCalibOn = false; ///< flag to produce VDrift calibration data o2::tpc::VDriftCorrFact mTPCDrift{}; o2::gpu::CorrectionMapsHelper* mTPCCorrMapsHelper = nullptr; @@ -601,12 +601,14 @@ class MatchTPCITS const o2::globaltracking::RecoContainer* mRecoCont = nullptr; ///>>>------ these are input arrays which should not be modified by the matching code // since this info is provided by external device - gsl::span mTPCTracksArray; ///< input TPC tracks span - gsl::span mTPCTrackClusIdx; ///< input TPC track cluster indices span - gsl::span mITSTrackROFRec; ///< input ITS tracks ROFRecord span - gsl::span mITSTracksArray; ///< input ITS tracks span - gsl::span mITSTrackClusIdx; ///< input ITS track cluster indices span - std::vector mITSClustersArray; ///< ITS clusters created in loadInput + gsl::span mTPCTracksArray; ///< input TPC tracks span + gsl::span mTPCTrackClusIdx; ///< input TPC track cluster indices span + gsl::span mITSTrackROFRec; ///< input ITS tracks ROFRecord span + gsl::span mITSTracksArray; ///< input ITS tracks span + gsl::span mITSTrackClusIdx; ///< input ITS track cluster indices span + std::vector mITSClustersArray; ///< ITS clusters created in loadInput + std::vector mITSClusterSizes; ///< ITS cluster sizes created in loadInput + gsl::span mITSClusterROFRec; ///< input ITS clusters ROFRecord span gsl::span mFITInfo; ///< optional input FIT info span @@ -624,6 +626,7 @@ class MatchTPCITS size_t mNMatches = 0; size_t mNCalibPrelim = 0; size_t mNMatchesControl = 0; + size_t mNABRefsClus = 0; float mAB2MatchGuess = 0.2; // heuristic guess about fraction of AB matches in total matches std::vector mInteractions; ///< possible interaction times @@ -693,7 +696,6 @@ class MatchTPCITS static constexpr std::string_view TimerName[] = {"Total", "PrepareITS", "PrepareTPC", "DoMatching", "SelectBest", "Refit", "ABSeeds", "ABMatching", "ABWinners", "ABRefit", "IO", "Debug"}; TStopwatch mTimer[NStopWatches]; - }; //______________________________________________ @@ -714,7 +716,6 @@ inline bool MatchTPCITS::isDisabledITS(const TrackLocITS& t) const { return t.ma //______________________________________________ inline bool MatchTPCITS::isDisabledTPC(const TrackLocTPC& t) const { return t.matchID < 0; } - } // namespace globaltracking } // namespace o2 diff --git a/Detectors/GlobalTracking/src/MatchTPCITS.cxx b/Detectors/GlobalTracking/src/MatchTPCITS.cxx index cff36caf2a249..3f22b9da176f6 100644 --- a/Detectors/GlobalTracking/src/MatchTPCITS.cxx +++ b/Detectors/GlobalTracking/src/MatchTPCITS.cxx @@ -155,6 +155,7 @@ void MatchTPCITS::clear() mITSROFTimes.clear(); mITSTrackROFContMapping.clear(); mITSClustersArray.clear(); + mITSClusterSizes.clear(); mTPCABSeeds.clear(); mTPCABIndexCache.clear(); mABWinnersIDs.clear(); @@ -309,7 +310,7 @@ bool MatchTPCITS::validateTPCMatch(int iTPC) if (rcITS.nextRecID == Validated) { return false; } - if (rcITS.partnerID == iTPC) { // is best matching TPC track for this ITS track actually iTPC? + if (rcITS.partnerID == iTPC) { // is best matching TPC track for this ITS track actually iTPC? int cloneID = tITS.getCloneShift(); // check if there is a clone of tITS while (cloneID) { cloneID += rcTPC.partnerID; @@ -580,6 +581,27 @@ bool MatchTPCITS::prepareITSData() auto pattIt = patterns.begin(); mITSClustersArray.reserve(clusITS.size()); o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict); + + // ITS clusters sizes + mITSClusterSizes.reserve(clusITS.size()); + auto pattIt2 = patterns.begin(); + for (auto& clus : clusITS) { + auto pattID = clus.getPatternID(); + unsigned int npix; + if (pattID == o2::itsmft::CompCluster::InvalidPatternID || mITSDict->isGroup(pattID)) { + o2::itsmft::ClusterPattern patt; + patt.acquirePattern(pattIt2); + npix = patt.getNPixels(); + } else { + npix = mITSDict->getNpixels(pattID); + } + if (npix < 255) { + mITSClusterSizes.push_back(npix); + } else { + mITSClusterSizes.push_back(255); + } + } + if (mMCTruthON) { mITSClsLabels = inp.mcITSClusters.get(); } @@ -1295,21 +1317,21 @@ bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS, pmr::vector mITSTimeResMUS && tTPC.constraint != TrackLocTPC::Constrained) { timeErr = mITSTimeResMUS; // chose smallest error deltaT = tTPC.constraint == TrackLocTPC::ASide ? tITS.tBracket.mean() - tTPC.time0 : tTPC.time0 - tITS.tBracket.mean(); } timeErr += mParams->globalTimeExtraErrorMUS; - float timeC = tTPC.getCorrectedTime(deltaT) + mParams->globalTimeBiasMUS; /// precise time estimate, optionally corrected for bias - if (timeC < 0) { // RS TODO similar check is needed for other edge of TF + float timeC = tTPC.getCorrectedTime(deltaT) + mParams->globalTimeBiasMUS; /// precise time estimate, optionally corrected for bias + if (timeC < 0) { // RS TODO similar check is needed for other edge of TF if (timeC + std::min(timeErr, mParams->tfEdgeTimeToleranceMUS * mTPCTBinMUSInv) < 0) { matchedTracks.pop_back(); // destroy failed track return false; @@ -1845,6 +1867,7 @@ void MatchTPCITS::refitABWinners(pmr::vector& matc ABTrackletClusterIDs.push_back(winL.clID); ncl++; clref.pattern |= 0x1 << winL.layerID; + clref.setClusterSize(winL.layerID, mITSClusterSizes[winL.clID]); if (mMCTruthON) { accountClusterLabel(winL.clID); } diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h index da35b1714978a..3b10e1d76f18c 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h @@ -129,6 +129,7 @@ class TimeFrame const gsl::span getClusterLabels(int layerId, const Cluster& cl) const; const gsl::span getClusterLabels(int layerId, const int clId) const; int getClusterExternalIndex(int layerId, const int clId) const; + int getClusterSize(int clusterId); std::vector& getTrackletsLabel(int layer) { return mTrackletLabels[layer]; } std::vector& getCellsLabel(int layer) { return mCellLabels[layer]; } @@ -244,6 +245,7 @@ class TimeFrame std::vector mMSangles; std::vector mPhiCuts; std::vector mPositionResolution; + std::vector mClusterSize; std::vector mMultiplicityCutMask; std::vector> mPValphaX; /// PV x and alpha for track propagation std::vector> mUnsortedClusters; @@ -424,6 +426,11 @@ inline const gsl::span TimeFrame::getClusterLabels(int layerI return mClusterLabels->getLabels(mClusterExternalIndices[layerId][clId]); } +inline int TimeFrame::getClusterSize(int clusterId) +{ + return mClusterSize[clusterId]; +} + inline int TimeFrame::getClusterExternalIndex(int layerId, const int clId) const { return mClusterExternalIndices[layerId][clId]; diff --git a/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx b/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx index 24349e30b8017..11da548c377b0 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx @@ -175,6 +175,8 @@ int TimeFrame::loadROFrameData(gsl::span rofs, geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G)); mNrof = 0; + mClusterSize.clear(); + mClusterSize.reserve(clusters.size()); for (auto& rof : rofs) { for (int clusterId{rof.getFirstEntry()}; clusterId < rof.getFirstEntry() + rof.getNEntries(); ++clusterId) { auto& c = clusters[clusterId]; @@ -184,18 +186,27 @@ int TimeFrame::loadROFrameData(gsl::span rofs, auto pattID = c.getPatternID(); o2::math_utils::Point3D locXYZ; float sigmaY2 = DefClusError2Row, sigmaZ2 = DefClusError2Col, sigmaYZ = 0; // Dummy COG errors (about half pixel size) + unsigned int clusterSize{0}; if (pattID != itsmft::CompCluster::InvalidPatternID) { sigmaY2 = dict->getErr2X(pattID); sigmaZ2 = dict->getErr2Z(pattID); if (!dict->isGroup(pattID)) { locXYZ = dict->getClusterCoordinates(c); + clusterSize = dict->getNpixels(pattID); } else { o2::itsmft::ClusterPattern patt(pattIt); locXYZ = dict->getClusterCoordinates(c, patt); + clusterSize = patt.getNPixels(); } } else { o2::itsmft::ClusterPattern patt(pattIt); locXYZ = dict->getClusterCoordinates(c, patt, false); + clusterSize = patt.getNPixels(); + } + if (clusterSize < 255) { + mClusterSize.push_back(clusterSize); + } else { + mClusterSize.push_back(255); } auto sensorID = c.getSensorID(); // Inverse transformation to the local --> tracking diff --git a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx index b9831462b0a13..91542a37ae2eb 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx @@ -296,6 +296,7 @@ void TrackerDPL::run(ProcessingContext& pc) for (int ic = TrackITSExt::MaxClusters; ic--;) { // track internally keeps in->out cluster indices, but we want to store the references as out->in!!! auto clid = trc.getClusterIndex(ic); if (clid >= 0) { + trc.setClusterSize(ic, mTimeFrame->getClusterSize(clid)); allClusIdx.push_back(clid); nclf++; } diff --git a/Framework/Core/include/Framework/AnalysisDataModel.h b/Framework/Core/include/Framework/AnalysisDataModel.h index e409dba7db9da..5f8f7fef5f506 100644 --- a/Framework/Core/include/Framework/AnalysisDataModel.h +++ b/Framework/Core/include/Framework/AnalysisDataModel.h @@ -221,7 +221,8 @@ DECLARE_SOA_EXPRESSION_COLUMN(C1Pt21Pt2, c1Pt21Pt2, float, //! // TRACKEXTRA TABLE definition DECLARE_SOA_COLUMN(TPCInnerParam, tpcInnerParam, float); //! Momentum at inner wall of the TPC DECLARE_SOA_COLUMN(Flags, flags, uint32_t); //! Track flags. Run 2: see TrackFlagsRun2Enum | Run 3: see TrackFlags -DECLARE_SOA_COLUMN(ITSClusterMap, itsClusterMap, uint8_t); //! ITS cluster map, one bit per a layer, starting from the innermost +DECLARE_SOA_COLUMN(ITSClusterSizes, itsClusterSizes, uint32_t); //! Clusters sizes, four bits per a layer, starting from the innermost +DECLARE_SOA_COLUMN(ITSClusterMap, itsClusterMap, uint8_t); //! Old cluster ITS cluster map, kept for version 0 compatibility DECLARE_SOA_COLUMN(TPCNClsFindable, tpcNClsFindable, uint8_t); //! Findable TPC clusters for this track geometry DECLARE_SOA_COLUMN(TPCNClsFindableMinusFound, tpcNClsFindableMinusFound, int8_t); //! TPC Clusters: Findable - Found DECLARE_SOA_COLUMN(TPCNClsFindableMinusCrossedRows, tpcNClsFindableMinusCrossedRows, int8_t); //! TPC Clusters: Findable - crossed rows @@ -239,11 +240,53 @@ DECLARE_SOA_COLUMN(TrackEtaEMCAL, trackEtaEmcal, float); DECLARE_SOA_COLUMN(TrackPhiEMCAL, trackPhiEmcal, float); //! DECLARE_SOA_COLUMN(TrackTime, trackTime, float); //! Estimated time of the track in ns wrt collision().bc() or ambiguoustrack.bcSlice()[0] DECLARE_SOA_COLUMN(TrackTimeRes, trackTimeRes, float); //! Resolution of the track time in ns (see TrackFlags::TrackTimeResIsRange) -DECLARE_SOA_EXPRESSION_COLUMN(DetectorMap, detectorMap, uint8_t, //! Detector map: see enum DetectorMapEnum + +// expression columns changing between versions have to be declared in different namespaces + +DECLARE_SOA_EXPRESSION_COLUMN(DetectorMap, detectorMap, uint8_t, //! Detector map: see enum DetectorMapEnum ifnode(aod::track::itsClusterMap > (uint8_t)0, static_cast(o2::aod::track::ITS), (uint8_t)0x0) | ifnode(aod::track::tpcNClsFindable > (uint8_t)0, static_cast(o2::aod::track::TPC), (uint8_t)0x0) | ifnode(aod::track::trdPattern > (uint8_t)0, static_cast(o2::aod::track::TRD), (uint8_t)0x0) | ifnode((aod::track::tofChi2 >= 0.f) && (aod::track::tofExpMom > 0.f), static_cast(o2::aod::track::TOF), (uint8_t)0x0)); + +namespace v001 +{ +DECLARE_SOA_EXPRESSION_COLUMN(DetectorMap, detectorMap, uint8_t, //! Detector map version 1, see enum DetectorMapEnum + ifnode(aod::track::itsClusterSizes > (uint32_t)0, static_cast(o2::aod::track::ITS), (uint8_t)0x0) | + ifnode(aod::track::tpcNClsFindable > (uint8_t)0, static_cast(o2::aod::track::TPC), (uint8_t)0x0) | + ifnode(aod::track::trdPattern > (uint8_t)0, static_cast(o2::aod::track::TRD), (uint8_t)0x0) | + ifnode((aod::track::tofChi2 >= 0.f) && (aod::track::tofExpMom > 0.f), static_cast(o2::aod::track::TOF), (uint8_t)0x0)); +DECLARE_SOA_DYNAMIC_COLUMN(ITSClusterMap, itsClusterMap, //! ITS cluster map, one bit per a layer, starting from the innermost + [](uint32_t itsClusterSizes) -> uint8_t { + uint8_t clmap = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + if ((itsClusterSizes >> (layer * 4)) & 0xf) { + clmap |= (1 << layer); + } + } + return clmap; + }); +DECLARE_SOA_DYNAMIC_COLUMN(ITSNCls, itsNCls, //! Number of ITS clusters + [](uint8_t itsClusterSizes) -> uint8_t { + uint8_t itsNcls = 0; + for (int layer = 0; layer < 7; layer++) { + if ((itsClusterSizes >> (layer * 4)) & 0xf) + itsNcls++; + } + return itsNcls; + }); +DECLARE_SOA_DYNAMIC_COLUMN(ITSNClsInnerBarrel, itsNClsInnerBarrel, //! Number of ITS clusters in the Inner Barrel + [](uint8_t itsClusterSizes) -> uint8_t { + uint8_t itsNclsInnerBarrel = 0; + for (int layer = 0; layer < 3; layer++) { + if ((itsClusterSizes >> (layer * 4)) & 0xf) + itsNclsInnerBarrel++; + } + return itsNclsInnerBarrel; + }); + +} // namespace v001 + DECLARE_SOA_DYNAMIC_COLUMN(HasITS, hasITS, //! Flag to check if track has a ITS match [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::ITS; }); DECLARE_SOA_DYNAMIC_COLUMN(HasTPC, hasTPC, //! Flag to check if track has a TPC match @@ -280,7 +323,6 @@ DECLARE_SOA_DYNAMIC_COLUMN(ITSNClsInnerBarrel, itsNClsInnerBarrel, //! Number of } return itsNclsInnerBarrel; }); - DECLARE_SOA_DYNAMIC_COLUMN(TPCFoundOverFindableCls, tpcFoundOverFindableCls, //! Ratio of found over findable clusters [](uint8_t tpcNClsFindable, int8_t tpcNClsFindableMinusFound) -> float { int16_t tpcNClsFound = (int16_t)tpcNClsFindable - tpcNClsFindableMinusFound; @@ -390,7 +432,7 @@ DECLARE_SOA_EXTENDED_TABLE(TracksCovIU, StoredTracksCovIU, "TRACKCOV_IU", //! Tr aod::track::C1PtTgl, aod::track::C1Pt21Pt2); -DECLARE_SOA_TABLE_FULL(StoredTracksExtra, "TracksExtra", "AOD", "TRACKEXTRA", //! On disk version of TracksExtra +DECLARE_SOA_TABLE_FULL(StoredTracksExtra_000, "TracksExtra", "AOD", "TRACKEXTRA", //! On disk version of TracksExtra, version 0 track::TPCInnerParam, track::Flags, track::ITSClusterMap, track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, track::TPCNClsShared, track::TRDPattern, track::ITSChi2NCl, @@ -408,8 +450,31 @@ DECLARE_SOA_TABLE_FULL(StoredTracksExtra, "TracksExtra", "AOD", "TRACKEXTRA", // track::TPCFractionSharedCls, track::TrackEtaEMCAL, track::TrackPhiEMCAL, track::TrackTime, track::TrackTimeRes); -DECLARE_SOA_EXTENDED_TABLE(TracksExtra, StoredTracksExtra, "TRACKEXTRA", //! Additional track information (clusters, PID, etc.) +DECLARE_SOA_TABLE_FULL_VERSIONED(StoredTracksExtra_001, "TracksExtra", "AOD", "TRACKEXTRA", 1, // On disk version of TracksExtra, version 1 + track::TPCInnerParam, track::Flags, track::ITSClusterSizes, + track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, + track::TPCNClsShared, track::TRDPattern, track::ITSChi2NCl, + track::TPCChi2NCl, track::TRDChi2, track::TOFChi2, + track::TPCSignal, track::TRDSignal, track::Length, track::TOFExpMom, + track::PIDForTracking, + track::IsPVContributor, + track::HasITS, track::HasTPC, + track::HasTRD, track::HasTOF, + track::TPCNClsFound, + track::TPCNClsCrossedRows, + track::v001::ITSClusterMap, track::v001::ITSNCls, track::v001::ITSNClsInnerBarrel, + track::TPCCrossedRowsOverFindableCls, + track::TPCFoundOverFindableCls, + track::TPCFractionSharedCls, + track::TrackEtaEMCAL, track::TrackPhiEMCAL, track::TrackTime, track::TrackTimeRes); + +DECLARE_SOA_EXTENDED_TABLE(TracksExtra_000, StoredTracksExtra_000, "TRACKEXTRA", //! Additional track information (clusters, PID, etc.) track::DetectorMap); +DECLARE_SOA_EXTENDED_TABLE(TracksExtra_001, StoredTracksExtra_001, "TRACKEXTRA", //! Additional track information (clusters, PID, etc.) + track::v001::DetectorMap); + +using StoredTracksExtra = StoredTracksExtra_000; +using TracksExtra = TracksExtra_000; using Track = Tracks::iterator; using TrackIU = TracksIU::iterator; @@ -1298,7 +1363,7 @@ using Run2BCInfo = Run2BCInfos::iterator; // ---- MC tables ---- namespace mccollision { -DECLARE_SOA_INDEX_COLUMN(BC, bc); //! BC index +DECLARE_SOA_INDEX_COLUMN(BC, bc); //! BC index DECLARE_SOA_COLUMN(GeneratorsID, generatorsID, short); //! disentangled generator IDs should be accessed from dynamic columns using getGenId, getCocktailId and getSourceId DECLARE_SOA_COLUMN(PosX, posX, float); //! X vertex position in cm DECLARE_SOA_COLUMN(PosY, posY, float); //! Y vertex position in cm @@ -1437,8 +1502,11 @@ namespace soa DECLARE_EQUIVALENT_FOR_INDEX(aod::Collisions_000, aod::Collisions_001); DECLARE_EQUIVALENT_FOR_INDEX(aod::StoredMcParticles_000, aod::StoredMcParticles_001); DECLARE_EQUIVALENT_FOR_INDEX(aod::StoredTracks, aod::StoredTracksIU); -DECLARE_EQUIVALENT_FOR_INDEX(aod::StoredTracks, aod::StoredTracksExtra); -DECLARE_EQUIVALENT_FOR_INDEX(aod::StoredTracksIU, aod::StoredTracksExtra); +DECLARE_EQUIVALENT_FOR_INDEX(aod::StoredTracks, aod::StoredTracksExtra_000); +DECLARE_EQUIVALENT_FOR_INDEX(aod::StoredTracksIU, aod::StoredTracksExtra_000); +DECLARE_EQUIVALENT_FOR_INDEX(aod::StoredTracks, aod::StoredTracksExtra_001); +DECLARE_EQUIVALENT_FOR_INDEX(aod::StoredTracksIU, aod::StoredTracksExtra_001); +DECLARE_EQUIVALENT_FOR_INDEX(aod::StoredTracksExtra_000, aod::StoredTracksExtra_001); DECLARE_EQUIVALENT_FOR_INDEX(aod::HMPID_000, aod::HMPID_001); } // namespace soa diff --git a/Framework/Core/src/AODReaderHelpers.cxx b/Framework/Core/src/AODReaderHelpers.cxx index 28b1c65f7def2..5f65f42e13427 100644 --- a/Framework/Core/src/AODReaderHelpers.cxx +++ b/Framework/Core/src/AODReaderHelpers.cxx @@ -176,7 +176,11 @@ AlgorithmSpec AODReaderHelpers::aodSpawnerCallback(std::vector& reque } else if (description == header::DataDescription{"TRACKCOV_IU"}) { outputs.adopt(Output{origin, description, version}, maker(o2::aod::TracksCovIUExtensionMetadata{})); } else if (description == header::DataDescription{"TRACKEXTRA"}) { - outputs.adopt(Output{origin, description, version}, maker(o2::aod::TracksExtraExtensionMetadata{})); + if (version == 0U) { + outputs.adopt(Output{origin, description, version}, maker(o2::aod::TracksExtra_000ExtensionMetadata{})); + } else if (version == 1U) { + outputs.adopt(Output{origin, description, version}, maker(o2::aod::TracksExtra_001ExtensionMetadata{})); + } } else if (description == header::DataDescription{"MFTTRACK"}) { outputs.adopt(Output{origin, description, version}, maker(o2::aod::MFTTracksExtensionMetadata{})); } else if (description == header::DataDescription{"FWDTRACK"}) { diff --git a/Framework/Core/test/test_AnalysisTask.cxx b/Framework/Core/test/test_AnalysisTask.cxx index b07c6a9afa0d4..30e58735257ed 100644 --- a/Framework/Core/test/test_AnalysisTask.cxx +++ b/Framework/Core/test/test_AnalysisTask.cxx @@ -164,7 +164,7 @@ TEST_CASE("AdaptorCompilation") REQUIRE(task2.inputs.size() == 10); REQUIRE(task2.inputs[1].binding == "TracksExtension"); REQUIRE(task2.inputs[2].binding == "Tracks"); - REQUIRE(task2.inputs[3].binding == "TracksExtraExtension"); + REQUIRE(task2.inputs[3].binding == "TracksExtra_000Extension"); REQUIRE(task2.inputs[4].binding == "TracksExtra"); REQUIRE(task2.inputs[5].binding == "TracksCovExtension"); REQUIRE(task2.inputs[6].binding == "TracksCov"); From 705005bc010ba9fb05c4e338d6a309ec7c73272c Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Thu, 19 Oct 2023 12:00:14 +0200 Subject: [PATCH 294/324] Remove obsolete TRD compressor files (#12102) --- .../TRD/reconstruction/src/CruCompressor.cxx | 102 ---------- .../reconstruction/src/CruCompressorTask.cxx | 181 ------------------ 2 files changed, 283 deletions(-) delete mode 100644 Detectors/TRD/reconstruction/src/CruCompressor.cxx delete mode 100644 Detectors/TRD/reconstruction/src/CruCompressorTask.cxx diff --git a/Detectors/TRD/reconstruction/src/CruCompressor.cxx b/Detectors/TRD/reconstruction/src/CruCompressor.cxx deleted file mode 100644 index 85fd3baceb8f4..0000000000000 --- a/Detectors/TRD/reconstruction/src/CruCompressor.cxx +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file crucompressor.cxx -/// @author Sean Murray -/// @brief Basic DPL workflow for TRD CRU output(raw) to tracklet/digit data. -/// There may or may not be some compression in this at some point. - -#include "TRDReconstruction/CruCompressorTask.h" -#include "Framework/WorkflowSpec.h" -#include "Framework/ConfigParamSpec.h" -#include "Framework/ConcreteDataMatcher.h" -#include "Framework/Logger.h" -#include "DetectorsRaw/RDHUtils.h" - -using namespace o2::framework; - -// add workflow options, note that customization needs to be declared before -// including Framework/runDataProcessing -void customize(std::vector& workflowOptions) -{ - auto config = ConfigParamSpec{"trd-crucompressor-config", VariantType::String, "A:TRD/RAWDATA", {"TRD raw data config"}}; - auto outputDesc = ConfigParamSpec{"trd-crucompressor-output-desc", VariantType::String, "TRDTLT", {"Output specs description string"}}; - auto verbosity = ConfigParamSpec{"trd-crucompressor-verbose", VariantType::Bool, false, {"Enable verbose compressor"}}; - auto verboseheaders = ConfigParamSpec{"trd-crucompressor-hedaerverbose", VariantType::Bool, false, {"Enable header verbose compressor"}}; - auto verbosedata = ConfigParamSpec{"trd-crucompressor-dataverbose", VariantType::Bool, false, {"Enable data verbose compressor"}}; - - auto digithcheader = ConfigParamSpec{"trd-crucompressor-digitheader", VariantType::Bool, true, {"using digit half chamber headers"}}; - auto tracklethcheader = ConfigParamSpec{"trd-crucompressor-tracklethcheader", VariantType::Bool, true, {"using tracklet half chamber headers"}}; - auto trackletformat = ConfigParamSpec{"trd-crucompressor-trackletformat", VariantType::Int, 0, {"0: no pid scale factor, 1: pid scale factor"}}; - auto digitformat = ConfigParamSpec{"trd-crucompressor-digitformat", VariantType::Int, 1, {"0: zero supressed digits, 1: non zero suppressed digits "}}; - - workflowOptions.push_back(config); - workflowOptions.push_back(outputDesc); - workflowOptions.push_back(verbosity); - workflowOptions.push_back(verboseheaders); - workflowOptions.push_back(verbosedata); - workflowOptions.push_back(digithcheader); - workflowOptions.push_back(tracklethcheader); - workflowOptions.push_back(trackletformat); - workflowOptions.push_back(digitformat); -} - -#include "Framework/runDataProcessing.h" // the main driver - -/// This function hooks up the the workflow specifications into the DPL driver. -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - - auto config = cfgc.options().get("trd-crucompressor-config"); - auto verbosity = cfgc.options().get("trd-crucompressor-verbose"); - std::vector outputs; - outputs.emplace_back(OutputSpec(ConcreteDataTypeMatcher{"TRD", "CDATA"})); - - AlgorithmSpec algoSpec; - algoSpec = AlgorithmSpec{adaptFromTask()}; - - WorkflowSpec workflow; - - /* - * This is originaly replicated from TOF - We define at run time the number of devices to be attached - to the workflow and the input matching string of the device. - This is is done with a configuration string like the following - one, where the input matching for each device is provide in - comma-separated strings. For instance - A:TRD/RAWDATA/785;B:TRF/RAWDATA/2560,C:TRD/RAWDATA/1280;D:TRD/RAWDATA/1536 - - will lead to a workflow with 2 devices which will input match - - trd-crucompressor-0 --> A:TRD/RAWDATA/768;B:TRD/RAWDATA/1024 - trd-crucompressor-1 --> C:TRD/RAWDATA/1280;D:TRD/RAWDATA/1536 - The number after the RAWDATA is the FeeID in decimal - */ - - std::stringstream ssconfig(config); - std::string iconfig; - int idevice = 0; - LOG(info) << " config string is : " << config; - LOG(info) << "for now ignoring the multiple processors, something going wrong"; - while (getline(ssconfig, iconfig, ',')) { // for now we will keep the possibilty to have a device per half cru/feeid i.e. 6 per flp - // this is probably never going to be used but would to nice to know hence here. - workflow.emplace_back(DataProcessorSpec{ - std::string("trd-crucompressor-") + std::to_string(idevice), - select(iconfig.c_str()), - outputs, - algoSpec, - Options{ - {"trd-crucompressor-verbose", VariantType::Bool, false, {"verbose flag"}}}}); - idevice++; - } - - return workflow; -} diff --git a/Detectors/TRD/reconstruction/src/CruCompressorTask.cxx b/Detectors/TRD/reconstruction/src/CruCompressorTask.cxx deleted file mode 100644 index 89a3ba421ac96..0000000000000 --- a/Detectors/TRD/reconstruction/src/CruCompressorTask.cxx +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file CruCompressorTask.cxx -/// @author Sean Murray -/// @brief TRD cru output to tracklet task - -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/RawDeviceService.h" -#include "Framework/DeviceSpec.h" -#include "Framework/DataSpecUtils.h" -#include "Headers/RDHAny.h" - -#include "DataFormatsTRD/Constants.h" -#include "DataFormatsTRD/CompressedHeader.h" - -#include "TRDReconstruction/CruCompressorTask.h" -#include "TRDReconstruction/CruRawReader.h" - -#include -#include -#include - -using namespace o2::framework; - -namespace o2 -{ -namespace trd -{ - -void CruCompressorTask::init(InitContext& ic) -{ - LOG(info) << "FLP Compressore Task init"; -} - -uint64_t CruCompressorTask::buildEventOutput() -{ - //mReader holds the vectors of tracklets and digits. - // tracklets are 64 bit - // digits are DigitMCMHeader and DigitMCMData - - uint64_t currentpos = 0; - uint64_t trailer = 0xeeeeeeeeeeeeeeeeLL; - //first we write a start rdh block - CompressedRawHeader* trackletheader = (CompressedRawHeader*)&mOutBuffer[0]; - trackletheader->format = 1; - trackletheader->eventtime = 99; - currentpos = 1; - //write the - std::vector ir; - std::vector tracklets; - std::vector digits; - trackletheader->bc = ir[0].getBCData().bc; - trackletheader->orbit = ir[0].getBCData().orbit; - trackletheader->padding = 0xeeee; - trackletheader->size = mReader.sumTrackletsFound() * 8; // to get to bytes. TODO compare to getTrackletsFound - /* - for (auto tracklet : mReader.getTracklets(ir[0].getBCData())) { - //convert tracklet to 64 bit and add to blob - mOutBuffer[currentpos++] = tracklet.getTrackletWord(); - } - */ - CompressedRawTrackletDigitSeperator* tracklettrailer = (CompressedRawTrackletDigitSeperator*)&mOutBuffer[currentpos]; - tracklettrailer->word = trailer; - currentpos++; - CompressedRawHeader* digitheader = (CompressedRawHeader*)&mOutBuffer[currentpos]; - currentpos++; - digitheader->format = 2; - digitheader->eventtime = 99; - - /* - for (auto digit : mReader.getDigits(ir[0].getBCData())) { - uint64_t* word; - word = &mOutBuffer[currentpos]; - DigitMCMHeader mcmheader; - mcmheader.eventcount = 1; - mcmheader.mcm = digit.getMCM(); - mcmheader.rob = digit.getROB(); - mcmheader.yearflag = 1; - mcmheader.eventcount = 1; - mcmheader.res = 0xc; // formst is reservedto be 1100 binary - //unpack the digit. - mcmheader.word = (*word) >> 32; - currentpos++; - } - */ - CompressedRawTrackletDigitSeperator* digittrailer = (CompressedRawTrackletDigitSeperator*)&mOutBuffer[currentpos]; - digittrailer->word = trailer; - currentpos++; - //as far as I can tell this is almost always going to be blank. - CompressedRawHeader* configheader = (CompressedRawHeader*)&mOutBuffer[currentpos]; - currentpos++; - configheader->size = 2; - configheader->format = 3; - configheader->eventtime = 99; - CompressedRawTrackletDigitSeperator* configtrailer = (CompressedRawTrackletDigitSeperator*)&mOutBuffer[currentpos]; - configtrailer->word = trailer; - //finally we write a stop rdh block - - return currentpos; -} - -void CruCompressorTask::run(ProcessingContext& pc) -{ - LOG(info) << "TRD Compression Task run method"; - - auto device = pc.services().get().device(); - auto outputRoutes = pc.services().get().spec().outputs; - auto fairMQChannel = outputRoutes.at(0).channel; - int inputcount = 0; - /* loop over inputs routes */ - for (auto iit = pc.inputs().begin(), iend = pc.inputs().end(); iit != iend; ++iit) { - if (!iit.isValid()) { - continue; - } - //LOG(info) << "iit.mInputs " << iit.mInputs. - /* prepare output parts */ - fair::mq::Parts parts; - - /* loop over input parts */ - for (auto const& ref : iit) { - - auto headerIn = DataRefUtils::getHeader(ref); - auto dataProcessingHeaderIn = DataRefUtils::getHeader(ref); - auto payloadIn = ref.payload; - auto payloadInSize = DataRefUtils::getPayloadSize(ref); - std::cout << "payload In is : " << std::hex << payloadIn << std::endl; - std::cout << "payload In is : " << std::dec << payloadIn << std::endl; - std::cout << "payload In size is : " << std::dec << payloadInSize << std::endl; - mReader.setDataBuffer(payloadIn); - mReader.setDataBufferSize(payloadInSize); - /* run */ - mReader.run(); - - auto payloadOutSize = buildEventOutput(); - - auto payloadOutSizeBytes = payloadOutSize * 8; // payloadoutsize in bytes. - LOG(info) << "outgoing message has a data size of : " << payloadOutSize; - if (payloadOutSizeBytes > 32 * 1024) { - LOG(warn) << " buffer size for data is >32kB so will span rdh"; - } - int numberofpiecestocutinto = payloadOutSizeBytes / (32 * 1024); - int segmentsize = 32 * 1024 - 0x40; // 0x40 is the size of the rdh header in bytes. - //the above will drop the decimal due to int. - numberofpiecestocutinto++; - for (int datasegment = 0; datasegment < numberofpiecestocutinto; ++datasegment) { - auto payloadMessage = device->NewMessage(payloadOutSize); - std::memcpy(payloadMessage->GetData(), (char*)mOutBuffer.data() + datasegment * segmentsize, payloadOutSize); - /* output */ - auto headerOut = *headerIn; - auto dataProcessingHeaderOut = *dataProcessingHeaderIn; - headerOut.dataDescription = "CDATA"; - headerOut.payloadSize = payloadOutSizeBytes; - // what to do about the packet count? - //headerOut.packetCounter; - o2::header::Stack headerStack{headerOut, dataProcessingHeaderOut}; - auto headerMessage = device->NewMessage(headerStack.size()); - std::memcpy(headerMessage->GetData(), headerStack.data(), headerStack.size()); - - /* add parts */ - parts.AddPart(std::move(headerMessage)); - parts.AddPart(std::move(payloadMessage)); - } - } - - /* send message */ - device->Send(parts, fairMQChannel); - } -} - -} // namespace trd -} // namespace o2 From b82807bb9f696d7cc6373c9dd0f842fcb734ec9e Mon Sep 17 00:00:00 2001 From: Chiara Zampolli Date: Thu, 19 Oct 2023 12:56:25 +0200 Subject: [PATCH 295/324] Using http to access CCDB --- Detectors/Calibration/testMacros/getRunParameters.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/Calibration/testMacros/getRunParameters.cxx b/Detectors/Calibration/testMacros/getRunParameters.cxx index 7dfdce471f350..605cc26b1a36f 100644 --- a/Detectors/Calibration/testMacros/getRunParameters.cxx +++ b/Detectors/Calibration/testMacros/getRunParameters.cxx @@ -106,7 +106,7 @@ int main(int argc, char* argv[]) long duration = 0; // duration as O2end - O2start: auto& ccdb_inst = o2::ccdb::BasicCCDBManager::instance(); - ccdb_inst.setURL("https://alice-ccdb.cern.ch"); + ccdb_inst.setURL("http://alice-ccdb.cern.ch"); std::pair run_times = ccdb_inst.getRunDuration(run); long run_O2duration = long(run_times.second - run_times.first); // access SOR and EOR timestamps From 1ea72d933e3b9dd1b4a91af9f598d86b056caac6 Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Mon, 16 Oct 2023 16:56:13 +0200 Subject: [PATCH 296/324] TPC: Using PropagateToXBxByBz for residual gain map extraction - adjusting default parameters - small optimizations during normalisation of the extracted map --- Detectors/TPC/calibration/src/CalibPadGainTracks.cxx | 5 ++++- .../TPC/calibration/src/CalibPadGainTracksBase.cxx | 12 ++++++++++-- .../include/TPCWorkflow/TPCCalibPadGainTracksSpec.h | 12 ++++++------ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Detectors/TPC/calibration/src/CalibPadGainTracks.cxx b/Detectors/TPC/calibration/src/CalibPadGainTracks.cxx index b57aabe469484..97927107d56a9 100644 --- a/Detectors/TPC/calibration/src/CalibPadGainTracks.cxx +++ b/Detectors/TPC/calibration/src/CalibPadGainTracks.cxx @@ -25,6 +25,7 @@ #include "GPUO2Interface.h" #include "DataFormatsTPC/ClusterNative.h" #include "DataFormatsTPC/VDriftCorrFact.h" +#include "DetectorsBase/Propagator.h" // root includes #include "TFile.h" @@ -92,8 +93,10 @@ void CalibPadGainTracks::processTrack(o2::tpc::TrackTPC track, o2::gpu::GPUO2Int const float xPosition = Mapper::instance().getPadCentre(PadPos(rowIndex, 0)).X(); if (!mPropagateTrack) { refit->setTrackReferenceX(xPosition); + } else { + track.rotate(o2::math_utils::detail::sector2Angle(sectorIndex)); } - const bool check = mPropagateTrack ? track.propagateTo(xPosition, mField) : ((refit->RefitTrackAsGPU(track, false, true) < 0) ? false : true); // propagate this track to the plane X=xk (cm) in the field "b" (kG) + const bool check = mPropagateTrack ? o2::base::Propagator::Instance()->PropagateToXBxByBz(track, xPosition, 0.9f, 2., o2::base::Propagator::MatCorrType::USEMatCorrLUT) : ((refit->RefitTrackAsGPU(track, false, true) < 0) ? false : true); // propagate this track to the plane X=xk (cm) in the field "b" (kG) if (!check || std::isnan(track.getParam(1))) { continue; diff --git a/Detectors/TPC/calibration/src/CalibPadGainTracksBase.cxx b/Detectors/TPC/calibration/src/CalibPadGainTracksBase.cxx index a964de03f891b..2d8c34810324b 100644 --- a/Detectors/TPC/calibration/src/CalibPadGainTracksBase.cxx +++ b/Detectors/TPC/calibration/src/CalibPadGainTracksBase.cxx @@ -212,7 +212,7 @@ void CalibPadGainTracksBase::finalize(const int minEntries, const float minRelga const auto& histo = mPadHistosDet->getCalArray(roc).getData()[pad]; unsigned int entries = histo.getEntries(); const auto stat = histo.getStatisticsData(low, high); - const auto cog = std::clamp(static_cast(stat.mCOG), minRelgain, maxRelgain); + const auto cog = static_cast(stat.mCOG); // subtract underflow and overflow entries to check if only the valid entries are > 0 if (histo.isUnderflowSet()) { @@ -235,6 +235,14 @@ void CalibPadGainTracksBase::finalize(const int minEntries, const float minRelga } } normalizeGain(*mGainMap.get()); + + // clamp to min/max + for (int roc = 0; roc < ROC::MaxROC; ++roc) { + const auto padsInRoc = ROC(roc).isIROC() ? Mapper::getPadsInIROC() : Mapper::getPadsInOROC(); + for (int pad = 0; pad < padsInRoc; ++pad) { + mGainMap->getCalArray(roc).getData()[pad] = std::clamp(mGainMap->getCalArray(roc).getData()[pad], minRelgain, maxRelgain); + } + } } void CalibPadGainTracksBase::normalizeGain(CalPad& calPad) @@ -265,7 +273,7 @@ void CalibPadGainTracksBase::normalize(std::vector& data, const std::vect int padStart = 0; for (const auto pads : nPads) { auto median = TMath::Median(pads, data.data() + padStart); - std::for_each(data.data() + padStart, data.data() + padStart + pads, [median](auto& val) { val /= (val > 0) ? median : 1; }); + std::for_each(data.data() + padStart, data.data() + padStart + pads, [median](auto& val) { val /= ((val > 0) && (val != 1)) ? median : 1; }); padStart += pads; } } diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h index 66dffa8a8347c..f87b5129b3d33 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h @@ -85,8 +85,8 @@ class TPCCalibPadGainTracksDevice : public o2::framework::Task mPadGainTracks.setdEdxMax(maxdEdx); mPadGainTracks.doNotNomalize(donotnormalize); - const auto propagateTrack = ic.options().get("propagateTrack"); - mPadGainTracks.setPropagateTrack(propagateTrack); + const auto propagateTrack = ic.options().get("do-not-propagateTrack"); + mPadGainTracks.setPropagateTrack(!propagateTrack); const auto dedxRegionType = ic.options().get("dedxRegionType"); mPadGainTracks.setdEdxRegion(static_cast(dedxRegionType)); @@ -271,14 +271,14 @@ DataProcessorSpec getTPCCalibPadGainTracksSpec(const uint32_t publishAfterTFs, c {"etaMax", VariantType::Float, 1.f, {"maximum eta of the tracks which are used for the pad-by-pad gain map"}}, {"disable-log-transform", VariantType::Bool, false, {"Disable the transformation of q/dedx -> log(1 + q/dedx)"}}, {"do-not-normalize", VariantType::Bool, false, {"Do not normalize the cluster charge to the dE/dx"}}, - {"mindEdx", VariantType::Float, 0.f, {"Minimum accepted dE/dx value"}}, - {"maxdEdx", VariantType::Float, -1.f, {"Maximum accepted dE/dx value (-1=accept all dE/dx)"}}, + {"mindEdx", VariantType::Float, 10.f, {"Minimum accepted dE/dx value"}}, + {"maxdEdx", VariantType::Float, 500.f, {"Maximum accepted dE/dx value (-1=accept all dE/dx)"}}, {"minClusters", VariantType::Int, 50, {"minimum number of clusters of tracks which are used for the pad-by-pad gain map"}}, {"gainMapFile", VariantType::String, "", {"file to reference gain map, which will be used for correcting the cluster charge"}}, {"dedxRegionType", VariantType::Int, 2, {"using the dE/dx per chamber (0), stack (1) or per sector (2)"}}, {"dedxType", VariantType::Int, 0, {"recalculating the dE/dx (0), using it from tracking (1)"}}, {"chargeType", VariantType::Int, 0, {"Using qMax (0) or qTot (1) for the dE/dx and the pad-by-pad histograms"}}, - {"propagateTrack", VariantType::Bool, false, {"Propagating the track instead of performing a refit for obtaining track parameters."}}, + {"do-not-propagateTrack", VariantType::Bool, false, {"Performing a refit for obtaining track parameters instead of propagating."}}, {"useEveryNthTF", VariantType::Int, 10, {"Using only a fraction of the data: 1: Use every TF, 10: Use only every tenth TF."}}, {"maxTracksPerTF", VariantType::Int, 10000, {"Maximum number of processed tracks per TF (-1 for processing all tracks)"}}, }; @@ -288,7 +288,7 @@ DataProcessorSpec getTPCCalibPadGainTracksSpec(const uint32_t publishAfterTFs, c false, // GRPECS=true false, // GRPLHCIF true, // GRPMagField - false, // askMatLUT + true, // askMatLUT o2::base::GRPGeomRequest::None, // geometry inputs); From ee141f3546324f8a9fb80b75b78724a15de01d96 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 19 Oct 2023 15:10:23 +0200 Subject: [PATCH 297/324] DPL: Fix new run detection in input proxy --- Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index d1a45a95c6d98..11b4ba46b3899 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -862,7 +862,9 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, newRun = true; inStopTransition = false; } - currentRunNumber = dh->runNumber; + if (currentRunNumber == -1 || dh->runNumber != 0) { + currentRunNumber = dh->runNumber; + } timingInfo.runNumber = dh->runNumber; timingInfo.firstTForbit = dh->firstTForbit; timingInfo.tfCounter = dh->tfCounter; From 7ac0b52466cf078231a865845c69a70a49349377 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 19 Oct 2023 13:45:57 +0200 Subject: [PATCH 298/324] Drop obsolete flag -undefined error is the default now. --- dependencies/O2CompileFlags.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/dependencies/O2CompileFlags.cmake b/dependencies/O2CompileFlags.cmake index e52260ed74455..7fe9019701efe 100644 --- a/dependencies/O2CompileFlags.cmake +++ b/dependencies/O2CompileFlags.cmake @@ -126,7 +126,6 @@ set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}} set(CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE}} ${CMAKE_C_WARNINGS}") if(APPLE) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-undefined,error") # avoid undefined in our libs elseif(UNIX) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") # avoid undefined in our libs endif() From 3d52ff095ba8ce1095ba42a85a97323b850e05d2 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 19 Oct 2023 15:54:20 +0200 Subject: [PATCH 299/324] DPL: change InjectorFunction to return a bool The result is now wether or not something was send out of band --- .../CTP/workflowScalers/src/ctp-proxy.cxx | 3 ++- .../CTP/workflowScalers/src/ctp-qc-proxy.cxx | 5 ++-- .../DCS/testWorkflow/src/DCStoDPLconverter.h | 7 +++-- .../DCS/testWorkflow/src/dcs-config-proxy.cxx | 11 ++++---- .../Framework/ExternalFairMQDeviceProxy.h | 11 +++++++- .../Core/src/ExternalFairMQDeviceProxy.cxx | 6 +++-- .../benchmark_ExternalFairMQDeviceProxies.cxx | 11 ++++---- .../test_ExternalFairMQDeviceWorkflow.cxx | 26 +++++++++---------- .../src/DataSamplingReadoutAdapter.cxx | 1 + run/o2sim_mctracks_proxy.cxx | 8 ++++-- 10 files changed, 56 insertions(+), 33 deletions(-) diff --git a/Detectors/CTP/workflowScalers/src/ctp-proxy.cxx b/Detectors/CTP/workflowScalers/src/ctp-proxy.cxx index 449cd0903c882..3634df6d30bda 100644 --- a/Detectors/CTP/workflowScalers/src/ctp-proxy.cxx +++ b/Detectors/CTP/workflowScalers/src/ctp-proxy.cxx @@ -52,7 +52,7 @@ InjectorFunction dcs2dpl(std::string& ccdbhost) auto runMgr = std::make_shared(); runMgr->setCCDBHost(ccdbhost); runMgr->init(); - return [runMgr](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { + return [runMgr](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) -> bool { // FIXME: Why isn't this function using the timeslice index? // make sure just 2 messages received // if (parts.Size() != 2) { @@ -64,6 +64,7 @@ InjectorFunction dcs2dpl(std::string& ccdbhost) std::string messageData{static_cast(parts.At(1)->GetData()), parts.At(1)->GetSize()}; LOG(info) << "received message " << messageHeader << " of size " << dataSize << " # parts:" << parts.Size(); // << " Payload:" << messageData; runMgr->processMessage(messageHeader, messageData); + return true; }; } diff --git a/Detectors/CTP/workflowScalers/src/ctp-qc-proxy.cxx b/Detectors/CTP/workflowScalers/src/ctp-qc-proxy.cxx index 0502bbae86493..2372ba07a28f7 100644 --- a/Detectors/CTP/workflowScalers/src/ctp-qc-proxy.cxx +++ b/Detectors/CTP/workflowScalers/src/ctp-qc-proxy.cxx @@ -46,7 +46,7 @@ using DetID = o2::detectors::DetID; InjectorFunction dcs2dpl() // InjectorFunction dcs2dpl() { - return [](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + return [](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) -> bool { auto *device = services.get().device(); std::string messageHeader{static_cast(parts.At(0)->GetData()), parts.At(0)->GetSize()}; size_t dataSize = parts.At(1)->GetSize(); @@ -57,7 +57,7 @@ InjectorFunction dcs2dpl() auto channel = channelRetriever(outsp, newTimesliceId); if (channel.empty()) { LOG(error) << "No output channel found for OutputSpec " << outsp; - return; + return false; } hdrF.tfCounter = newTimesliceId; // this also hdrF.payloadSerializationMethod = o2::header::gSerializationMethodNone; @@ -91,6 +91,7 @@ InjectorFunction dcs2dpl() outParts.AddPart(std::move(plMessageF)); sendOnChannel(*device, outParts, channel, newTimesliceId); LOG(info) << "Sent CTP counters DPL message" << std::flush; + return true; }; } diff --git a/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h b/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h index dab2fd730b360..4384628d01f4c 100644 --- a/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h +++ b/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h @@ -53,7 +53,7 @@ using DPCOM = o2::dcs::DataPointCompositeObject; o2f::InjectorFunction dcs2dpl(std::unordered_map& dpid2group, bool fbiFirst, bool verbose = false, int FBIPerInterval = 1) { - return [dpid2group, fbiFirst, verbose, FBIPerInterval](o2::framework::TimingInfo& tinfo, framework::ServiceRegistryRef const& services, fair::mq::Parts& parts, o2f::ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { + return [dpid2group, fbiFirst, verbose, FBIPerInterval](o2::framework::TimingInfo& tinfo, framework::ServiceRegistryRef const& services, fair::mq::Parts& parts, o2f::ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) -> bool { auto *device = services.get().device(); static std::unordered_map cache; // will keep only the latest measurement in the 1-second wide window for each DPID static std::unordered_map sentToChannel; @@ -69,7 +69,7 @@ o2f::InjectorFunction dcs2dpl(std::unordered_map& dp // check if we got FBI (Master) or delta (MasterDelta) if (!parts.Size()) { LOGP(warn, "Empty input recieved at timeslice {}", tinfo.timeslice); - return; + return false; } std::string firstName = std::string((char*)&(reinterpret_cast(parts.At(0)->GetData()))->id); @@ -124,6 +124,7 @@ o2f::InjectorFunction dcs2dpl(std::unordered_map& dp } std::chrono::duration> duration = timerNow - timer; + bool didSendMessages = false; if (duration.count() > 1 && (seenFBI || !fbiFirst)) { // did we accumulate for 1 sec and have we seen FBI if it was requested? std::unordered_map, std::hash> outputs; // in the cache we have the final values of the DPs that we should put in the output @@ -183,6 +184,7 @@ o2f::InjectorFunction dcs2dpl(std::unordered_map& dp } o2f::sendOnChannel(*device, *msgIt.second.get(), msgIt.first, tinfo.timeslice); sentToChannel[msgIt.first]++; + didSendMessages |= msgIt.second->Size() > 0; } timer = timerNow; cache.clear(); @@ -200,6 +202,7 @@ o2f::InjectorFunction dcs2dpl(std::unordered_map& dp } LOGP(info, "{} inputs ({} bytes) of which {} FBI ({} bytes) seen in {:.3f} s | {}", nInp, fmt::group_digits(szInp), nInpFBI, fmt::group_digits(szInpFBI), runtime, sent); } + return didSendMessages; }; } diff --git a/Detectors/DCS/testWorkflow/src/dcs-config-proxy.cxx b/Detectors/DCS/testWorkflow/src/dcs-config-proxy.cxx index 936ceebf1e0f2..9b697da428ad2 100644 --- a/Detectors/DCS/testWorkflow/src/dcs-config-proxy.cxx +++ b/Detectors/DCS/testWorkflow/src/dcs-config-proxy.cxx @@ -67,17 +67,17 @@ auto getDataOriginFromFilename(const std::string& filename) InjectorFunction dcs2dpl(const std::string& acknowledge) { - return [acknowledge](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + return [acknowledge](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) -> bool { auto *device = services.get().device(); if (parts.Size() == 0) { // received at ^c, ignore LOG(info) << "ignoring empty message"; - return; + return false; } // make sure just 2 messages received if (parts.Size() != 2) { LOG(error) << "received " << parts.Size() << " instead of 2 expected"; sendAnswer("error0: wrong number of messages", acknowledge, *device); - return; + return false; } std::string filename{static_cast(parts.At(0)->GetData()), parts.At(0)->GetSize()}; size_t filesize = parts.At(1)->GetSize(); @@ -86,7 +86,7 @@ InjectorFunction dcs2dpl(const std::string& acknowledge) if (dataOrigin == o2::header::gDataOriginInvalid) { LOG(error) << "unknown detector for " << filename; sendAnswer(fmt::format("{}:error1: unrecognized filename", filename), acknowledge, *device); - return; + return false; } o2::header::DataHeader hdrF("DCS_CONFIG_FILE", dataOrigin, 0); @@ -96,7 +96,7 @@ InjectorFunction dcs2dpl(const std::string& acknowledge) if (channel.empty()) { LOG(error) << "No output channel found for OutputSpec " << outsp; sendAnswer(fmt::format("{}:error2: no channel to send", filename), acknowledge, *device); - return; + return false; } hdrF.tfCounter = newTimesliceId; @@ -140,6 +140,7 @@ InjectorFunction dcs2dpl(const std::string& acknowledge) sendAnswer(fmt::format("{}:ok", filename), acknowledge, *device); LOG(info) << "Sent DPL message and acknowledgment for file " << filename; + return true; }; } diff --git a/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h b/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h index cfa05cd07d1d2..3ff77ae703b9b 100644 --- a/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h +++ b/Framework/Core/include/Framework/ExternalFairMQDeviceProxy.h @@ -23,7 +23,16 @@ namespace o2::framework /// A callback function to retrieve the fair::mq::Channel name to be used for sending /// messages of the specified OutputSpec using ChannelRetriever = std::function; -using InjectorFunction = std::function; +/// The callback which actually does the heavy lifting of converting the input data into +/// DPL messages. The callback is invoked with the following parameters: +/// @param timingInfo is the timing information of the current timeslice +/// @param services is the service registry +/// @param inputs is the list of input messages +/// @param channelRetriever is a callback to retrieve the fair::mq::Channel name to be used for +/// sending the messages +/// @param newTimesliceId is the timeslice ID of the current timeslice +/// @return true if any message were sent, false otherwise +using InjectorFunction = std::function; using ChannelSelector = std::function>& channels)>; struct InputChannelSpec; diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 11b4ba46b3899..594c4d22ae50e 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -203,7 +203,7 @@ void appendForSending(fair::mq::Device& device, o2::header::Stack&& headerStack, InjectorFunction o2DataModelAdaptor(OutputSpec const& spec, uint64_t startTime, uint64_t /*step*/) { - return [spec](TimingInfo&, ServiceRegistryRef const& ref, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) { + return [spec](TimingInfo&, ServiceRegistryRef const& ref, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) -> bool { auto* device = ref.get().device(); for (int i = 0; i < parts.Size() / 2; ++i) { auto dh = o2::header::get(parts.At(i * 2)->GetData()); @@ -212,6 +212,7 @@ InjectorFunction o2DataModelAdaptor(OutputSpec const& spec, uint64_t startTime, o2::header::Stack headerStack{*dh, dph}; sendOnChannel(*device, std::move(headerStack), std::move(parts.At(i * 2 + 1)), spec, channelRetriever); } + return parts.Size() > 0; }; } @@ -589,7 +590,7 @@ InjectorFunction dplModelAdaptor(std::vector const& filterSpecs, DPL } } } - return; + return didSendParts; }; } @@ -621,6 +622,7 @@ InjectorFunction incrementalConverter(OutputSpec const& spec, o2::header::Serial sendOnChannel(*device, std::move(headerStack), std::move(parts.At(i)), spec, channelRetriever); } + return parts.Size(); }; } diff --git a/Framework/Core/test/benchmark_ExternalFairMQDeviceProxies.cxx b/Framework/Core/test/benchmark_ExternalFairMQDeviceProxies.cxx index 55e0b4cec89db..bdb4deb443021 100644 --- a/Framework/Core/test/benchmark_ExternalFairMQDeviceProxies.cxx +++ b/Framework/Core/test/benchmark_ExternalFairMQDeviceProxies.cxx @@ -469,22 +469,22 @@ std::vector defineDataProcessing(ConfigContext const& config) // reads the messages from the output proxy via the out-of-band channel // converter callback for the external FairMQ device proxy ProcessorSpec generator - auto converter = [](TimingInfo&, ServiceRegistryRef const& ref, fair::mq::Parts& inputs, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + InjectorFunction converter = [](TimingInfo&, ServiceRegistryRef const& ref, fair::mq::Parts& inputs, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) -> bool { auto* device = ref.get().device(); ASSERT_ERROR(inputs.Size() >= 2); if (inputs.Size() < 2) { - return; + return false; } int msgidx = 0; auto dh = o2::header::get(inputs.At(msgidx)->GetData()); if (!dh) { LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataHeader missing"; - return; + return false; } auto dph = o2::header::get(inputs.At(msgidx)->GetData()); if (!dph) { LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataProcessingHeader missing"; - return; + return false; } // Note: we want to run both the output and input proxy in the same workflow and thus we need // different data identifiers and change the data origin in the forwarding @@ -497,7 +497,7 @@ std::vector defineDataProcessing(ConfigContext const& config) ASSERT_ERROR(!isData || !channelName.empty()); LOG(debug) << "using channel '" << channelName << "' for " << DataSpecUtils::describe(OutputSpec{dh->dataOrigin, dh->dataDescription, dh->subSpecification}); if (channelName.empty()) { - return; + return false; } // make a copy of the header message, get the data header and change origin auto outHeaderMessage = device->NewMessageFor(channelName, 0, inputs.At(msgidx)->GetSize()); @@ -511,6 +511,7 @@ std::vector defineDataProcessing(ConfigContext const& config) output.AddPart(std::move(inputs.At(msgidx + 1))); LOG(debug) << "sending " << DataSpecUtils::describe(OutputSpec{odh->dataOrigin, odh->dataDescription, odh->subSpecification}); o2::framework::sendOnChannel(*device, output, channelName, (size_t)-1); + return output.Size() > 0; }; // we use the same spec to build the configuration string, ideally we would have some helpers diff --git a/Framework/Core/test/test_ExternalFairMQDeviceWorkflow.cxx b/Framework/Core/test/test_ExternalFairMQDeviceWorkflow.cxx index 98f3139fe7b86..c105a9d0f662c 100644 --- a/Framework/Core/test/test_ExternalFairMQDeviceWorkflow.cxx +++ b/Framework/Core/test/test_ExternalFairMQDeviceWorkflow.cxx @@ -176,7 +176,7 @@ std::vector defineDataProcessing(ConfigContext const& config) // the compute callback of the producer auto producerCallback = [nRolls, channelName, proxyMode, counter = std::make_shared()](DataAllocator& outputs, ControlService& control, RawDeviceService& rds) { int data = *counter; - //outputs.make(OutputRef{"data", 0}) = data; + // outputs.make(OutputRef{"data", 0}) = data; fair::mq::Device& device = *(rds.device()); auto transport = device.GetChannel(*channelName, 0).Transport(); @@ -327,14 +327,14 @@ std::vector defineDataProcessing(ConfigContext const& config) Inputs checkerInputs; if (proxyMode != ProxyMode::All) { checkerInputs.emplace_back(InputSpec{"datain", ConcreteDataTypeMatcher{"TST", "DATA"}, Lifetime::Timeframe}); - //for (unsigned int i = 0; i < pState->nChannels; i++) { - // checkerInputs.emplace_back(InputSpec{{"datain"}, "TST", "DATA", i, Lifetime::Timeframe}); - //} + // for (unsigned int i = 0; i < pState->nChannels; i++) { + // checkerInputs.emplace_back(InputSpec{{"datain"}, "TST", "DATA", i, Lifetime::Timeframe}); + // } } else { checkerInputs.emplace_back(InputSpec{"datain", ConcreteDataTypeMatcher{"PRX", "DATA"}, Lifetime::Timeframe}); - //for (unsigned int i = 0; i < pState->nChannels; i++) { - // checkerInputs.emplace_back(InputSpec{{"datain"}, "PRX", "DATA", i, Lifetime::Timeframe}); - //} + // for (unsigned int i = 0; i < pState->nChannels; i++) { + // checkerInputs.emplace_back(InputSpec{{"datain"}, "PRX", "DATA", i, Lifetime::Timeframe}); + // } } if (proxyMode != ProxyMode::OnlyOutput) { // the checker is not added if the input proxy is skipped @@ -349,22 +349,22 @@ std::vector defineDataProcessing(ConfigContext const& config) // reads the messages from the output proxy via the out-of-band channel // converter callback for the external FairMQ device proxy ProcessorSpec generator - auto converter = [](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& inputs, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) { + InjectorFunction converter = [](TimingInfo&, ServiceRegistryRef const& services, fair::mq::Parts& inputs, ChannelRetriever channelRetriever, size_t newTimesliceId, bool&) -> bool { auto* device = services.get().device(); ASSERT_ERROR(inputs.Size() >= 2); if (inputs.Size() < 2) { - return; + return false; } int msgidx = 0; auto dh = o2::header::get(inputs.At(msgidx)->GetData()); if (!dh) { LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataHeader missing"; - return; + return false; } auto dph = o2::header::get(inputs.At(msgidx)->GetData()); if (!dph) { LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataProcessingHeader missing"; - return; + return false; } // Note: we want to run both the output and input proxy in the same workflow and thus we need // different data identifiers and change the data origin in the forwarding @@ -377,7 +377,7 @@ std::vector defineDataProcessing(ConfigContext const& config) ASSERT_ERROR(!isData || !channelName.empty()); LOG(debug) << "using channel '" << channelName << "' for " << DataSpecUtils::describe(OutputSpec{dh->dataOrigin, dh->dataDescription, dh->subSpecification}); if (channelName.empty()) { - return; + return false; } fair::mq::Parts output; for (; msgidx < inputs.Size(); ++msgidx) { @@ -402,7 +402,7 @@ std::vector defineDataProcessing(ConfigContext const& config) } } o2::framework::sendOnChannel(*device, output, channelName, (size_t)-1); - return; + return output.Size() != 0; }; // we use the same spec to build the configuration string, ideally we would have some helpers diff --git a/Utilities/DataSampling/src/DataSamplingReadoutAdapter.cxx b/Utilities/DataSampling/src/DataSamplingReadoutAdapter.cxx index 745c0cddbf835..66a872e265baf 100644 --- a/Utilities/DataSampling/src/DataSamplingReadoutAdapter.cxx +++ b/Utilities/DataSampling/src/DataSamplingReadoutAdapter.cxx @@ -41,6 +41,7 @@ InjectorFunction dataSamplingReadoutAdapter(OutputSpec const& spec) o2::header::Stack headerStack{dh, dph}; sendOnChannel(*device, std::move(headerStack), std::move(parts.At(i)), spec, channelRetriever); } + return parts.Size() != 0; }; } diff --git a/run/o2sim_mctracks_proxy.cxx b/run/o2sim_mctracks_proxy.cxx index cd032dd35c4fa..8b40c6a647cca 100644 --- a/run/o2sim_mctracks_proxy.cxx +++ b/run/o2sim_mctracks_proxy.cxx @@ -93,8 +93,9 @@ InjectorFunction o2simKinematicsConverter(std::vector const& specs, auto MCTracksMessageCache = std::make_shared(); auto Nparts = std::make_shared(nPerTF); - return [timesliceId, specs, step, nevents, nPerTF, totalEventCounter, eventCounter, TFcounter, Nparts, MCHeadersMessageCache = MCHeadersMessageCache, MCTracksMessageCache = MCTracksMessageCache](TimingInfo& ti, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) mutable { + return [timesliceId, specs, step, nevents, nPerTF, totalEventCounter, eventCounter, TFcounter, Nparts, MCHeadersMessageCache = MCHeadersMessageCache, MCTracksMessageCache = MCTracksMessageCache](TimingInfo& ti, ServiceRegistryRef const& services, fair::mq::Parts& parts, ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) mutable -> bool { auto*device = services.get().device(); + bool didSendData = false; if (nPerTF < 0) { // if no aggregation requested, forward each message with the DPL header if (*timesliceId != newTimesliceId) { @@ -108,6 +109,7 @@ InjectorFunction o2simKinematicsConverter(std::vector const& specs, // we have to move the incoming data o2::header::Stack headerStack{dh, dph}; sendOnChannel(*device, std::move(headerStack), std::move(parts.At(i)), specs[i], channelRetriever); + didSendData |= parts.At(i)->GetSize() > 0; } *timesliceId += step; } else { @@ -141,6 +143,8 @@ InjectorFunction o2simKinematicsConverter(std::vector const& specs, *eventCounter = 0; sendOnChannel(*device, *MCHeadersMessageCache.get(), channelRetriever(specs[0], *TFcounter), *TFcounter); sendOnChannel(*device, *MCTracksMessageCache.get(), channelRetriever(specs[1], *TFcounter), *TFcounter); + didSendData |= MCHeadersMessageCache->Size() > 0; + didSendData |= MCTracksMessageCache->Size() > 0; ++(*TFcounter); MCHeadersMessageCache->Clear(); MCTracksMessageCache->Clear(); @@ -150,7 +154,7 @@ InjectorFunction o2simKinematicsConverter(std::vector const& specs, // I am done (I don't expect more events to convert); so tell the proxy device to shut-down stop = true; } - return; + return didSendData; }; } From 79f2be25d9d8a595808416e9f3d9fc3649af7172 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:15:34 +0200 Subject: [PATCH 300/324] DPL: notify DPL about out of band data being sent by input proxy This is needed to avoid skipping some of the callbacks, in particular the CCDB one. --- .../Core/src/ExternalFairMQDeviceProxy.cxx | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 594c4d22ae50e..4d9d4c11df49f 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -561,13 +561,6 @@ InjectorFunction dplModelAdaptor(std::vector const& filterSpecs, DPL didSendParts = true; sendOnChannel(*device, channelParts, channelName, newTimesliceId); } - // In case we did not send any part at all, we need to rewind by one - // to avoid creating extra timeslices at the end of the run. - auto& decongestion = services.get(); - decongestion.nextEnumerationTimesliceRewinded = !didSendParts; - if (didSendParts == false) { - decongestion.nextEnumerationTimeslice -= 1; - } if (not unmatchedDescriptions.empty()) { if (throwOnUnmatchedInputs) { std::string descriptions; @@ -769,12 +762,13 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, return count; }; - auto dataHandler = [ref = ctx.services(), converter, doInjectMissingData, doPrintSizes, + // Data handler for incoming data. Must return true if it sent any data. + auto dataHandler = [converter, doInjectMissingData, doPrintSizes, outputRoutes = std::move(outputRoutes), control = &ctx.services().get(), deviceState = &ctx.services().get(), timesliceIndex = &ctx.services().get(), - outputChannels = std::move(outputChannels)](TimingInfo& timingInfo, fair::mq::Parts& inputs, int, size_t ci, bool newRun) { + outputChannels = std::move(outputChannels)](ServiceRegistryRef ref, TimingInfo& timingInfo, fair::mq::Parts& inputs, int, size_t ci, bool newRun) -> bool { auto* device = ref.get().device(); // pass a copy of the outputRoutes auto channelRetriever = [&outputRoutes](OutputSpec const& query, DataProcessingHeader::StartTime timeslice) -> std::string { @@ -803,7 +797,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, if (doInjectMissingData) { injectMissingData(*device, inputs, outputRoutes, doInjectMissingData, doPrintSizes); } - converter(timingInfo, ref, inputs, channelRetriever, timesliceIndex->getOldestPossibleOutput().timeslice.value, shouldstop); + bool didSendParts = converter(timingInfo, ref, inputs, channelRetriever, timesliceIndex->getOldestPossibleOutput().timeslice.value, shouldstop); // If we have enough EoS messages, we can stop the device // Notice that this has a number of failure modes: @@ -832,6 +826,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, std::fill(eosPeersCount.begin(), eosPeersCount.end(), 0); control->endOfStream(); } + return didSendParts; }; auto runHandler = [dataHandler, minSHM, sendTFcounter](ProcessingContext& ctx) { @@ -844,6 +839,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, inStopTransition = true; } + bool didSendParts = false; for (size_t ci = 0; ci < channels.size(); ++ci) { std::string const& channel = channels[ci]; int waitTime = channels.size() == 1 ? -1 : 1; @@ -877,7 +873,7 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, timingInfo.creation = dph->creation; } if (!inStopTransition) { - dataHandler(timingInfo, parts, 0, ci, newRun); + didSendParts |= dataHandler(ctx.services(), timingInfo, parts, 0, ci, newRun); } if (sendTFcounter) { ctx.services().get().send(o2::monitoring::Metric{(uint64_t)timingInfo.tfCounter, "df-sent"}.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::DPL)); @@ -889,6 +885,15 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name, waitTime = 0; } } + // In case we did not send any part at all, we need to rewind by one + // to avoid creating extra timeslices. + auto& decongestion = ctx.services().get(); + decongestion.nextEnumerationTimesliceRewinded = !didSendParts; + if (didSendParts) { + ctx.services().get().fakeDispatch(); + } else { + decongestion.nextEnumerationTimeslice -= 1; + } }; return runHandler; From d3e3bf2d58afe58bfec0cbad6cc61d7987a7292b Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 19 Oct 2023 23:25:40 +0200 Subject: [PATCH 301/324] Port the same fix we have in the Run3 code (#12104) --- Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx b/Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx index f66454ebad52e..e2078046d1966 100644 --- a/Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx +++ b/Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx @@ -189,7 +189,6 @@ void TrackerDPL::run(ProcessingContext& pc) LOG(info) << labels->getIndexedSize() << " MC label objects , in " << mc2rofs.size() << " MC events"; } - std::vector tracks; auto& allClusIdx = pc.outputs().make>(Output{"IT3", "TRACKCLSID", 0, Lifetime::Timeframe}); std::vector trackLabels; std::vector verticesLabels; @@ -281,7 +280,7 @@ void TrackerDPL::run(ProcessingContext& pc) for (unsigned int iROF{0}; iROF < rofs.size(); ++iROF) { auto& rof{rofs[iROF]}; - tracks = timeFrame->getTracks(iROF); + auto& tracks = timeFrame->getTracks(iROF); trackLabels = timeFrame->getTracksLabel(iROF); auto number{tracks.size()}; auto first{allTracks.size()}; From fa5b990f89f99ead1bc41cd176e2c8c6b2e1c200 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 19 Oct 2023 23:25:26 +0200 Subject: [PATCH 302/324] GPU: Fix HIP compilation with modern system LLVM present --- dependencies/FindO2GPU.cmake | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index 1a504c9e5084e..01bd08616c9ec 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -205,12 +205,19 @@ if(ENABLE_HIP) if(HIP_AMDGPUTARGET) set(AMDGPU_TARGETS "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) set(GPU_TARGETS "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) + set(CMAKE_HIP_ARCHITECTURES "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) endif() - include(CheckLanguage) - check_language(HIP) if(EXISTS "/opt/rocm/lib/cmake" AND (NOT DEFINED CMAKE_PREFIX_PATH OR NOT ${CMAKE_PREFIX_PATH} MATCHES "rocm") AND (NOT ENV{CMAKE_PREFIX_PATH} MATCHES "rocm")) set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};/opt/rocm/lib/cmake") + if (NOT DEFINED CMAKE_HIP_COMPILER) + set(CMAKE_HIP_COMPILER "/opt/rocm/llvm/bin/clang++") + endif() + if (NOT DEFINED HIP_CLANG_PATH) + set(HIP_CLANG_PATH "/opt/rocm/llvm/bin") + endif() endif() + include(CheckLanguage) + check_language(HIP) find_package(hip) find_package(hipcub) find_package(rocprim) From 4c594970aeff8e8c4cbe2e54e122b0429f43bc95 Mon Sep 17 00:00:00 2001 From: Fabio Catalano Date: Wed, 18 Oct 2023 16:05:57 +0200 Subject: [PATCH 303/324] Fix typo in subGenerator check --- Generators/src/Generator.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 90f0d2dd3a5df..99a00f154c268 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -222,7 +222,7 @@ Bool_t void Generator::addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription) { - if (mSubGeneratorId < 0) { + if (subGeneratorId < 0) { LOG(fatal) << "Sub-generator IDs must be >= 0, instead, passed value is " << subGeneratorId; } mSubGeneratorsIdToDesc.insert({subGeneratorId, subGeneratorDescription}); From e322401a8dc560f0457e6832c32b493482c69225 Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Fri, 20 Oct 2023 10:43:16 +0200 Subject: [PATCH 304/324] TRD Kr cluster writing to EOS (#12113) --- Detectors/TRD/workflow/CMakeLists.txt | 2 +- .../include/TRDWorkflow/KrClustererSpec.h | 68 +++++++- Detectors/TRD/workflow/io/CMakeLists.txt | 2 +- .../TRDWorkflowIO/KrClusterWriterSpec.h | 164 +++++++++++++++++- .../workflow/io/src/KrClusterWriterSpec.cxx | 39 ----- .../TRD/workflow/src/KrClustererSpec.cxx | 91 ---------- 6 files changed, 225 insertions(+), 141 deletions(-) delete mode 100644 Detectors/TRD/workflow/io/src/KrClusterWriterSpec.cxx delete mode 100644 Detectors/TRD/workflow/src/KrClustererSpec.cxx diff --git a/Detectors/TRD/workflow/CMakeLists.txt b/Detectors/TRD/workflow/CMakeLists.txt index 481a085306eed..53bb79565c8c4 100644 --- a/Detectors/TRD/workflow/CMakeLists.txt +++ b/Detectors/TRD/workflow/CMakeLists.txt @@ -21,7 +21,7 @@ o2_add_library(TRDWorkflow src/EntropyDecoderSpec.cxx src/EntropyEncoderSpec.cxx src/TrackBasedCalibSpec.cxx - src/KrClustererSpec.cxx + include/TRDWorkflow/KrClustererSpec.h include/TRDWorkflow/VdAndExBCalibSpec.h include/TRDWorkflow/GainCalibSpec.h include/TRDWorkflow/TRDPulseHeightSpec.h diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/KrClustererSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/KrClustererSpec.h index 649e4637eba54..26be31d51c084 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/KrClustererSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/KrClustererSpec.h @@ -19,7 +19,13 @@ // input TRD digits, TRD trigger records // output Kr clusters +#include "TRDWorkflow/KrClustererSpec.h" +#include "TRDCalibration/KrClusterFinder.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" #include "Framework/DataProcessorSpec.h" +#include "TStopwatch.h" +#include using namespace o2::framework; @@ -27,10 +33,68 @@ namespace o2 { namespace trd { -/// create a processor spec -framework::DataProcessorSpec getKrClustererSpec(); +class TRDKrClustererDevice : public Task +{ + public: + TRDKrClustererDevice() = default; + ~TRDKrClustererDevice() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) final; + + private: + o2::trd::KrClusterFinder mKrClFinder; +}; + +void TRDKrClustererDevice::init(InitContext& ic) +{ + mKrClFinder.init(); +} + +void TRDKrClustererDevice::run(ProcessingContext& pc) +{ + TStopwatch timer; + + const auto digits = pc.inputs().get>("digits"); + const auto triggerRecords = pc.inputs().get>("triggerRecords"); + + mKrClFinder.reset(); + mKrClFinder.setInput(digits, triggerRecords); + timer.Start(); + mKrClFinder.findClusters(); + timer.Stop(); + + LOGP(info, "Found {} Kr clusters in {} input trigger records. Timing: CPU: {}, Real: {}", + mKrClFinder.getKrClusters().size(), triggerRecords.size(), timer.CpuTime(), timer.RealTime()); + + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "KRCLUSTER", 0, Lifetime::Timeframe}, mKrClFinder.getKrClusters()); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRGKRCLS", 0, Lifetime::Timeframe}, mKrClFinder.getKrTrigRecs()); +} + +void TRDKrClustererDevice::endOfStream(EndOfStreamContext& ec) +{ + LOG(info) << "Done with the cluster finding (EoS received)"; +} + +framework::DataProcessorSpec getKrClustererSpec() +{ + std::vector inputs; + inputs.emplace_back("digits", ConcreteDataTypeMatcher{o2::header::gDataOriginTRD, "DIGITS"}, Lifetime::Timeframe); + inputs.emplace_back("triggerRecords", ConcreteDataTypeMatcher{o2::header::gDataOriginTRD, "TRKTRGRD"}, Lifetime::Timeframe); + std::vector outputs; + outputs.emplace_back(o2::header::gDataOriginTRD, "KRCLUSTER", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "TRGKRCLS", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "trd-kr-clusterer", + inputs, + outputs, + AlgorithmSpec{adaptFromTask()}, + Options{}}; +} } // namespace trd + } // namespace o2 #endif // O2_TRD_KRCLUSTERERSPEC_H diff --git a/Detectors/TRD/workflow/io/CMakeLists.txt b/Detectors/TRD/workflow/io/CMakeLists.txt index 198113e2cdd46..4405d12b4f987 100644 --- a/Detectors/TRD/workflow/io/CMakeLists.txt +++ b/Detectors/TRD/workflow/io/CMakeLists.txt @@ -22,7 +22,7 @@ o2_add_library(TRDWorkflowIO src/TRDTrackReaderSpec.cxx src/TRDCalibWriterSpec.cxx src/TRDPHReaderSpec.cxx - src/KrClusterWriterSpec.cxx + include/TRDWorkflowIO/KrClusterWriterSpec.h PUBLIC_LINK_LIBRARIES O2::DataFormatsTRD O2::SimulationDataFormat O2::DPLUtils O2::GPUDataTypeHeaders O2::DataFormatsTPC) diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/KrClusterWriterSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/KrClusterWriterSpec.h index a33886639c813..944ba6987806f 100644 --- a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/KrClusterWriterSpec.h +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/KrClusterWriterSpec.h @@ -12,20 +12,170 @@ #ifndef O2_TRD_KRWRITERSPEC_H #define O2_TRD_KRWRITERSPEC_H +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataTakingContext.h" +#include "DataFormatsTRD/KrCluster.h" +#include "DataFormatsTRD/KrClusterTriggerRecord.h" +#include "CommonUtils/MemFileHelper.h" +#include "DetectorsCommonDataFormats/FileMetaData.h" + +#include +#include +#include +#include + namespace o2 { -namespace framework +namespace trd { -struct DataProcessorSpec; -} -} // namespace o2 -namespace o2 +class TRDKrClsWriterTask : public o2::framework::Task { -namespace trd + public: + TRDKrClsWriterTask() = default; + + void init(o2::framework::InitContext& ic) final + { + mOutputDir = o2::utils::Str::rectifyDirectory(ic.options().get("output-dir")); + + // should we write meta files for epn2eos? + mMetaFileDir = ic.options().get("meta-output-dir"); + if (mMetaFileDir != "/dev/null") { + mMetaFileDir = o2::utils::Str::rectifyDirectory(mMetaFileDir); + mStoreMetaFile = true; + } + + LOGP(info, "Storing output in {}, meta file writing enabled: {}", mOutputDir, mStoreMetaFile); + mAutoSave = ic.options().get("autosave-interval"); + + char hostname[_POSIX_HOST_NAME_MAX]; + gethostname(hostname, _POSIX_HOST_NAME_MAX); + mHostName = hostname; + mHostName = mHostName.substr(0, mHostName.find('.')); + } + + void createOutputFile(int runNumber, o2::framework::ProcessingContext& pc) + { + mFileName = fmt::format("o2_trdKrCls_run{}_{}.root", runNumber, mHostName); + auto fileNameTmp = o2::utils::Str::concat_string(mOutputDir, mFileName, ".part"); + mFileOut = std::make_unique(fileNameTmp.c_str(), "recreate"); + mTreeOut = std::make_unique("krData", "TRD krypton cluster data"); + mTreeOut->Branch("cluster", &krClusterPtr); + mTreeOut->Branch("trigRec", &krTrigRecPtr); + mDataTakingContext = pc.services().get(); + mOutputFileCreated = true; + } + + void writeToFile() + { + if (!mOutputFileCreated) { + return; + } + mFileOut->cd(); + mTreeOut->Write(); + } + + void closeOutputFile() + { + if (!mOutputFileCreated) { + return; + } + writeToFile(); + mTreeOut.reset(); + mFileOut->Close(); + mFileOut.reset(); + auto fileNameWithPath = mOutputDir + mFileName; + std::filesystem::rename(o2::utils::Str::concat_string(mOutputDir, mFileName, ".part"), fileNameWithPath); + if (mStoreMetaFile) { + o2::dataformats::FileMetaData fileMetaData; // object with information for meta data file + fileMetaData.fillFileData(fileNameWithPath); + fileMetaData.setDataTakingContext(mDataTakingContext); + fileMetaData.type = "calib"; + fileMetaData.priority = "high"; + auto metaFileNameTmp = fmt::format("{}{}.tmp", mMetaFileDir, mFileName); + auto metaFileName = fmt::format("{}{}.done", mMetaFileDir, mFileName); + try { + std::ofstream metaFileOut(metaFileNameTmp); + metaFileOut << fileMetaData; + metaFileOut.close(); + std::filesystem::rename(metaFileNameTmp, metaFileName); + } catch (std::exception const& e) { + LOG(error) << "Failed to store meta data file " << metaFileName << ", reason: " << e.what(); + } + } + } + + void run(o2::framework::ProcessingContext& pc) final + { + if (!mOutputFileCreated) { + auto tInfo = pc.services().get(); + createOutputFile(tInfo.runNumber, pc); + } + if (pc.transitionState() == TransitionHandlingState::Requested) { + LOG(info) << "Run stop requested, closing output file"; + mRunStopRequested = true; + closeOutputFile(); + } + if (mRunStopRequested) { + return; + } + auto cluster = pc.inputs().get>("krcluster"); + auto triggerRecords = pc.inputs().get>("krtrigrec"); + for (const auto& cls : cluster) { + krCluster.push_back(cls); + } + for (const auto& trig : triggerRecords) { + krTrigRec.push_back(trig); + } + mTreeOut->Fill(); + krCluster.clear(); + krTrigRec.clear(); + if (mAutoSave > 0 && ++mTFCounter % mAutoSave == 0) { + writeToFile(); + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + if (mRunStopRequested) { + return; + } + LOG(info) << "End of stream received, closing output file"; + closeOutputFile(); + } + + private: + bool mRunStopRequested{false}; + bool mStoreMetaFile{false}; + bool mOutputFileCreated{false}; + int mAutoSave{0}; + uint64_t mTFCounter{0}; + std::string mOutputDir{"none"}; + std::string mMetaFileDir{"/dev/null"}; + std::string mHostName{}; + std::string mFileName{}; + std::unique_ptr mFileOut{}; + std::unique_ptr mTreeOut{}; + std::vector krCluster, *krClusterPtr{&krCluster}; + std::vector krTrigRec, *krTrigRecPtr{&krTrigRec}; + o2::framework::DataTakingContext mDataTakingContext; +}; + +framework::DataProcessorSpec getKrClusterWriterSpec() { + std::vector inputs; + inputs.emplace_back("krcluster", "TRD", "KRCLUSTER"); + inputs.emplace_back("krtrigrec", "TRD", "TRGKRCLS"); -o2::framework::DataProcessorSpec getKrClusterWriterSpec(); + return DataProcessorSpec{"kr-cluster-writer", + inputs, + Outputs{}, + AlgorithmSpec{adaptFromTask()}, + Options{ + {"output-dir", VariantType::String, "none", {"Output directory for data. Defaults to current working directory"}}, + {"meta-output-dir", VariantType::String, "/dev/null", {"metadata output directory, must exist (if not /dev/null)"}}, + {"autosave-interval", VariantType::Int, 0, {"Write output to file for every n-th TF. 0 means this feature is OFF"}}}}; +} } // end namespace trd } // end namespace o2 diff --git a/Detectors/TRD/workflow/io/src/KrClusterWriterSpec.cxx b/Detectors/TRD/workflow/io/src/KrClusterWriterSpec.cxx deleted file mode 100644 index 92fce34ada4a4..0000000000000 --- a/Detectors/TRD/workflow/io/src/KrClusterWriterSpec.cxx +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "Framework/DataProcessorSpec.h" -#include "DPLUtils/MakeRootTreeWriterSpec.h" -#include "TRDWorkflowIO/KrClusterWriterSpec.h" -#include "DataFormatsTRD/KrCluster.h" -#include "DataFormatsTRD/KrClusterTriggerRecord.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace trd -{ - -template -using BranchDefinition = framework::MakeRootTreeWriterSpec::BranchDefinition; - -o2::framework::DataProcessorSpec getKrClusterWriterSpec() -{ - - return framework::MakeRootTreeWriterSpec("TRDKrClWriter", - "trdkrclusters.root", - "krClusters", - BranchDefinition>{InputSpec{"clusters", "TRD", "KRCLUSTER"}, "KrCluster"}, - BranchDefinition>{InputSpec{"trigRecs", "TRD", "TRGKRCLS"}, "TriggerRecord"})(); -}; - -} // end namespace trd -} // end namespace o2 diff --git a/Detectors/TRD/workflow/src/KrClustererSpec.cxx b/Detectors/TRD/workflow/src/KrClustererSpec.cxx deleted file mode 100644 index 0cbacd08589b3..0000000000000 --- a/Detectors/TRD/workflow/src/KrClustererSpec.cxx +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file KrClustererSpec.cxx -/// \brief DPL device for running the TRD Krypton cluster finder -/// \author Ole Schmidt - -#include "TRDWorkflow/KrClustererSpec.h" -#include "TRDCalibration/KrClusterFinder.h" -#include "Framework/Task.h" -#include "Framework/ConfigParamRegistry.h" -#include "TStopwatch.h" -#include - -using namespace o2::framework; - -namespace o2 -{ -namespace trd -{ - -class TRDKrClustererDevice : public Task -{ - public: - TRDKrClustererDevice() = default; - ~TRDKrClustererDevice() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - void endOfStream(framework::EndOfStreamContext& ec) final; - - private: - o2::trd::KrClusterFinder mKrClFinder; -}; - -void TRDKrClustererDevice::init(InitContext& ic) -{ - mKrClFinder.init(); -} - -void TRDKrClustererDevice::run(ProcessingContext& pc) -{ - TStopwatch timer; - - const auto digits = pc.inputs().get>("digits"); - const auto triggerRecords = pc.inputs().get>("triggerRecords"); - - mKrClFinder.reset(); - mKrClFinder.setInput(digits, triggerRecords); - timer.Start(); - mKrClFinder.findClusters(); - timer.Stop(); - - LOGF(info, "TRD Krypton cluster finder total timing: Cpu: %.3e Real: %.3e s", timer.CpuTime(), timer.RealTime()); - LOGF(info, "Found %lu Kr clusters in %lu input trigger records.", mKrClFinder.getKrClusters().size(), triggerRecords.size()); - - pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "KRCLUSTER", 0, Lifetime::Timeframe}, mKrClFinder.getKrClusters()); - pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRGKRCLS", 0, Lifetime::Timeframe}, mKrClFinder.getKrTrigRecs()); -} - -void TRDKrClustererDevice::endOfStream(EndOfStreamContext& ec) -{ - LOG(info) << "Done with the cluster finding (EoS received)"; -} - -DataProcessorSpec getKrClustererSpec() -{ - std::vector inputs; - inputs.emplace_back("digits", ConcreteDataTypeMatcher{o2::header::gDataOriginTRD, "DIGITS"}, Lifetime::Timeframe); - inputs.emplace_back("triggerRecords", ConcreteDataTypeMatcher{o2::header::gDataOriginTRD, "TRKTRGRD"}, Lifetime::Timeframe); - std::vector outputs; - outputs.emplace_back(o2::header::gDataOriginTRD, "KRCLUSTER", 0, Lifetime::Timeframe); - outputs.emplace_back(o2::header::gDataOriginTRD, "TRGKRCLS", 0, Lifetime::Timeframe); - - return DataProcessorSpec{ - "trd-kr-clusterer", - inputs, - outputs, - AlgorithmSpec{adaptFromTask()}, - Options{}}; -} - -} // namespace trd -} // namespace o2 From 085907d37917e730a9ee8d0402315ca21c49713e Mon Sep 17 00:00:00 2001 From: amorsch Date: Thu, 19 Oct 2023 20:04:40 +0200 Subject: [PATCH 305/324] hooks and configuration for POWHEG --- Generators/share/egconfig/pythia8_powheg.cfg | 79 ++++++++++++++++++++ Generators/src/GeneratorFactory.cxx | 5 ++ Generators/src/GeneratorPythia8.cxx | 26 ++++++- 3 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 Generators/share/egconfig/pythia8_powheg.cfg diff --git a/Generators/share/egconfig/pythia8_powheg.cfg b/Generators/share/egconfig/pythia8_powheg.cfg new file mode 100644 index 0000000000000..ed41ab695bb48 --- /dev/null +++ b/Generators/share/egconfig/pythia8_powheg.cfg @@ -0,0 +1,79 @@ +Beams:eCM 13000. # GeV +### processes +Next:numberShowLHA = 1 +Next:numberShowInfo = 1 +Next:numberShowProcess = 1 +Next:numberShowEvent = 1 +Main:timesAllowErrors = 10 +! Read LHE file from POWHEG +Beams:frameType = 4 +Beams:LHEF = powheg.lhe + +! Number of outgoing particles of POWHEG Born level process +! (i.e. not counting additional POWHEG radiation) +POWHEG:nFinal = 2 + +! How vetoing is performed: +! 0 - No vetoing is performed (userhooks are not loaded) +! 1 - Showers are started at the kinematical limit. +! Emissions are vetoed if pTemt > pThard. +! See also POWHEG:vetoCount below +POWHEG:veto = 1 + +! After 'vetoCount' accepted emissions in a row, no more emissions +! are checked. 'vetoCount = 0' means that no emissions are checked. +! Use a very large value, e.g. 10000, to have all emissions checked. +POWHEG:vetoCount = 3 + +! Selection of pThard (note, for events where there is no +! radiation, pThard is always set to be SCALUP): +! 0 - pThard = SCALUP (of the LHA/LHEF standard) +! 1 - the pT of the POWHEG emission is tested against all other +! incoming and outgoing partons, with the minimal value chosen +! 2 - the pT of all final-state partons is tested against all other +! incoming and outgoing partons, with the minimal value chosen +POWHEG:pThard = 2 + +! Selection of pTemt: +! 0 - pTemt is pT of the emitted parton w.r.t. radiating parton +! 1 - pT of the emission is checked against all incoming and outgoing +! partons. pTemt is set to the minimum of these values +! 2 - the pT of all final-state partons is tested against all other +! incoming and outgoing partons, with the minimal value chosen +! WARNING: the choice here can give significant variations in the final +! distributions, notably in the tail to large pT values. +POWHEG:pTemt = 0 + +! Selection of emitted parton for FSR +! 0 - Pythia definition of emitted +! 1 - Pythia definition of radiator +! 2 - Random selection of emitted or radiator +! 3 - Both are emitted and radiator are tried +POWHEG:emitted = 0 + +! pT definitions +! 0 - POWHEG ISR pT definition is used for both ISR and FSR +! 1 - POWHEG ISR pT and FSR d_ij definitions +! 2 - Pythia definitions +POWHEG:pTdef = 1 + +! MPI vetoing +! 0 - No MPI vetoing is done +! 1 - When there is no radiation, MPIs with a scale above pT_1 are vetoed, +! else MPIs with a scale above (pT_1 + pT_2 + pT_3) / 2 are vetoed +POWHEG:MPIveto = 0 +! Note that POWHEG:MPIveto = 1 should be combined with +! MultipartonInteractions:pTmaxMatch = 2 +! which here is taken care of in main31.cc. + +! QED vetoing +! 0 - No QED vetoing is done for pTemt > 0. +! 1 - QED vetoing is done for pTemt > 0. +! 2 - QED vetoing is done for pTemt > 0. If a photon is found +! with pT>pThard from the Born level process, the event is accepted +! and no further veto of this event is allowed (for any pTemt). +POWHEG:QEDveto = 2 + +### decays +ParticleDecays:limitTau0 on +ParticleDecays:tau0Max 10. diff --git a/Generators/src/GeneratorFactory.cxx b/Generators/src/GeneratorFactory.cxx index ae47ede14f4a3..abe22a6fe75fe 100644 --- a/Generators/src/GeneratorFactory.cxx +++ b/Generators/src/GeneratorFactory.cxx @@ -216,6 +216,11 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair auto py8config = std::string(std::getenv("O2_ROOT")) + "/share/Generators/egconfig/pythia8_hi.cfg"; auto py8 = makePythia8Gen(py8config); primGen->AddGenerator(py8); + } else if (genconfig.compare("pythia8powheg") == 0) { + // pythia8 with powheg + auto py8config = std::string(std::getenv("O2_ROOT")) + "/share/Generators/egconfig/pythia8_powheg.cfg"; + auto py8 = makePythia8Gen(py8config); + primGen->AddGenerator(py8); #endif } else if (genconfig.compare("external") == 0 || genconfig.compare("extgen") == 0) { // external generator via configuration macro diff --git a/Generators/src/GeneratorPythia8.cxx b/Generators/src/GeneratorPythia8.cxx index 13c17003ee612..aba74f7ce61ee 100644 --- a/Generators/src/GeneratorPythia8.cxx +++ b/Generators/src/GeneratorPythia8.cxx @@ -22,6 +22,7 @@ #include "SimulationDataFormat/MCGenProperties.h" #include "SimulationDataFormat/ParticleStatus.h" #include "Pythia8/HIUserHooks.h" +#include "Pythia8Plugins/PowhegHooks.h" #include "TSystem.h" #include "ZDCBase/FragmentParam.h" @@ -107,7 +108,28 @@ Bool_t GeneratorPythia8::Init() /** inhibit hadron decays **/ mPythia.readString("HadronLevel:Decay off"); #endif - + if (mPythia.settings.mode("Beams:frameType") == 4) { + // Hook for POWHEG + // Read in key POWHEG merging settings + int vetoMode = mPythia.settings.mode("POWHEG:veto"); + int MPIvetoMode = mPythia.settings.mode("POWHEG:MPIveto"); + bool loadHooks = (vetoMode > 0 || MPIvetoMode > 0); + // Add in user hooks for shower vetoing + std::shared_ptr powhegHooks; + if (loadHooks) { + // Set ISR and FSR to start at the kinematical limit + if (vetoMode > 0) { + mPythia.readString("SpaceShower:pTmaxMatch = 2"); + mPythia.readString("TimeShower:pTmaxMatch = 2"); + } + // Set MPI to start at the kinematical limit + if (MPIvetoMode > 0) { + mPythia.readString("MultipartonInteractions:pTmaxMatch = 2"); + } + powhegHooks = std::make_shared(); + mPythia.setUserHooksPtr((Pythia8::UserHooksPtr)powhegHooks); + } + } /** initialise **/ if (!mPythia.init()) { LOG(fatal) << "Failed to init \'Pythia8\': init returned with error"; @@ -123,8 +145,6 @@ Bool_t GeneratorPythia8::Init() Bool_t GeneratorPythia8::generateEvent() { - /** generate event **/ - /** generate event **/ if (!mPythia.next()) { return false; From c5ca3854f80f2fdfbe94b45a3a4090060f004055 Mon Sep 17 00:00:00 2001 From: Matteo Concas Date: Fri, 20 Oct 2023 11:36:40 +0200 Subject: [PATCH 306/324] ITS tracker: Reserve output buffers (#12089) * ITS tracker: Reserve output buffers * Rerserve all possible buffers --- .../tracking/include/ITStracking/TimeFrame.h | 14 ++++++- Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx | 8 ++-- .../ITSMFT/ITS/workflow/src/TrackerSpec.cxx | 39 +++++++++---------- GPU/Workflow/src/GPUWorkflowITS.cxx | 35 ++++++++--------- 4 files changed, 51 insertions(+), 45 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h index 3b10e1d76f18c..914479602469b 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h @@ -166,7 +166,8 @@ class TimeFrame int getNumberOfClusters() const; int getNumberOfCells() const; int getNumberOfTracklets() const; - int getNumberOfTracks() const; + size_t getNumberOfTracks() const; + size_t getNumberOfUsedClusters() const; bool checkMemory(unsigned long max) { return getArtefactsMemory() < max; } unsigned long getArtefactsMemory(); @@ -610,7 +611,7 @@ inline int TimeFrame::getNumberOfTracklets() const return nTracklets; } -inline int TimeFrame::getNumberOfTracks() const +inline size_t TimeFrame::getNumberOfTracks() const { int nTracks = 0; for (auto& t : mTracks) { @@ -619,6 +620,15 @@ inline int TimeFrame::getNumberOfTracks() const return nTracks; } +inline size_t TimeFrame::getNumberOfUsedClusters() const +{ + size_t nClusters = 0; + for (auto& layer : mUsedClusters) { + nClusters += std::count(layer.begin(), layer.end(), true); + } + return nClusters; +} + } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx b/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx index 2a657866b8f76..60ae4163bfaaf 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx @@ -54,24 +54,24 @@ void Tracker::clustersToTracks(std::function logger, std::f total += evaluateTask(&Tracker::computeTracklets, "Tracklet finding", logger, iteration); logger(fmt::format("\t- Number of tracklets: {}", mTraits->getTFNumberOfTracklets())); if (!mTimeFrame->checkMemory(mTrkParams[iteration].MaxMemory)) { - error("Too much memory used during trackleting, check the detector status and/or the selections."); + error(fmt::format("Too much memory used during trackleting in iteration {}, check the detector status and/or the selections.", iteration)); break; } float trackletsPerCluster = mTraits->getTFNumberOfClusters() > 0 ? float(mTraits->getTFNumberOfTracklets()) / mTraits->getTFNumberOfClusters() : 0.f; if (trackletsPerCluster > mTrkParams[iteration].TrackletsPerClusterLimit) { - error(fmt::format("Too many tracklets per cluster ({}), check the detector status and/or the selections.", trackletsPerCluster)); + error(fmt::format("Too many tracklets per cluster ({}) in iteration {}, check the detector status and/or the selections.", trackletsPerCluster, iteration)); break; } total += evaluateTask(&Tracker::computeCells, "Cell finding", logger, iteration); logger(fmt::format("\t- Number of Cells: {}", mTraits->getTFNumberOfCells())); if (!mTimeFrame->checkMemory(mTrkParams[iteration].MaxMemory)) { - error("Too much memory used during cell finding, check the detector status and/or the selections."); + error(fmt::format("Too much memory used during cell finding in iteration {}, check the detector status and/or the selections.", iteration)); break; } float cellsPerCluster = mTraits->getTFNumberOfClusters() > 0 ? float(mTraits->getTFNumberOfCells()) / mTraits->getTFNumberOfClusters() : 0.f; if (cellsPerCluster > mTrkParams[iteration].CellsPerClusterLimit) { - error(fmt::format("Too many cells per cluster ({}), check the detector status and/or the selections.", cellsPerCluster)); + error(fmt::format("Too many cells per cluster ({}) in iteration {}, check the detector status and/or the selections.", cellsPerCluster, iteration)); break; } diff --git a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx index 91542a37ae2eb..6f6be501403ad 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx @@ -147,39 +147,35 @@ void TrackerDPL::run(ProcessingContext& pc) physTriggers = pc.inputs().get>("phystrig"); } - // code further down does assignment to the rofs and the altered object is used for output - // we therefore need a copy of the vector rather than an object created directly on the input data, - // the output vector however is created directly inside the message memory thus avoiding copy by - // snapshot auto rofsinput = pc.inputs().get>("ROframes"); auto& rofs = pc.outputs().make>(Output{"ITS", "ITSTrackROF", 0, Lifetime::Timeframe}, rofsinput.begin(), rofsinput.end()); - auto& irFrames = pc.outputs().make>(Output{"ITS", "IRFRAMES", 0, Lifetime::Timeframe}); - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); // RS: this should come from CCDB + + irFrames.reserve(rofs.size()); int nBCPerTF = alpParams.roFrameLengthInBC; - LOG(info) << "ITSTracker pulled " << compClusters.size() << " clusters, " << rofs.size() << " RO frames"; + LOGP(info, "ITSTracker pulled {} clusters, {} RO frames", compClusters.size(), rofs.size()); const dataformats::MCTruthContainer* labels = nullptr; gsl::span mc2rofs; if (mIsMC) { labels = pc.inputs().get*>("itsmclabels").release(); - // get the array as read-only span, a snapshot is send forward - mc2rofs = pc.inputs().get>("ITSMC2ROframes"); + // get the array as read-only span, a snapshot is sent forward + pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0, Lifetime::Timeframe}, pc.inputs().get>("ITSMC2ROframes")); LOG(info) << labels->getIndexedSize() << " MC label objects , in " << mc2rofs.size() << " MC events"; } auto& allClusIdx = pc.outputs().make>(Output{"ITS", "TRACKCLSID", 0, Lifetime::Timeframe}); - std::vector trackLabels; - std::vector verticesLabels; auto& allTracks = pc.outputs().make>(Output{"ITS", "TRACKS", 0, Lifetime::Timeframe}); - std::vector allTrackLabels; - std::vector allVerticesLabels; - auto& vertROFvec = pc.outputs().make>(Output{"ITS", "VERTICESROF", 0, Lifetime::Timeframe}); auto& vertices = pc.outputs().make>(Output{"ITS", "VERTICES", 0, Lifetime::Timeframe}); + // MC + static pmr::vector dummyMCLabTracks, dummyMCLabVerts; + auto& allTrackLabels = mIsMC ? pc.outputs().make>(Output{"ITS", "TRACKSMCTR", 0, Lifetime::Timeframe}) : dummyMCLabTracks; + auto& allVerticesLabels = mIsMC ? pc.outputs().make>(Output{"ITS", "VERTICESMCTR", 0, Lifetime::Timeframe}) : dummyMCLabVerts; + std::uint32_t roFrame = 0; bool continuous = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS); @@ -210,6 +206,7 @@ void TrackerDPL::run(ProcessingContext& pc) mTimeFrame->setMultiplicityCutMask(processingMask); float vertexerElapsedTime{0.f}; if (mRunVertexer) { + vertROFvec.reserve(rofs.size()); // Run seeding vertexer vertexerElapsedTime = mVertexer->clustersToVertices(logger); } else { // cosmics @@ -233,6 +230,7 @@ void TrackerDPL::run(ProcessingContext& pc) vertices.push_back(v); if (mIsMC) { auto vLabels = mTimeFrame->getPrimaryVerticesLabels(iRof)[iV]; + allVerticesLabels.reserve(allVerticesLabels.size() + vLabels.size()); std::copy(vLabels.begin(), vLabels.end(), std::back_inserter(allVerticesLabels)); } } @@ -269,6 +267,10 @@ void TrackerDPL::run(ProcessingContext& pc) mTimeFrame->setMultiplicityCutMask(processingMask); // Run CA tracker mTracker->clustersToTracks(logger, errorLogger); + size_t totTracks{mTimeFrame->getNumberOfTracks()}, totClusIDs{mTimeFrame->getNumberOfUsedClusters()}; + allTracks.reserve(totTracks); + allClusIdx.reserve(totClusIDs); + if (mTimeFrame->hasBogusClusters()) { LOG(warning) << fmt::format(" - The processed timeframe had {} clusters with wild z coordinates, check the dictionaries", mTimeFrame->hasBogusClusters()); } @@ -276,7 +278,6 @@ void TrackerDPL::run(ProcessingContext& pc) for (unsigned int iROF{0}; iROF < rofs.size(); ++iROF) { auto& rof{rofs[iROF]}; auto& tracks = mTimeFrame->getTracks(iROF); - trackLabels = mTimeFrame->getTracksLabel(iROF); auto number{tracks.size()}; auto first{allTracks.size()}; int offset = -rof.getFirstEntry(); // cluster entry!!! @@ -286,8 +287,8 @@ void TrackerDPL::run(ProcessingContext& pc) if (processingMask[iROF]) { irFrames.emplace_back(rof.getBCData(), rof.getBCData() + nBCPerTF - 1).info = tracks.size(); } - - std::copy(trackLabels.begin(), trackLabels.end(), std::back_inserter(allTrackLabels)); + allTrackLabels.reserve(mTimeFrame->getTracksLabel(iROF).size()); // should be 0 if not MC + std::copy(mTimeFrame->getTracksLabel(iROF).begin(), mTimeFrame->getTracksLabel(iROF).end(), std::back_inserter(allTrackLabels)); // Some conversions that needs to be moved in the tracker internals for (unsigned int iTrk{0}; iTrk < tracks.size(); ++iTrk) { auto& trc{tracks[iTrk]}; @@ -309,10 +310,6 @@ void TrackerDPL::run(ProcessingContext& pc) if (mIsMC) { LOGP(info, "ITSTracker pushed {} track labels", allTrackLabels.size()); LOGP(info, "ITSTracker pushed {} vertex labels", allVerticesLabels.size()); - - pc.outputs().snapshot(Output{"ITS", "TRACKSMCTR", 0, Lifetime::Timeframe}, allTrackLabels); - pc.outputs().snapshot(Output{"ITS", "VERTICESMCTR", 0, Lifetime::Timeframe}, allVerticesLabels); - pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0, Lifetime::Timeframe}, mc2rofs); } } mTimer.Stop(); diff --git a/GPU/Workflow/src/GPUWorkflowITS.cxx b/GPU/Workflow/src/GPUWorkflowITS.cxx index 876561d381594..e3b66ce74a118 100644 --- a/GPU/Workflow/src/GPUWorkflowITS.cxx +++ b/GPU/Workflow/src/GPUWorkflowITS.cxx @@ -132,14 +132,11 @@ int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) physTriggers = pc.inputs().get>("phystrig"); } - // code further down does assignment to the rofs and the altered object is used for output - // we therefore need a copy of the vector rather than an object created directly on the input data, - // the output vector however is created directly inside the message memory thus avoiding copy by - // snapshot auto rofsinput = pc.inputs().get>("ROframes"); - auto& rofs = pc.outputs().make>(Output{"ITS", "ITSTrackROF", 0, Lifetime::Timeframe}, rofsinput.begin(), rofsinput.end()); + auto& rofs = pc.outputs().make>(Output{"ITS", "ITSTrackROF", 0, Lifetime::Timeframe}, rofsinput.begin(), rofsinput.end()); auto& irFrames = pc.outputs().make>(Output{"ITS", "IRFRAMES", 0, Lifetime::Timeframe}); + irFrames.reserve(rofs.size()); const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); // RS: this should come from CCDB int nBCPerTF = alpParams.roFrameLengthInBC; @@ -150,21 +147,21 @@ int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) gsl::span mc2rofs; if (mSpecConfig.processMC) { labels = pc.inputs().get*>("itsmclabels").release(); - // get the array as read-only span, a snapshot is send forward - mc2rofs = pc.inputs().get>("ITSMC2ROframes"); + // get the array as read-only span, a snapshot is sent forward + pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0, Lifetime::Timeframe}, pc.inputs().get>("ITSMC2ROframes")); LOG(info) << labels->getIndexedSize() << " MC label objects , in " << mc2rofs.size() << " MC events"; } auto& allClusIdx = pc.outputs().make>(Output{"ITS", "TRACKCLSID", 0, Lifetime::Timeframe}); - std::vector trackLabels; - std::vector verticesLabels; auto& allTracks = pc.outputs().make>(Output{"ITS", "TRACKS", 0, Lifetime::Timeframe}); - std::vector allTrackLabels; - std::vector allVerticesLabels; - auto& vertROFvec = pc.outputs().make>(Output{"ITS", "VERTICESROF", 0, Lifetime::Timeframe}); auto& vertices = pc.outputs().make>(Output{"ITS", "VERTICES", 0, Lifetime::Timeframe}); + // MC + static pmr::vector dummyMCLabTracks, dummyMCLabVerts; + auto& allTrackLabels = mSpecConfig.processMC ? pc.outputs().make>(Output{"ITS", "TRACKSMCTR", 0, Lifetime::Timeframe}) : dummyMCLabTracks; + auto& allVerticesLabels = mSpecConfig.processMC ? pc.outputs().make>(Output{"ITS", "VERTICESMCTR", 0, Lifetime::Timeframe}) : dummyMCLabVerts; + std::uint32_t roFrame = 0; bool continuous = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS); @@ -196,6 +193,7 @@ int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) float vertexerElapsedTime{0.f}; if (mITSRunVertexer) { // Run seeding vertexer + vertROFvec.reserve(rofs.size()); vertexerElapsedTime = mITSVertexer->clustersToVertices(logger); } else { // cosmics mITSTimeFrame->resetRofPV(); @@ -218,6 +216,7 @@ int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) vertices.push_back(v); if (mSpecConfig.processMC) { auto vLabels = mITSTimeFrame->getPrimaryVerticesLabels(iRof)[iV]; + allVerticesLabels.reserve(allVerticesLabels.size() + vLabels.size()); std::copy(vLabels.begin(), vLabels.end(), std::back_inserter(allVerticesLabels)); } } @@ -254,6 +253,10 @@ int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) mITSTimeFrame->setMultiplicityCutMask(processingMask); // Run CA tracker mITSTracker->clustersToTracks(logger, errorLogger); + size_t totTracks{mITSTimeFrame->getNumberOfTracks()}, totClusIDs{mITSTimeFrame->getNumberOfUsedClusters()}; + allTracks.reserve(totTracks); + allClusIdx.reserve(totClusIDs); + if (mITSTimeFrame->hasBogusClusters()) { LOG(warning) << fmt::format(" - The processed timeframe had {} clusters with wild z coordinates, check the dictionaries", mITSTimeFrame->hasBogusClusters()); } @@ -261,7 +264,6 @@ int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) for (unsigned int iROF{0}; iROF < rofs.size(); ++iROF) { auto& rof{rofs[iROF]}; auto& tracks = mITSTimeFrame->getTracks(iROF); - trackLabels = mITSTimeFrame->getTracksLabel(iROF); auto number{tracks.size()}; auto first{allTracks.size()}; int offset = -rof.getFirstEntry(); // cluster entry!!! @@ -272,7 +274,8 @@ int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) irFrames.emplace_back(rof.getBCData(), rof.getBCData() + nBCPerTF - 1).info = tracks.size(); } - std::copy(trackLabels.begin(), trackLabels.end(), std::back_inserter(allTrackLabels)); + allTrackLabels.reserve(mITSTimeFrame->getTracksLabel(iROF).size()); // should be 0 if not MC + std::copy(mITSTimeFrame->getTracksLabel(iROF).begin(), mITSTimeFrame->getTracksLabel(iROF).end(), std::back_inserter(allTrackLabels)); // Some conversions that needs to be moved in the tracker internals for (unsigned int iTrk{0}; iTrk < tracks.size(); ++iTrk) { auto& trc{tracks[iTrk]}; @@ -293,10 +296,6 @@ int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) if (mSpecConfig.processMC) { LOGP(info, "ITSTracker pushed {} track labels", allTrackLabels.size()); LOGP(info, "ITSTracker pushed {} vertex labels", allVerticesLabels.size()); - - pc.outputs().snapshot(Output{"ITS", "TRACKSMCTR", 0, Lifetime::Timeframe}, allTrackLabels); - pc.outputs().snapshot(Output{"ITS", "VERTICESMCTR", 0, Lifetime::Timeframe}, allVerticesLabels); - pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0, Lifetime::Timeframe}, mc2rofs); } } return 0; From ba4e300af788660552c4b0d04a515a903ca06b64 Mon Sep 17 00:00:00 2001 From: iravasen Date: Fri, 20 Oct 2023 11:39:17 +0200 Subject: [PATCH 307/324] ITS: process hits from different MEBs + bug fix for scurve dump (#12110) * added possibility to process hits from different MEBs + bug fix for s-curves dump * reverted unwanted change --- .../ITSWorkflow/ThresholdCalibratorSpec.h | 9 ++- .../workflow/src/ThresholdCalibratorSpec.cxx | 60 +++++++++++++------ 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h index bd08859a0fe3a..07761f20fd872 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h @@ -63,6 +63,7 @@ namespace its { int nInj = 50; +int nInjScaled = 50; // different from nInj only if mMeb > 0, in this case it is nInj/3. // List of the possible run types for reference enum RunTypes { @@ -72,6 +73,7 @@ enum RunTypes { THR_SCAN_SHORT_2_10HZ = 18, THR_SCAN_SHORT_100HZ = 19, THR_SCAN_SHORT_200HZ = 20, + THR_SCAN_SHORT_150INJ = 55, VCASN150 = 23, VCASN100 = 10, VCASN100_100HZ = 21, @@ -164,7 +166,7 @@ class ITSThresholdCalibrator : public Task short int vRow[N_COL]; short int vThreshold[N_COL]; bool vSuccess[N_COL]; - unsigned char vNoise[N_COL]; + float vNoise[N_COL]; unsigned char vPoints[N_COL]; short int vMixData[N_COL]; unsigned char vCharge[N_COL]; @@ -288,6 +290,7 @@ class ITSThresholdCalibrator : public Task // parameters for manual mode: if run type is not among the listed one bool isManualMode = false; bool saveTree; + bool scaleNinj = false; short int manualMin, manualMin2 = 0; short int manualMax, manualMax2 = 0; short int manualStep = 1, manualStep2 = 1; @@ -306,6 +309,7 @@ class ITSThresholdCalibrator : public Task int maxDumpS = -1; // maximum number of s-curves to be dumped, default -1 = dump all std::string chipDumpS = ""; // list of comma-separated O2 chipIDs to be dumped, default is empty = dump all int dumpCounterS[24120] = {0}; // count dumps for every chip + int countCdw[24120] = {0}; // count how many CDWs have been processed with the maximum charge injected: usefull for s-curve dump when hits do not arrive in order TFile* fileDumpS; // file where to store the s-curves on disk std::vector chipDumpList; // vector of chips to dump @@ -317,6 +321,9 @@ class ITSThresholdCalibrator : public Task bool mCalculate2DParams = true; int chargeA = 0; int chargeB = 0; + + // Variable to select from which MEB to consider the hits. + int mMeb = -1; }; // Create a processor spec diff --git a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx index b45614d64c268..391ef5c38677c 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx @@ -28,13 +28,13 @@ namespace its // Define error function for ROOT fitting double erf(double* xx, double* par) { - return (nInj / 2) * TMath::Erf((xx[0] - par[0]) / (sqrt(2) * par[1])) + (nInj / 2); + return (nInjScaled / 2) * TMath::Erf((xx[0] - par[0]) / (sqrt(2) * par[1])) + (nInjScaled / 2); } // ITHR erf is reversed double erf_ithr(double* xx, double* par) { - return (nInj / 2) * (1 - TMath::Erf((xx[0] - par[0]) / (sqrt(2) * par[1]))); + return (nInjScaled / 2) * (1 - TMath::Erf((xx[0] - par[0]) / (sqrt(2) * par[1]))); } ////////////////////////////////////////////////////////////////////////////// @@ -183,6 +183,9 @@ void ITSThresholdCalibrator::init(InitContext& ic) // this is not mandatory since it's 5 by default manualStrobeWindow = ic.options().get("manual-strobewindow"); + + // Flag to scale the number of injections by 3 in case --meb-select is used + scaleNinj = ic.options().get("scale-ninj"); } // Flag to enable the analysis of CRU_ITS data @@ -190,6 +193,7 @@ void ITSThresholdCalibrator::init(InitContext& ic) // Number of injections nInj = ic.options().get("ninj"); + nInjScaled = nInj; // Flag to enable the call of the finalize() method at end of stream isFinalizeEos = ic.options().get("finalize-at-eos"); @@ -242,6 +246,12 @@ void ITSThresholdCalibrator::init(InitContext& ic) } } + // Variable to select from which multi-event buffer select the hits + mMeb = ic.options().get("meb-select"); + if (mMeb > 2) { + LOG(error) << "MEB cannot be greater than 2. Please check your command line."; + } + return; } @@ -357,7 +367,7 @@ void ITSThresholdCalibrator::initThresholdTree(bool recreate /*=true*/) this->mThresholdTree->Branch("row", &vRow, "vRow[1024]/S"); if (this->mScanType == 'T') { this->mThresholdTree->Branch("thr", &vThreshold, "vThreshold[1024]/S"); - this->mThresholdTree->Branch("noise", &vNoise, "vNoise[1024]/b"); + this->mThresholdTree->Branch("noise", &vNoise, "vNoise[1024]/F"); this->mThresholdTree->Branch("spoints", &vPoints, "vPoints[1024]/b"); this->mThresholdTree->Branch("success", &vSuccess, "vSuccess[1024]/O"); } else if (mScanType == 'D' || mScanType == 'A') { // this->mScanType == 'D' and this->mScanType == 'A' @@ -381,7 +391,7 @@ void ITSThresholdCalibrator::initThresholdTree(bool recreate /*=true*/) this->mThresholdTree->Branch("vresetd", &vMixData, "vMixData[1024]/S"); } else if (mScanType == 'r') { this->mThresholdTree->Branch("thr", &vThreshold, "vThreshold[1024]/S"); - this->mThresholdTree->Branch("noise", &vNoise, "vNoise[1024]/b"); + this->mThresholdTree->Branch("noise", &vNoise, "vNoise[1024]/F"); this->mThresholdTree->Branch("success", &vSuccess, "vSuccess[1024]/O"); this->mThresholdTree->Branch("vresetd", &vMixData, "vMixData[1024]/S"); } @@ -417,7 +427,7 @@ bool ITSThresholdCalibrator::findUpperLower( } for (int i = upper; i > 0; i--) { int comp = mScanType != 'r' ? data[iloop2][i] : data[i][iloop2]; - if (comp >= nInj) { + if (comp >= nInjScaled) { lower = i; break; } @@ -427,7 +437,7 @@ bool ITSThresholdCalibrator::findUpperLower( for (int i = 0; i < NPoints; i++) { int comp = mScanType != 'r' ? data[iloop2][i] : data[i][iloop2]; - if (comp >= nInj) { + if (comp >= nInjScaled) { upper = i; break; } @@ -611,7 +621,7 @@ bool ITSThresholdCalibrator::findThresholdHitcounting( for (unsigned short int i = 0; i < NPoints; i++) { numberOfHits += (mScanType != 'r') ? data[iloop2][i] : data[i][iloop2]; int comp = (mScanType != 'r') ? data[iloop2][i] : data[i][iloop2]; - if (!is50 && comp == nInj) { + if (!is50 && comp == nInjScaled) { is50 = true; } } @@ -625,11 +635,11 @@ bool ITSThresholdCalibrator::findThresholdHitcounting( } if (this->mScanType == 'T') { - thresh = this->mX[N_RANGE - 1] - numberOfHits / float(nInj); + thresh = this->mX[N_RANGE - 1] - numberOfHits / float(nInjScaled); } else if (this->mScanType == 'V') { - thresh = (this->mX[N_RANGE - 1] * nInj - numberOfHits) / float(nInj); + thresh = (this->mX[N_RANGE - 1] * nInjScaled - numberOfHits) / float(nInjScaled); } else if (this->mScanType == 'I') { - thresh = (numberOfHits + nInj * this->mX[0]) / float(nInj); + thresh = (numberOfHits + nInjScaled * this->mX[0]) / float(nInjScaled); } else { LOG(error) << "Unexpected runtype encountered in findThresholdHitcounting()"; return false; @@ -748,7 +758,7 @@ void ITSThresholdCalibrator::extractThresholdRow(const short int& chipID, const vChipid[col_i] = chipID; vRow[col_i] = row; vThreshold[col_i] = (mScanType == 'T' || mScanType == 'r') ? (short int)(thresh * 10.) : (short int)(thresh); - vNoise[col_i] = (unsigned char)(noise * 10.); // always factor 10 also for ITHR/VCASN to not have all zeros + vNoise[col_i] = (float)(noise * 10.); // always factor 10 also for ITHR/VCASN to not have all zeros vSuccess[col_i] = success; vPoints[col_i] = spoints > 0 ? (unsigned char)(spoints) : 0; @@ -904,7 +914,7 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) this->mCheckExactRow = true; } else if (runtype == THR_SCAN_SHORT || runtype == THR_SCAN_SHORT_100HZ || - runtype == THR_SCAN_SHORT_200HZ || runtype == THR_SCAN_SHORT_33 || runtype == THR_SCAN_SHORT_2_10HZ) { + runtype == THR_SCAN_SHORT_200HZ || runtype == THR_SCAN_SHORT_33 || runtype == THR_SCAN_SHORT_2_10HZ || runtype == THR_SCAN_SHORT_150INJ) { // threshold_scan_short -- just extract thresholds for each pixel and write to TTree // 10 rows per chip this->mScanType = 'T'; @@ -913,7 +923,12 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) this->mMax = 50; this->N_RANGE = 51; this->mCheckExactRow = true; - + if (runtype == THR_SCAN_SHORT_150INJ) { + nInj = 150; + if (mMeb >= 0) { + nInjScaled = nInj / 3; + } + } } else if (runtype == VCASN150 || runtype == VCASN100 || runtype == VCASN100_100HZ || runtype == VCASN130 || runtype == VCASNBB) { // VCASN tuning for different target thresholds // Store average VCASN for each chip into CCDB @@ -1007,7 +1022,7 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) this->initThresholdTree(); } else { // No other run type recognized by this workflow - LOG(warning) << "Runtype " << runtype << " not recognized by calibration workflow."; + LOG(error) << "Runtype " << runtype << " not recognized by calibration workflow (ignore if you are in manual mode)"; if (isManualMode) { LOG(info) << "Entering manual mode: be sure to have set all parameters correctly"; this->mScanType = manualScanType[0]; @@ -1025,6 +1040,9 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) } this->mFitType = (mScanType == 'D' || mScanType == 'A' || mScanType == 'P' || mScanType == 'p') ? NO_FIT : mFitType; this->mCheckExactRow = (mScanType == 'D' || mScanType == 'A') ? false : true; + if (scaleNinj) { + nInjScaled = nInj / 3; + } } else { throw runtype; } @@ -1062,7 +1080,7 @@ bool ITSThresholdCalibrator::isScanFinished(const short int& chipID, const short short int chg = (mScanType == 'I' || mScanType == 'D' || mScanType == 'A') ? 0 : (N_RANGE - 1); // check 2 pixels in case one of them is dead - return ((this->mPixelHits[chipID][row][col][0][chg] >= nInj || this->mPixelHits[chipID][row][col + 100][0][chg] >= nInj) && (!mCheckCw || cwcnt == nInj - 1)); + return ((this->mPixelHits[chipID][row][col][0][chg] >= nInjScaled || this->mPixelHits[chipID][row][col + 100][0][chg] >= nInjScaled) && (!mCheckCw || cwcnt == nInj - 1)); } ////////////////////////////////////////////////////////////////////////////// @@ -1429,7 +1447,7 @@ void ITSThresholdCalibrator::run(ProcessingContext& pc) continue; } - if (!mChipsForbRows[chipID] && (!mCheckExactRow || d.getRow() == row)) { // row has NOT to be forbidden and we ignore hits coming from other rows (potential masking issue on chip) + if (!mChipsForbRows[chipID] && (!mCheckExactRow || d.getRow() == row) && (mMeb < 0 || cwcnt % 3 == mMeb)) { // row has NOT to be forbidden and we ignore hits coming from other rows (potential masking issue on chip) // Increment the number of counts for this pixel this->mPixelHits[chipID][d.getRow()][col][chgPoint][loopPoint]++; } @@ -1450,7 +1468,10 @@ void ITSThresholdCalibrator::run(ProcessingContext& pc) if (isDumpS) { auto fndVal = std::find(chipDumpList.begin(), chipDumpList.end(), chipID); int checkR = (mScanType == 'I') ? mMin : mMax; - passCondition = (cwcnt == nInj - 1) && (loopval == checkR) && (fndVal != chipDumpList.end() || !chipDumpList.size()); // in this way we dump any s-curve, bad and good + if (loopval == checkR) { + countCdw[chipID]++; + } + passCondition = (countCdw[chipID] == nInj) && (loopval == checkR) && (fndVal != chipDumpList.end() || !chipDumpList.size()); // in this way we dump any s-curve, bad and good if (mVerboseOutput) { LOG(info) << "Loopval: " << loopval << " counter: " << cwcnt << " checkR: " << checkR << " chipID: " << chipID << " pass: " << passCondition; } @@ -1467,6 +1488,7 @@ void ITSThresholdCalibrator::run(ProcessingContext& pc) if (mScanType != 'D' && mScanType != 'A' && mScanType != 'P' && mScanType != 'p' && mScanType != 'R' && mScanType != 'r' && passCondition) { // for D,A,P we do it at the end in finalize() this->extractAndUpdate(chipID, row); + countCdw[chipID] = 0; // remove entry for this row whose scan is completed mPixelHits[chipID].erase(row); mForbiddenRows[chipID].push_back(row); // due to the loose cut in isScanFinished, extra hits may come for this deleted row. In this way the row is ignored afterwards @@ -1982,6 +2004,7 @@ DataProcessorSpec getITSThresholdCalibratorSpec(const ITSCalibInpConf& inpConf) {"manual-scantype", VariantType::String, "T", {"scan type, can be D, T, I, V, P, p: use only in manual mode"}}, {"manual-strobewindow", VariantType::Int, 5, {"strobe duration in clock cycles, default is 5 = 125 ns: use only in manual mode"}}, {"save-tree", VariantType::Bool, false, {"Flag to save ROOT tree on disk: use only in manual mode"}}, + {"scale-ninj", VariantType::Bool, false, {"Flag to activate the scale of the number of injects to be used to count hits from specific MEBs: use only in manual mode and in combination with --meb-select"}}, {"enable-mpv", VariantType::Bool, false, {"Flag to enable calculation of most-probable value in vcasn/ithr scans"}}, {"enable-cru-its", VariantType::Bool, false, {"Flag to enable the analysis of raw data on disk produced by CRU_ITS IB commissioning tools"}}, {"ninj", VariantType::Int, 50, {"Number of injections per change, default is 50"}}, @@ -1991,7 +2014,8 @@ DataProcessorSpec getITSThresholdCalibratorSpec(const ITSCalibInpConf& inpConf) {"calculate-slope", VariantType::Bool, false, {"For Pulse Shape 2D: if enabled it calculate the slope of the charge vs strobe delay trend for each pixel and fill it in the output tree"}}, {"finalize-at-eos", VariantType::Bool, false, {"Call the finalize() method at the end of stream: to be used in case end-of-run flags are not available so to force calculations at end of run"}}, {"charge-a", VariantType::Int, 0, {"To use with --calculate-slope, it defines the charge (in DAC) for the 1st point used for the slope calculation"}}, - {"charge-b", VariantType::Int, 0, {"To use with --calculate-slope, it defines the charge (in DAC) for the 2nd point used for the slope calculation"}}}}; + {"charge-b", VariantType::Int, 0, {"To use with --calculate-slope, it defines the charge (in DAC) for the 2nd point used for the slope calculation"}}, + {"meb-select", VariantType::Int, -1, {"Select from which multi-event buffer consider the hits: 0,1 or 2"}}}}; } } // namespace its } // namespace o2 From b6c23299392cb1f49a0bd7420309ac23da00054e Mon Sep 17 00:00:00 2001 From: Chiara Zampolli Date: Thu, 19 Oct 2023 17:14:55 +0200 Subject: [PATCH 308/324] Adding also detector list --- .../testMacros/getRunParameters.cxx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Detectors/Calibration/testMacros/getRunParameters.cxx b/Detectors/Calibration/testMacros/getRunParameters.cxx index 605cc26b1a36f..5aa2dc4c60dc2 100644 --- a/Detectors/Calibration/testMacros/getRunParameters.cxx +++ b/Detectors/Calibration/testMacros/getRunParameters.cxx @@ -20,6 +20,7 @@ #include "DataFormatsCTP/Scalers.h" #include "DataFormatsCTP/Configuration.h" #include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPECSObject.h" #include "CommonTypes/Units.h" #include @@ -64,6 +65,17 @@ void writeBFieldToFile(float b) fclose(fptr); } +void writeDetListToFile(std::string detList) +{ + FILE* fptr = fopen("DetList.txt", "w"); + if (fptr == nullptr) { + LOGP(fatal, "ERROR: Could not open file to write detector list!"); + return; + } + fprintf(fptr, "%s", detList.c_str()); + fclose(fptr); +} + bool initOptionsAndParse(bpo::options_description& options, int argc, char* argv[], bpo::variables_map& vm) { options.add_options()( @@ -123,6 +135,20 @@ int main(int argc, char* argv[]) LOGP(info, "run {}: B field = {}", run, magFieldL3Curr); writeBFieldToFile((float)magFieldL3Curr); + // getting the detector list + LOGP(info, "Getting detector participating in the run"); + std::map metadataRun; + metadataRun["runNumber"] = std::to_string(run); + o2::parameters::GRPECSObject* ecsObj = ccdb_inst.getSpecific("GLO/Config/GRPECS", tsSOR, metadataRun); + std::string dets = ""; + for (int i = o2::detectors::DetID::First; i < o2::detectors::DetID::nDetectors; ++i) { + if (ecsObj->isDetReadOut(i)) { + dets = dets + o2::detectors::DetID::getName(i) + " "; + } + } + LOGP(info, "run {}: detectors in readout = {}", run, dets); + writeDetListToFile(dets); + LOGP(info, "Checking IR and duration"); if (run < 519041) { // LHC22c, d From 5e1301c062e9a1e4a24c78df07a2a1b81fbfb335 Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Thu, 19 Oct 2023 16:52:29 +0200 Subject: [PATCH 309/324] TOF: fetching GRPECS for correct number of orbits per TF --- Detectors/TOF/workflow/src/TOFMergeIntegrateClusterSpec.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/TOF/workflow/src/TOFMergeIntegrateClusterSpec.cxx b/Detectors/TOF/workflow/src/TOFMergeIntegrateClusterSpec.cxx index e2066461cc236..1a609df1c5212 100644 --- a/Detectors/TOF/workflow/src/TOFMergeIntegrateClusterSpec.cxx +++ b/Detectors/TOF/workflow/src/TOFMergeIntegrateClusterSpec.cxx @@ -159,7 +159,7 @@ o2::framework::DataProcessorSpec getTOFMergeIntegrateClusterSpec() inputs.emplace_back("itofcq", o2::header::gDataOriginTOF, "ITOFCQ", 0, Lifetime::Sporadic); auto ccdbRequest = std::make_shared(true, // orbitResetTime - false, // GRPECS=true for nHBF per TF + true, // GRPECS=true for nHBF per TF false, // GRPLHCIF false, // GRPMagField false, // askMatLUT From d9035aebc005bd00475237277e004f7cd7655a04 Mon Sep 17 00:00:00 2001 From: sevdokim <30727271+sevdokim@users.noreply.github.com> Date: Fri, 20 Oct 2023 11:44:51 +0200 Subject: [PATCH 310/324] CPV,PHS: modernize cell, digit and cluster readers (#12060) * CPV,PHS: modernize cell, digit and cluster readers * GlobalTrackingWorkflow: add modernized CPV and PHS readers to InputHelper.cxx --- Detectors/CPV/workflow/CMakeLists.txt | 12 +++ .../include/CPVWorkflow/ClusterReaderSpec.h | 68 ++++++++++++ .../include/CPVWorkflow/DigitReaderSpec.h | 69 ++++++++++++ .../CPV/workflow/src/ClusterReaderSpec.cxx | 100 ++++++++++++++++++ .../CPV/workflow/src/DigitReaderSpec.cxx | 100 ++++++++++++++++++ Detectors/CPV/workflow/src/RecoWorkflow.cxx | 4 +- .../workflow/src/cluster-reader-workflow.cxx | 56 ++++++++++ .../workflow/src/digit-reader-workflow.cxx | 56 ++++++++++ .../helpers/src/InputHelper.cxx | 8 +- Detectors/PHOS/testsimulation/plot_dig_phos.C | 17 ++- Detectors/PHOS/workflow/CMakeLists.txt | 4 +- .../include/PHOSWorkflow/CellReaderSpec.h | 68 ++++++++++++ .../include/PHOSWorkflow/DigitReaderSpec.h | 68 ++++++++++++ .../PHOS/workflow/src/CellConverterSpec.cxx | 11 +- .../PHOS/workflow/src/CellReaderSpec.cxx | 100 ++++++++++++++++++ .../PHOS/workflow/src/ClusterizerSpec.cxx | 10 +- .../PHOS/workflow/src/DigitReaderSpec.cxx | 100 ++++++++++++++++++ Detectors/PHOS/workflow/src/RecoWorkflow.cxx | 11 +- 18 files changed, 840 insertions(+), 22 deletions(-) create mode 100644 Detectors/CPV/workflow/include/CPVWorkflow/ClusterReaderSpec.h create mode 100644 Detectors/CPV/workflow/include/CPVWorkflow/DigitReaderSpec.h create mode 100644 Detectors/CPV/workflow/src/ClusterReaderSpec.cxx create mode 100644 Detectors/CPV/workflow/src/DigitReaderSpec.cxx create mode 100644 Detectors/CPV/workflow/src/cluster-reader-workflow.cxx create mode 100644 Detectors/CPV/workflow/src/digit-reader-workflow.cxx create mode 100644 Detectors/PHOS/workflow/include/PHOSWorkflow/CellReaderSpec.h create mode 100644 Detectors/PHOS/workflow/include/PHOSWorkflow/DigitReaderSpec.h create mode 100644 Detectors/PHOS/workflow/src/CellReaderSpec.cxx create mode 100644 Detectors/PHOS/workflow/src/DigitReaderSpec.cxx diff --git a/Detectors/CPV/workflow/CMakeLists.txt b/Detectors/CPV/workflow/CMakeLists.txt index 04e4b075a7ec4..ba21452393b99 100644 --- a/Detectors/CPV/workflow/CMakeLists.txt +++ b/Detectors/CPV/workflow/CMakeLists.txt @@ -12,6 +12,8 @@ o2_add_library(CPVWorkflow SOURCES src/RecoWorkflow.cxx src/ReaderSpec.cxx + src/DigitReaderSpec.cxx + src/ClusterReaderSpec.cxx src/WriterSpec.cxx src/ClusterizerSpec.cxx src/DigitsPrinterSpec.cxx @@ -41,3 +43,13 @@ o2_add_executable(cluster-writer-workflow COMPONENT_NAME cpv SOURCES src/cluster-writer-workflow.cxx PUBLIC_LINK_LIBRARIES O2::CPVWorkflow) + +o2_add_executable(digit-reader-workflow + COMPONENT_NAME cpv + SOURCES src/digit-reader-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::CPVWorkflow) + +o2_add_executable(cluster-reader-workflow + COMPONENT_NAME cpv + SOURCES src/cluster-reader-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::CPVWorkflow) diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/ClusterReaderSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/ClusterReaderSpec.h new file mode 100644 index 0000000000000..ee1c195b0aec5 --- /dev/null +++ b/Detectors/CPV/workflow/include/CPVWorkflow/ClusterReaderSpec.h @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterReaderSpec.h + +#ifndef O2_CPV_CLUSTERREADER +#define O2_CPV_CLUSTERREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Headers/DataHeader.h" +#include "DataFormatsCPV/Cluster.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +namespace o2 +{ +namespace cpv +{ + +class ClusterReader : public o2::framework::Task +{ + public: + ClusterReader(bool useMC = true); + ~ClusterReader() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + protected: + void connectTree(const std::string& filename); + + std::vector mClusters, *mClustersInp = &mClusters; + std::vector mTRs, *mTRsInp = &mTRs; + o2::dataformats::MCTruthContainer mMCTruth, *mMCTruthInp = &mMCTruth; + + o2::header::DataOrigin mOrigin = o2::header::gDataOriginCPV; + + bool mUseMC = true; // use MC truth + + std::unique_ptr mFile; + std::unique_ptr mTree; + std::string mInputFileName = ""; + std::string mClusterTreeName = "o2sim"; + std::string mClusterBranchName = "CPVCluster"; + std::string mTRBranchName = "CPVClusterTrigRec"; + std::string mClusterMCTruthBranchName = "CPVClusterTrueMC"; +}; + +/// create a processor spec +/// read CPV Cluster data from a root file +framework::DataProcessorSpec getCPVClusterReaderSpec(bool useMC = true); + +} // namespace cpv +} // namespace o2 + +#endif /* O2_CPV_CLUSTERREADER */ diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/DigitReaderSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/DigitReaderSpec.h new file mode 100644 index 0000000000000..00fce64f89125 --- /dev/null +++ b/Detectors/CPV/workflow/include/CPVWorkflow/DigitReaderSpec.h @@ -0,0 +1,69 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.h + +#ifndef O2_CPV_DIGITREADER +#define O2_CPV_DIGITREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Headers/DataHeader.h" +#include "DataFormatsCPV/Digit.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +namespace o2 +{ +namespace cpv +{ + +class DigitReader : public o2::framework::Task +{ + public: + DigitReader(bool useMC = true); + ~DigitReader() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + protected: + void connectTree(const std::string& filename); + + std::vector mDigits, *mDigitsInp = &mDigits; + std::vector mTRs, *mTRsInp = &mTRs; + // std::vector mMCTruth, *mMCTruthInp = &mMCTruth; + o2::dataformats::MCTruthContainer mMCTruth, *mMCTruthInp = &mMCTruth; + + o2::header::DataOrigin mOrigin = o2::header::gDataOriginCPV; + + bool mUseMC = true; // use MC truth + + std::unique_ptr mFile; + std::unique_ptr mTree; + std::string mInputFileName = ""; + std::string mDigitTreeName = "o2sim"; + std::string mDigitBranchName = "CPVDigit"; + std::string mTRBranchName = "CPVDigitTrigRecords"; + std::string mDigitMCTruthBranchName = "CPVDigitMCTruth"; +}; + +/// create a processor spec +/// read CPV Digit data from a root file +framework::DataProcessorSpec getCPVDigitReaderSpec(bool useMC = true); + +} // namespace cpv +} // namespace o2 + +#endif /* O2_CPV_DIGITREADER */ diff --git a/Detectors/CPV/workflow/src/ClusterReaderSpec.cxx b/Detectors/CPV/workflow/src/ClusterReaderSpec.cxx new file mode 100644 index 0000000000000..f9d82eb23bf68 --- /dev/null +++ b/Detectors/CPV/workflow/src/ClusterReaderSpec.cxx @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterReaderSpec.cxx + +#include +#include +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "CPVWorkflow/ClusterReaderSpec.h" +#include "CommonUtils/NameConf.h" + +using namespace o2::framework; +using namespace o2::cpv; + +namespace o2 +{ +namespace cpv +{ + +ClusterReader::ClusterReader(bool useMC) +{ + mUseMC = useMC; +} + +void ClusterReader::init(InitContext& ic) +{ + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get("input-dir")), + ic.options().get("cpv-clusters-infile")); + connectTree(mInputFileName); +} + +void ClusterReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(info) << "Pushing " << mClusters.size() << " Clusters in " << mTRs.size() << " TriggerRecords at entry " << ent; + pc.outputs().snapshot(Output{mOrigin, "CLUSTERS", 0, Lifetime::Timeframe}, mClusters); + pc.outputs().snapshot(Output{mOrigin, "CLUSTERTRIGRECS", 0, Lifetime::Timeframe}, mTRs); + if (mUseMC) { + pc.outputs().snapshot(Output{mOrigin, "CLUSTERTRUEMC", 0, Lifetime::Timeframe}, mMCTruth); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(QuitRequest::Me); + } +} + +void ClusterReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mClusterTreeName.c_str())); + assert(mTree); + assert(mTree->GetBranch(mTRBranchName.c_str())); + + mTree->SetBranchAddress(mTRBranchName.c_str(), &mTRsInp); + mTree->SetBranchAddress(mClusterBranchName.c_str(), &mClustersInp); + if (mUseMC) { + if (mTree->GetBranch(mClusterMCTruthBranchName.c_str())) { + mTree->SetBranchAddress(mClusterMCTruthBranchName.c_str(), &mMCTruthInp); + } else { + LOG(warning) << "MC-truth is missing, message will be empty"; + } + } + LOG(info) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getCPVClusterReaderSpec(bool useMC) +{ + std::vector outputSpec; + outputSpec.emplace_back("CPV", "CLUSTERS", 0, Lifetime::Timeframe); + outputSpec.emplace_back("CPV", "CLUSTERTRIGRECS", 0, Lifetime::Timeframe); + if (useMC) { + outputSpec.emplace_back("CPV", "CLUSTERTRUEMC", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "cpv-cluster-reader", + Inputs{}, + outputSpec, + AlgorithmSpec{adaptFromTask(useMC)}, + Options{ + {"cpv-clusters-infile", VariantType::String, "cpvclusters.root", {"Name of the input Cluster file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace cpv +} // namespace o2 diff --git a/Detectors/CPV/workflow/src/DigitReaderSpec.cxx b/Detectors/CPV/workflow/src/DigitReaderSpec.cxx new file mode 100644 index 0000000000000..ba74cb88b10d2 --- /dev/null +++ b/Detectors/CPV/workflow/src/DigitReaderSpec.cxx @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.cxx + +#include +#include +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "CPVWorkflow/DigitReaderSpec.h" +#include "CommonUtils/NameConf.h" + +using namespace o2::framework; +using namespace o2::cpv; + +namespace o2 +{ +namespace cpv +{ + +DigitReader::DigitReader(bool useMC) +{ + mUseMC = useMC; +} + +void DigitReader::init(InitContext& ic) +{ + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get("input-dir")), + ic.options().get("cpv-digits-infile")); + connectTree(mInputFileName); +} + +void DigitReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(info) << "Pushing " << mDigits.size() << " Digits in " << mTRs.size() << " TriggerRecords at entry " << ent; + pc.outputs().snapshot(Output{mOrigin, "DIGITS", 0, Lifetime::Timeframe}, mDigits); + pc.outputs().snapshot(Output{mOrigin, "DIGITTRIGREC", 0, Lifetime::Timeframe}, mTRs); + if (mUseMC) { + pc.outputs().snapshot(Output{mOrigin, "DIGITSMCTR", 0, Lifetime::Timeframe}, mMCTruth); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(QuitRequest::Me); + } +} + +void DigitReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mDigitTreeName.c_str())); + assert(mTree); + assert(mTree->GetBranch(mTRBranchName.c_str())); + + mTree->SetBranchAddress(mTRBranchName.c_str(), &mTRsInp); + mTree->SetBranchAddress(mDigitBranchName.c_str(), &mDigitsInp); + if (mUseMC) { + if (mTree->GetBranch(mDigitMCTruthBranchName.c_str())) { + mTree->SetBranchAddress(mDigitMCTruthBranchName.c_str(), &mMCTruthInp); + } else { + LOG(warning) << "MC-truth is missing, message will be empty"; + } + } + LOG(info) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getCPVDigitReaderSpec(bool useMC) +{ + std::vector outputSpec; + outputSpec.emplace_back("CPV", "DIGITS", 0, Lifetime::Timeframe); + outputSpec.emplace_back("CPV", "DIGITTRIGREC", 0, Lifetime::Timeframe); + if (useMC) { + outputSpec.emplace_back("CPV", "DIGITSMCTR", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "cpv-digit-reader", + Inputs{}, + outputSpec, + AlgorithmSpec{adaptFromTask(useMC)}, + Options{ + {"cpv-digits-infile", VariantType::String, "cpvdigits.root", {"Name of the input Digit file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace cpv +} // namespace o2 diff --git a/Detectors/CPV/workflow/src/RecoWorkflow.cxx b/Detectors/CPV/workflow/src/RecoWorkflow.cxx index da4ffee8aa6e8..66b5f3dbe588a 100644 --- a/Detectors/CPV/workflow/src/RecoWorkflow.cxx +++ b/Detectors/CPV/workflow/src/RecoWorkflow.cxx @@ -24,6 +24,7 @@ #include "SimulationDataFormat/MCCompLabel.h" #include "DataFormatsCPV/TriggerRecord.h" #include "CPVWorkflow/RecoWorkflow.h" +#include "CPVWorkflow/DigitReaderSpec.h" #include "CPVWorkflow/ClusterizerSpec.h" #include "CPVWorkflow/ReaderSpec.h" #include "CPVWorkflow/WriterSpec.h" @@ -107,7 +108,8 @@ o2::framework::WorkflowSpec getWorkflow(bool disableRootInp, // Digits to .... if (inputType == InputType::Digits) { if (!disableRootInp) { - specs.emplace_back(o2::cpv::getDigitsReaderSpec(propagateMC)); + specs.emplace_back(o2::cpv::getCPVDigitReaderSpec(propagateMC)); + // specs.emplace_back(o2::cpv::getDigitsReaderSpec(propagateMC)); } if (isEnabled(OutputType::Clusters)) { diff --git a/Detectors/CPV/workflow/src/cluster-reader-workflow.cxx b/Detectors/CPV/workflow/src/cluster-reader-workflow.cxx new file mode 100644 index 0000000000000..33f389f15f9da --- /dev/null +++ b/Detectors/CPV/workflow/src/cluster-reader-workflow.cxx @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ConfigParamSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "Framework/CallbacksPolicy.h" + +using namespace o2::framework; + +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} + +void customize(std::vector& workflowOptions) +{ + workflowOptions.push_back( + ConfigParamSpec{ + "with-mc", + o2::framework::VariantType::Bool, + false, + {"propagate MC labels"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "configKeyValues", + VariantType::String, + "", + {"Semicolon separated key=value strings"}}); + o2::raw::HBFUtilsInitializer::addConfigOption(workflowOptions); +} + +#include "Framework/runDataProcessing.h" +#include "CPVWorkflow/ClusterReaderSpec.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cc) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(cc.options().get("configKeyValues")); + auto withMC = cc.options().get("with-mc"); + + specs.emplace_back(o2::cpv::getCPVClusterReaderSpec(withMC)); + + // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(cc, specs); + + return specs; +} diff --git a/Detectors/CPV/workflow/src/digit-reader-workflow.cxx b/Detectors/CPV/workflow/src/digit-reader-workflow.cxx new file mode 100644 index 0000000000000..dc068573b1218 --- /dev/null +++ b/Detectors/CPV/workflow/src/digit-reader-workflow.cxx @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/ConfigParamSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "Framework/CallbacksPolicy.h" + +using namespace o2::framework; + +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} + +void customize(std::vector& workflowOptions) +{ + workflowOptions.push_back( + ConfigParamSpec{ + "with-mc", + o2::framework::VariantType::Bool, + false, + {"propagate MC labels"}}); + workflowOptions.push_back( + ConfigParamSpec{ + "configKeyValues", + VariantType::String, + "", + {"Semicolon separated key=value strings"}}); + o2::raw::HBFUtilsInitializer::addConfigOption(workflowOptions); +} + +#include "Framework/runDataProcessing.h" +#include "CPVWorkflow/DigitReaderSpec.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cc) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(cc.options().get("configKeyValues")); + auto withMC = cc.options().get("with-mc"); + + specs.emplace_back(o2::cpv::getCPVDigitReaderSpec(withMC)); + + // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(cc, specs); + + return specs; +} diff --git a/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx b/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx index 856e20fe3f993..1069eb96c7938 100644 --- a/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx +++ b/Detectors/GlobalTrackingWorkflow/helpers/src/InputHelper.cxx @@ -43,8 +43,8 @@ #include "MCHIO/TrackReaderSpec.h" #include "MCHIO/ClusterReaderSpec.h" #include "MIDWorkflow/TrackReaderSpec.h" -#include "PHOSWorkflow/ReaderSpec.h" -#include "CPVWorkflow/ReaderSpec.h" +#include "PHOSWorkflow/CellReaderSpec.h" +#include "CPVWorkflow/ClusterReaderSpec.h" #include "EMCALWorkflow/PublisherSpec.h" // #include "StrangenessTrackingWorkflow/StrangenessTrackingReaderSpec.h" @@ -164,11 +164,11 @@ int InputHelper::addInputSpecs(const ConfigContext& configcontext, WorkflowSpec& } if (maskTracks[GID::PHS] || maskClusters[GID::PHS]) { - specs.emplace_back(o2::phos::getCellReaderSpec(maskTracksMC[GID::PHS] || maskClustersMC[GID::PHS])); + specs.emplace_back(o2::phos::getPHOSCellReaderSpec(maskTracksMC[GID::PHS] || maskClustersMC[GID::PHS])); } if (maskTracks[GID::CPV] || maskClusters[GID::CPV]) { - specs.emplace_back(o2::cpv::getClustersReaderSpec(maskTracksMC[GID::CPV] || maskClustersMC[GID::CPV])); + specs.emplace_back(o2::cpv::getCPVClusterReaderSpec(maskTracksMC[GID::CPV] || maskClustersMC[GID::CPV])); } if (maskTracks[GID::EMC] || maskClusters[GID::EMC]) { diff --git a/Detectors/PHOS/testsimulation/plot_dig_phos.C b/Detectors/PHOS/testsimulation/plot_dig_phos.C index 4b902bf3da9c0..5062ddfc35e05 100644 --- a/Detectors/PHOS/testsimulation/plot_dig_phos.C +++ b/Detectors/PHOS/testsimulation/plot_dig_phos.C @@ -1,3 +1,14 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + /// \file plot_dig_phos.C /// \brief Simple macro to plot PHOS digits per event @@ -24,11 +35,11 @@ void plot_dig_phos(int ievent = 0, TString inputfile = "o2dig.root") TTree* digTree = (TTree*)gFile->Get("o2sim"); std::vector* mDigitsArray = nullptr; o2::dataformats::MCTruthContainer* labels = nullptr; - digTree->SetBranchAddress("PHSDigit", &mDigitsArray); - digTree->SetBranchAddress("PHSDigitMCTruth", &labels); + digTree->SetBranchAddress("PHOSDigit", &mDigitsArray); + digTree->SetBranchAddress("PHOSDigitMCTruth", &labels); if (!mDigitsArray) { - cout << "PHOS digits not in tree. Exiting ..." << endl; + cout << "PHOS digits not in tree. Exiting..." << endl; return; } digTree->GetEvent(ievent); diff --git a/Detectors/PHOS/workflow/CMakeLists.txt b/Detectors/PHOS/workflow/CMakeLists.txt index 910127e6af188..d6712b274fabd 100644 --- a/Detectors/PHOS/workflow/CMakeLists.txt +++ b/Detectors/PHOS/workflow/CMakeLists.txt @@ -10,7 +10,9 @@ # or submit itself to any jurisdiction. o2_add_library(PHOSWorkflow - SOURCES src/RecoWorkflow.cxx + SOURCES src/CellReaderSpec.cxx + src/DigitReaderSpec.cxx + src/RecoWorkflow.cxx src/ReaderSpec.cxx src/CellConverterSpec.cxx src/RawToCellConverterSpec.cxx diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/CellReaderSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/CellReaderSpec.h new file mode 100644 index 0000000000000..113211418f4fb --- /dev/null +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/CellReaderSpec.h @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CellReaderSpec.h + +#ifndef O2_PHOS_CELLREADER +#define O2_PHOS_CELLREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Headers/DataHeader.h" +#include "DataFormatsPHOS/Cell.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DataFormatsPHOS/MCLabel.h" + +namespace o2 +{ +namespace phos +{ + +class CellReader : public o2::framework::Task +{ + public: + CellReader(bool useMC = true); + ~CellReader() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + protected: + void connectTree(const std::string& filename); + + std::vector mCells, *mCellsInp = &mCells; + std::vector mTRs, *mTRsInp = &mTRs; + o2::dataformats::MCTruthContainer mMCTruth, *mMCTruthInp = &mMCTruth; + + o2::header::DataOrigin mOrigin = o2::header::gDataOriginPHS; + + bool mUseMC = true; // use MC truth + + std::unique_ptr mFile; + std::unique_ptr mTree; + std::string mInputFileName = ""; + std::string mCellTreeName = "o2sim"; + std::string mCellBranchName = "PHOSCell"; + std::string mTRBranchName = "PHOSCellTrigRec"; + std::string mCellMCTruthBranchName = "PHOSCellTrueMC"; +}; + +/// create a processor spec +/// read PHOS Cell data from a root file +framework::DataProcessorSpec getPHOSCellReaderSpec(bool useMC = true); + +} // namespace phos +} // namespace o2 + +#endif /* O2_PHOS_CELLREADER */ diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/DigitReaderSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/DigitReaderSpec.h new file mode 100644 index 0000000000000..3ee0ed9789379 --- /dev/null +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/DigitReaderSpec.h @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.h + +#ifndef O2_PHOS_DIGITREADER +#define O2_PHOS_DIGITREADER + +#include "TFile.h" +#include "TTree.h" + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Headers/DataHeader.h" +#include "DataFormatsPHOS/Digit.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "DataFormatsPHOS/MCLabel.h" + +namespace o2 +{ +namespace phos +{ + +class DigitReader : public o2::framework::Task +{ + public: + DigitReader(bool useMC = true); + ~DigitReader() override = default; + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + + protected: + void connectTree(const std::string& filename); + + std::vector mDigits, *mDigitsInp = &mDigits; + std::vector mTRs, *mTRsInp = &mTRs; + o2::dataformats::MCTruthContainer mMCTruth, *mMCTruthInp = &mMCTruth; + + o2::header::DataOrigin mOrigin = o2::header::gDataOriginPHS; + + bool mUseMC = true; // use MC truth + + std::unique_ptr mFile; + std::unique_ptr mTree; + std::string mInputFileName = ""; + std::string mDigitTreeName = "o2sim"; + std::string mDigitBranchName = "PHOSDigit"; + std::string mTRBranchName = "PHOSDigitTrigRecords"; + std::string mDigitMCTruthBranchName = "PHOSDigitMCTruth"; +}; + +/// create a processor spec +/// read PHOS Digit data from a root file +framework::DataProcessorSpec getPHOSDigitReaderSpec(bool useMC = true); + +} // namespace phos +} // namespace o2 + +#endif /* O2_PHOS_DIGITREADER */ diff --git a/Detectors/PHOS/workflow/src/CellConverterSpec.cxx b/Detectors/PHOS/workflow/src/CellConverterSpec.cxx index 8d145ff7a3279..330dd27c45251 100644 --- a/Detectors/PHOS/workflow/src/CellConverterSpec.cxx +++ b/Detectors/PHOS/workflow/src/CellConverterSpec.cxx @@ -37,10 +37,12 @@ void CellConverterSpec::init(framework::InitContext& ctx) void CellConverterSpec::run(framework::ProcessingContext& ctx) { - LOG(debug) << "[PHOSCellConverter - run] called"; - auto dataref = ctx.inputs().get("digits"); - auto const* phosheader = o2::framework::DataRefUtils::getHeader(dataref); - if (!phosheader->mHasPayload) { + // LOG(debug) << "[PHOSCellConverter - run] called"; + // auto dataref = ctx.inputs().get("digits"); + // auto const* phosheader = o2::framework::DataRefUtils::getHeader(dataref); + // if (!phosheader->mHasPayload) { + auto digitsTR = ctx.inputs().get>("digitTriggerRecords"); + if (!digitsTR.size()) { // nothing to process mOutputCells.clear(); ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLS", 0, o2::framework::Lifetime::Timeframe}, mOutputCells); mOutputCellTrigRecs.clear(); @@ -61,7 +63,6 @@ void CellConverterSpec::run(framework::ProcessingContext& ctx) mOutputCellTrigRecs.clear(); auto digits = ctx.inputs().get>("digits"); - auto digitsTR = ctx.inputs().get>("digitTriggerRecords"); std::unique_ptr> truthcont(nullptr); if (mPropagateMC) { truthcont = ctx.inputs().get*>("digitsmctr"); diff --git a/Detectors/PHOS/workflow/src/CellReaderSpec.cxx b/Detectors/PHOS/workflow/src/CellReaderSpec.cxx new file mode 100644 index 0000000000000..64f54c1baf189 --- /dev/null +++ b/Detectors/PHOS/workflow/src/CellReaderSpec.cxx @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file CellReaderSpec.cxx + +#include +#include +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "PHOSWorkflow/CellReaderSpec.h" +#include "CommonUtils/NameConf.h" + +using namespace o2::framework; +using namespace o2::phos; + +namespace o2 +{ +namespace phos +{ + +CellReader::CellReader(bool useMC) +{ + mUseMC = useMC; +} + +void CellReader::init(InitContext& ic) +{ + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get("input-dir")), + ic.options().get("phos-cells-infile")); + connectTree(mInputFileName); +} + +void CellReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(info) << "Pushing " << mCells.size() << " Cells in " << mTRs.size() << " TriggerRecords at entry " << ent; + pc.outputs().snapshot(Output{mOrigin, "CELLS", 0, Lifetime::Timeframe}, mCells); + pc.outputs().snapshot(Output{mOrigin, "CELLTRIGREC", 0, Lifetime::Timeframe}, mTRs); + if (mUseMC) { + pc.outputs().snapshot(Output{mOrigin, "CELLSMCTR", 0, Lifetime::Timeframe}, mMCTruth); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(QuitRequest::Me); + } +} + +void CellReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mCellTreeName.c_str())); + assert(mTree); + assert(mTree->GetBranch(mTRBranchName.c_str())); + + mTree->SetBranchAddress(mTRBranchName.c_str(), &mTRsInp); + mTree->SetBranchAddress(mCellBranchName.c_str(), &mCellsInp); + if (mUseMC) { + if (mTree->GetBranch(mCellMCTruthBranchName.c_str())) { + mTree->SetBranchAddress(mCellMCTruthBranchName.c_str(), &mMCTruthInp); + } else { + LOG(warning) << "MC-truth is missing, message will be empty"; + } + } + LOG(info) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getPHOSCellReaderSpec(bool useMC) +{ + std::vector outputSpec; + outputSpec.emplace_back("PHS", "CELLS", 0, Lifetime::Timeframe); + outputSpec.emplace_back("PHS", "CELLTRIGREC", 0, Lifetime::Timeframe); + if (useMC) { + outputSpec.emplace_back("PHS", "CELLSMCTR", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "phos-cells-reader", + Inputs{}, + outputSpec, + AlgorithmSpec{adaptFromTask(useMC)}, + Options{ + {"phos-cells-infile", VariantType::String, "phoscells.root", {"Name of the input Cell file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace phos +} // namespace o2 diff --git a/Detectors/PHOS/workflow/src/ClusterizerSpec.cxx b/Detectors/PHOS/workflow/src/ClusterizerSpec.cxx index 7dd46e49c03d5..27bce0f8745f4 100644 --- a/Detectors/PHOS/workflow/src/ClusterizerSpec.cxx +++ b/Detectors/PHOS/workflow/src/ClusterizerSpec.cxx @@ -72,9 +72,11 @@ void ClusterizerSpec::run(framework::ProcessingContext& ctx) if (mUseDigits) { LOG(debug) << "PHOSClusterizer - run on digits called"; - auto dataref = ctx.inputs().get("digits"); - auto const* phosheader = o2::framework::DataRefUtils::getHeader(dataref); - if (!phosheader->mHasPayload) { + // auto dataref = ctx.inputs().get("digits"); + // auto const* phosheader = o2::framework::DataRefUtils::getHeader(dataref); + // if (!phosheader->mHasPayload) { + auto digitsTR = ctx.inputs().get>("digitTriggerRecords"); + if (!digitsTR.size()) { // nothing to process mOutputClusters.clear(); ctx.outputs().snapshot(o2::framework::Output{"PHS", "CLUSTERS", 0, o2::framework::Lifetime::Timeframe}, mOutputClusters); if (mFullCluOutput) { @@ -89,9 +91,7 @@ void ClusterizerSpec::run(framework::ProcessingContext& ctx) } return; } - // auto digits = ctx.inputs().get>("digits"); auto digits = ctx.inputs().get>("digits"); - auto digitsTR = ctx.inputs().get>("digitTriggerRecords"); LOG(debug) << "[PHOSClusterizer - run] Received " << digitsTR.size() << " TR, running clusterizer ..."; // const o2::dataformats::MCTruthContainer* truthcont=nullptr; if (mPropagateMC) { diff --git a/Detectors/PHOS/workflow/src/DigitReaderSpec.cxx b/Detectors/PHOS/workflow/src/DigitReaderSpec.cxx new file mode 100644 index 0000000000000..737856051af0c --- /dev/null +++ b/Detectors/PHOS/workflow/src/DigitReaderSpec.cxx @@ -0,0 +1,100 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file DigitReaderSpec.cxx + +#include +#include +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "PHOSWorkflow/DigitReaderSpec.h" +#include "CommonUtils/NameConf.h" + +using namespace o2::framework; +using namespace o2::phos; + +namespace o2 +{ +namespace phos +{ + +DigitReader::DigitReader(bool useMC) +{ + mUseMC = useMC; +} + +void DigitReader::init(InitContext& ic) +{ + mInputFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get("input-dir")), + ic.options().get("phos-digits-infile")); + connectTree(mInputFileName); +} + +void DigitReader::run(ProcessingContext& pc) +{ + auto ent = mTree->GetReadEntry() + 1; + assert(ent < mTree->GetEntries()); // this should not happen + mTree->GetEntry(ent); + LOG(info) << "Pushing " << mDigits.size() << " Digits in " << mTRs.size() << " TriggerRecords at entry " << ent; + pc.outputs().snapshot(Output{mOrigin, "DIGITS", 0, Lifetime::Timeframe}, mDigits); + pc.outputs().snapshot(Output{mOrigin, "DIGITTRIGREC", 0, Lifetime::Timeframe}, mTRs); + if (mUseMC) { + pc.outputs().snapshot(Output{mOrigin, "DIGITSMCTR", 0, Lifetime::Timeframe}, mMCTruth); + } + + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(QuitRequest::Me); + } +} + +void DigitReader::connectTree(const std::string& filename) +{ + mTree.reset(nullptr); // in case it was already loaded + mFile.reset(TFile::Open(filename.c_str())); + assert(mFile && !mFile->IsZombie()); + mTree.reset((TTree*)mFile->Get(mDigitTreeName.c_str())); + assert(mTree); + assert(mTree->GetBranch(mTRBranchName.c_str())); + + mTree->SetBranchAddress(mTRBranchName.c_str(), &mTRsInp); + mTree->SetBranchAddress(mDigitBranchName.c_str(), &mDigitsInp); + if (mUseMC) { + if (mTree->GetBranch(mDigitMCTruthBranchName.c_str())) { + mTree->SetBranchAddress(mDigitMCTruthBranchName.c_str(), &mMCTruthInp); + } else { + LOG(warning) << "MC-truth is missing, message will be empty"; + } + } + LOG(info) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; +} + +DataProcessorSpec getPHOSDigitReaderSpec(bool useMC) +{ + std::vector outputSpec; + outputSpec.emplace_back("PHS", "DIGITS", 0, Lifetime::Timeframe); + outputSpec.emplace_back("PHS", "DIGITTRIGREC", 0, Lifetime::Timeframe); + if (useMC) { + outputSpec.emplace_back("PHS", "DIGITSMCTR", 0, Lifetime::Timeframe); + } + + return DataProcessorSpec{ + "phos-digits-reader", + Inputs{}, + outputSpec, + AlgorithmSpec{adaptFromTask(useMC)}, + Options{ + {"phos-digits-infile", VariantType::String, "phosdigits.root", {"Name of the input Digit file"}}, + {"input-dir", VariantType::String, "none", {"Input directory"}}}}; +} + +} // namespace phos +} // namespace o2 diff --git a/Detectors/PHOS/workflow/src/RecoWorkflow.cxx b/Detectors/PHOS/workflow/src/RecoWorkflow.cxx index 431648b0ee02f..95e6c732f2046 100644 --- a/Detectors/PHOS/workflow/src/RecoWorkflow.cxx +++ b/Detectors/PHOS/workflow/src/RecoWorkflow.cxx @@ -29,6 +29,8 @@ #include "PHOSWorkflow/WriterSpec.h" #include "PHOSWorkflow/RawToCellConverterSpec.h" #include "PHOSWorkflow/RawWriterSpec.h" +#include "PHOSWorkflow/DigitReaderSpec.h" +#include "PHOSWorkflow/CellReaderSpec.h" #include "Framework/DataSpecUtils.h" #include "SimulationDataFormat/MCTruthContainer.h" @@ -51,7 +53,8 @@ const std::unordered_map InputMap{ const std::unordered_map OutputMap{ {"cells", OutputType::Cells}, - {"clusters", OutputType::Clusters}}; + {"clusters", OutputType::Clusters}, + {"digits", OutputType::Digits}}; o2::framework::WorkflowSpec getWorkflow(bool disableRootInp, bool disableRootOut, @@ -104,7 +107,8 @@ o2::framework::WorkflowSpec getWorkflow(bool disableRootInp, // Digits to .... if (inputType == InputType::Digits) { if (!disableRootInp) { - specs.emplace_back(o2::phos::getDigitsReaderSpec(propagateMC)); + // specs.emplace_back(o2::phos::getDigitsReaderSpec(propagateMC)); + specs.emplace_back(o2::phos::getPHOSDigitReaderSpec(propagateMC)); } if (isEnabled(OutputType::Cells)) { // add converter for cells @@ -125,7 +129,8 @@ o2::framework::WorkflowSpec getWorkflow(bool disableRootInp, // Cells to if (inputType == InputType::Cells) { if (!disableRootInp) { - specs.emplace_back(o2::phos::getCellReaderSpec(propagateMC)); + // specs.emplace_back(o2::phos::getCellReaderSpec(propagateMC)); + specs.emplace_back(o2::phos::getPHOSCellReaderSpec(propagateMC)); } if (isEnabled(OutputType::Clusters)) { // add clusterizer From d56ac3c75b0604f857659be19907f5febbe675e7 Mon Sep 17 00:00:00 2001 From: wiechula Date: Thu, 12 Oct 2023 19:05:44 +0200 Subject: [PATCH 311/324] Add EOV functionality --- Detectors/TPC/dcs/src/DCSConfigSpec.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Detectors/TPC/dcs/src/DCSConfigSpec.cxx b/Detectors/TPC/dcs/src/DCSConfigSpec.cxx index c01b5c83d6593..fb8b61574b60b 100644 --- a/Detectors/TPC/dcs/src/DCSConfigSpec.cxx +++ b/Detectors/TPC/dcs/src/DCSConfigSpec.cxx @@ -33,6 +33,8 @@ #include "Framework/ConfigParamRegistry.h" #include "DetectorsCalibration/Utils.h" #include "CommonUtils/StringUtils.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "CCDB/CcdbObjectInfo.h" #include "CCDB/CcdbApi.h" #include "CommonUtils/NameConf.h" @@ -197,7 +199,11 @@ void DCSConfigDevice::updateRunInfo(gsl::span configBuff) const long startValRCT = std::stol(data[1]); const long endValRCT = startValRCT + 48l * 60l * 60l * 1000l; if (!mDontWriteRunInfo) { + o2::ccdb::CcdbObjectInfo w(CDBTypeMap.at(CDBType::ConfigRunInfo), "", "", md, startValRCT, endValRCT); mCCDBApi.storeAsBinaryFile(&tempChar, sizeof(tempChar), "tmp.dat", "char", CDBTypeMap.at(CDBType::ConfigRunInfo), md, startValRCT, endValRCT); + if (!mCCDBApi.isSnapshotMode()) { + o2::ccdb::adjustOverriddenEOV(mCCDBApi, w); + } } std::string mdInfo = "["; From 55b7e33876de09c889c50707fb036aa12938bcf5 Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Fri, 13 Oct 2023 14:58:27 +0200 Subject: [PATCH 312/324] TPC IDC: Adding check for default GPECS object --- .../workflow/include/TPCWorkflow/TPCDistributeIDCSpec.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCDistributeIDCSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCDistributeIDCSpec.h index 7f13680b72eb7..6e589cd6c4e8b 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCDistributeIDCSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCDistributeIDCSpec.h @@ -93,8 +93,13 @@ class TPCDistributeIDCSpec : public o2::framework::Task LOGP(info, "Updating ORBITRESET"); std::fill(mSendCCDBOutputOrbitReset.begin(), mSendCCDBOutputOrbitReset.end(), true); } else if (matcher == ConcreteDataMatcher("GLO", "GRPECS", 0)) { - LOGP(info, "Updating GRPECS"); - std::fill(mSendCCDBOutputGRPECS.begin(), mSendCCDBOutputGRPECS.end(), true); + // check if received object is valid + if (o2::base::GRPGeomHelper::instance().getGRPECS()->getRun() != 0) { + LOGP(info, "Updating GRPECS"); + std::fill(mSendCCDBOutputGRPECS.begin(), mSendCCDBOutputGRPECS.end(), true); + } else { + LOGP(info, "Detected default GRPECS object"); + } } } From 96d1dbbd3c9fa7f3dc598d1d47039a5084cb3717 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 20 Oct 2023 10:24:08 +0200 Subject: [PATCH 313/324] RawFileReader: Fix triggering CCDB message --- Detectors/Raw/src/RawFileReaderWorkflow.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Detectors/Raw/src/RawFileReaderWorkflow.cxx b/Detectors/Raw/src/RawFileReaderWorkflow.cxx index 57a9e57cc322d..38d379aee9aea 100644 --- a/Detectors/Raw/src/RawFileReaderWorkflow.cxx +++ b/Detectors/Raw/src/RawFileReaderWorkflow.cxx @@ -348,10 +348,16 @@ void RawReaderSpecs::run(o2f::ProcessingContext& ctx) if (mTFCounter) { // delay sending std::this_thread::sleep_for(std::chrono::microseconds((size_t)mDelayUSec)); } + bool sentSomething = false; for (auto& msgIt : messagesPerRoute) { LOG(info) << "Sending " << msgIt.second->Size() / 2 << " parts to channel " << msgIt.first; device->Send(*msgIt.second.get(), msgIt.first); + sentSomething = msgIt.second->Size() > 0; } + if (sentSomething) { + ctx.services().get().fakeDispatch(); + } + mTimer.Stop(); LOGP(info, "Sent payload of {} bytes in {} parts in {} messages for TF#{} firstTForbit={} timeStamp={} | Timing: {}", tfSize, tfNParts, From 6ec304aaafdf962e6df13b2ed1a1585e3a2152bf Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 20 Oct 2023 14:07:15 +0200 Subject: [PATCH 314/324] Several upgrades for Event-Generators (#12032) Several improvements for event generators: - standardization of info keys in MC event headers - new GeneratorTParticle generator, being able to read simple TParticle events from file or process - ability to read HepMC events from process via FIFO and other improvements for HepMC Summary of individual commit messages ----------- * Introduce pre-defined keys for MC event header info A number of keys into the ME event header information mapping is defined. This is to ensure that code will use the same keys when ever information is set. Additional, non-predefined keys, are still possible. This makes it much more robust when we ask for specific MC information from the event header, such as - cross-section(s) - weight(s) - Heavy-ion "geometry" parameters - Npart in projectile and target - Ncoll in various views - Overall - Hard - wounded-nucleon on nucleon - nucleon on wounded-nucleon - wounded on wounded - Parton distribution function parameters This is crucial for building a HepMC event structure which can be passed on to say for example Rivet analyses. * Export _full_ header information to MC event header The generator has been changed so that it exports _all_ relevant and available information from Pythia to the MC event header, including heavy-ion "geometry" parameters. In particular, the information is stored in an HepMC compatible way for later user by f.ex. Rivet. Note, the current code counts up the number of collisions by it self. However, the authors of Pythia have another way of doing that. The code is now there to do it the same way as the Pythia authors, but is currenly disabled. We should decide which is the appropriate way to count Ncoll. I would recommend to follow how the Pythia authors do it. * Full header read-in and external program This change does two things: **Full header** _All_ information available in the HepMC event header is propagated to the MC event header information map. This includes - Heavy-ion "geometry" parameters (b,Ncoll,Npart,...) - Cross-section(s) - Weight(s) - PDF information - and other attributes defined This is so that we can build a full HepMC event structure later - for example to pass to Rivet analyses ** External program ** The functionality of the generator is expanded so that it may spawn an event generator program, say `eg`. - The generator opens a FIFO - The generator then executes the program `eg` in the background - The `eg` program is assumed to write HepMC event records on standard output, which is then redirected to the FIFO - The generator reads events from the FIFO For this to work, a number of conditions _must_ be met by the `eg` program: - It _must_ write events in the HepMC event format - It _must_ write the HepMC event records to standard output - It _cannot_ write anything else but the HepMC event record to standard output - It _must_ accept the command line option `-n NEVENTS` to set the number of events to generate. If a particular `eg` program does not meet these requirements, then a simple shell script can be defined to wrap the `eg` appropriately. For example, the CRMC program `crmc` _can_ write HepMC events to standard output, but it will also dump other stuff there. Thus, we can provide the script #!/bin/sh crmc $@ -o hepmc3 -f /dev/stdout | \ sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' which simply filters the output of `crmc`. Another EG program may not accept the `-n EVENTS` command line option, but rather has the command line option `--nevents`, so then we would do something like #!/bin/sh cmdline="eg-program -o /dev/stdout " while test $# -gt 0 ; do case x$1 in x-n) cmdline="$cmdline -n $2"; shift ;; *) cmdline="$cmdline $1" ;; esac shift done $cmdline The command line to run is specified as --configKeyValues "HepMC.progCmd=" and can include not only the program name but also other options to the program. For example --configKeyValues "HepMC.progCmd=crmc -m 5 -i 20800820 -I 20800820" for Pb-Pb collisions with Hijing. With this change, we can use _any_ event generator which is capable to write out its event records in the HepMC format. * New generator GeneratorTParticle The generator `GeneratorTParticle` will read in particles from a `TChain` containing a branch with a `TClonesArray` of `TParticle` objects. The generator can operate in two modes - Data is read from a file(s) - Data is read from a file being generated by a child program The first mode is selected by -g tparticle --configKeyValues "TParticle.fileNames=foo.root,bar.root" The second mode is selected by -g tparticle --configKeyValues "TParticle.progCmd=" For this latter mode, see also recent commit to `GeneratorHepMC` Above `` specifiy a program to spawn in the background which will write to a specified file (temporary file). Suppose the program is called `eg`, then the following _must_ be possible eg -n NEVENTS -o OUTPUT_FILENAME That is, `eg` _must_ accept the option `-n` to set the number of events to produce, and the option `-o` to set the output file name (a ROOT file). The name of the `TTree` object in the file(s) can be set with --configKeyValues "TParticle.treeName=" (defaults to `T`), and similar for the branch that contains the `TClonesArray` of `TParticle` --configKeyValues "TParticle.branchName=" (defaults to `Particles`). The generator `GeneratorTParticle` _does not_ import any header information into the simulation event record. Some proper convention could be decided upon, e.g., one that tracks the HepMC event record format. * Refactoring to HepMC and TParticle Generators The classes `GeneratorHepMC` and `GeneratorTParticle` is refactored to derive from the (second) base class `GeneratorFileOrCmd`. `GeneratorFileOrCmd` provides common infrastructure to specify - File(s) to read events from (ROOT files in case of `GeneratorTParticle`, and HepMC files in case of `GeneratorHepMC`), _or_ - Which commmand to execute and with which options. It also provides infrastructure to make unique temporary names, a FIFO to read from (child program writes to), and so on. These are all configured through configuration keys prefixed by `GeneratorFileOrCmd.`. Other changes include - `GeneratorHepMC` will open _any_ file that HepMC supports - ASCII, compressed ASCII, HEPEVT, etc. - Through the use of `GeneratorFileOrCmd` the command line option flags for specifying seed (default: `-s`), number of events (default `-n`), largest impact parameter (defautl: `-b`), output (default: `>`), and so on can be configured via configuration key values - `GeneratorHepMC` and `GeneratorTParticle` are passed the `GeneratorFileOrCmdParam` as well as specific `GeneratorHepMCParam` and `GeneratorTParticleParam`, respectively, objects by `GeneratorFactor` and sets the internal parameters accordingly. This hides the specifics of the parameters from `GeneratorFactory`. - `GeneratorHepMC` accepts the old `HepMC.fileName` configuration option (with a deprecation warning) - `HepMC.version` is honoured when spawning a child process. That is, if it is set to 2, then use compatibility reader `HepMC3::ReaderAsciiVersion2`, otherwise use the version 3 reader. If option is given with file names, then give warning that it is not used. --- .../SimulationDataFormat/MCEventHeader.h | 61 +++ Generators/CMakeLists.txt | 8 + .../include/Generators/GeneratorFileOrCmd.h | 243 +++++++++++ .../Generators/GeneratorFileOrCmdParam.h | 45 ++ .../include/Generators/GeneratorHepMC.h | 54 ++- .../include/Generators/GeneratorHepMCParam.h | 4 +- .../include/Generators/GeneratorTParticle.h | 119 ++++++ .../Generators/GeneratorTParticleParam.h | 39 ++ Generators/src/GeneratorFactory.cxx | 23 +- Generators/src/GeneratorFileOrCmd.cxx | 214 ++++++++++ Generators/src/GeneratorFileOrCmdParam.cxx | 18 + Generators/src/GeneratorHepMC.cxx | 387 +++++++++++++++--- Generators/src/GeneratorPythia8.cxx | 71 +++- Generators/src/GeneratorTParticle.cxx | 154 +++++++ Generators/src/GeneratorTParticleParam.cxx | 18 + Generators/src/GeneratorsLinkDef.h | 5 + run/CMakeLists.txt | 2 +- run/SimExamples/HepMC/README.md | 169 ++++++++ run/SimExamples/HepMC/child.sh | 53 +++ run/SimExamples/HepMC/crmc.sh | 7 + run/SimExamples/HepMC/read.sh | 48 +++ run/SimExamples/HepMC_STARlight/run.sh | 4 +- run/SimExamples/README.md | 2 + run/SimExamples/TParticle/MyEG.macro | 128 ++++++ run/SimExamples/TParticle/README.md | 265 ++++++++++++ run/SimExamples/TParticle/child.sh | 57 +++ run/SimExamples/TParticle/myeg.sh | 37 ++ run/SimExamples/TParticle/read.sh | 54 +++ 28 files changed, 2197 insertions(+), 92 deletions(-) create mode 100644 Generators/include/Generators/GeneratorFileOrCmd.h create mode 100644 Generators/include/Generators/GeneratorFileOrCmdParam.h create mode 100644 Generators/include/Generators/GeneratorTParticle.h create mode 100644 Generators/include/Generators/GeneratorTParticleParam.h create mode 100644 Generators/src/GeneratorFileOrCmd.cxx create mode 100644 Generators/src/GeneratorFileOrCmdParam.cxx create mode 100644 Generators/src/GeneratorTParticle.cxx create mode 100644 Generators/src/GeneratorTParticleParam.cxx create mode 100644 run/SimExamples/HepMC/README.md create mode 100755 run/SimExamples/HepMC/child.sh create mode 100755 run/SimExamples/HepMC/crmc.sh create mode 100755 run/SimExamples/HepMC/read.sh create mode 100644 run/SimExamples/TParticle/MyEG.macro create mode 100644 run/SimExamples/TParticle/README.md create mode 100755 run/SimExamples/TParticle/child.sh create mode 100755 run/SimExamples/TParticle/myeg.sh create mode 100755 run/SimExamples/TParticle/read.sh diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h index 1532973778eed..b0dcd6891bb9c 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h @@ -27,6 +27,67 @@ namespace dataformats class GeneratorHeader; +/** Common keys for information in MC event header */ +struct MCInfoKeys { + /** @{ +@name HepMC3 heavy-ion fields */ + static constexpr const char* impactParameter = "Bimpact"; + static constexpr const char* nPart = "Npart"; + static constexpr const char* nPartProjectile = "Npart_proj"; + static constexpr const char* nPartTarget = "Npart_targ"; + static constexpr const char* nColl = "Ncoll"; + static constexpr const char* nCollHard = "Ncoll_hard"; + static constexpr const char* nCollNNWounded = "NColl_NNw"; + static constexpr const char* nCollNWoundedN = "NColl_NwN"; + static constexpr const char* nCollNWoundedNwounded = "NColl_NwNW"; + static constexpr const char* planeAngle = "eventPsi"; + static constexpr const char* sigmaInelNN = "sigmaInelNN"; + static constexpr const char* centrality = "centrality"; + static constexpr const char* nSpecProjectileProton = "Nspec_proj_p"; + static constexpr const char* nSpecProjectileNeutron = "Nspec_proj_n"; + static constexpr const char* nSpecTargetProton = "Nspec_targ_p"; + static constexpr const char* nSpecTargetNeutron = "Nspec_targ_n"; + /** @} */ + /** @{ +@name HepMC3 PDF information + +In principle a header can have many of these. In that case, +each set should be prefixed with "_" where "" is a +serial number. + */ + static constexpr const char* pdfParton1Id = "pdf_parton_1_id"; + static constexpr const char* pdfParton2Id = "pdf_parton_2_id"; + static constexpr const char* pdfX1 = "pdf_x1"; + static constexpr const char* pdfX2 = "pdf_x2"; + static constexpr const char* pdfScale = "pdf_scale"; + static constexpr const char* pdfXF1 = "pdf_par_x1"; + static constexpr const char* pdfXF2 = "pdf_par_x2"; + static constexpr const char* pdfCode1 = "pdf_lhc_1_id"; + static constexpr const char* pdfCode2 = "pdf_lhc_2_id"; + /** @} */ + /** @{ +@name HepMC3 cross-section information + +In principle we can have one cross section per weight. In that +case, each should be post-fixed by "_" where "" is a +serial number. These should then matcht possible names of +weights. + */ + static constexpr const char* acceptedEvents = "accepted_events"; + static constexpr const char* attemptedEvents = "attempted_events"; + static constexpr const char* xSection = "cross_section"; + static constexpr const char* xSectionError = "cross_section_error"; + /** @} */ + /** @{ +@name Common fields */ + static constexpr const char* generator = "generator"; + static constexpr const char* generatorVersion = "version"; + static constexpr const char* processName = "processName"; + static constexpr const char* processCode = "processCode"; + static constexpr const char* weight = "weight"; + /** @} */ +}; + /*****************************************************************/ /*****************************************************************/ diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 0b0f92955a651..f8551a9e5e8ba 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -29,6 +29,8 @@ o2_add_library(Generators src/GeneratorExternalParam.cxx src/GeneratorFromFile.cxx src/GeneratorFromO2KineParam.cxx + src/GeneratorFileOrCmd.cxx + src/GeneratorFileOrCmdParam.cxx src/PrimaryGenerator.cxx src/PrimaryGeneratorParam.cxx src/TriggerExternalParam.cxx @@ -38,6 +40,8 @@ o2_add_library(Generators src/GenCosmicsParam.cxx src/GeneratorFactory.cxx src/GeneratorGeantinos.cxx + src/GeneratorTParticle.cxx + src/GeneratorTParticleParam.cxx $<$:src/GeneratorPythia6.cxx> $<$:src/GeneratorPythia6Param.cxx> $<$:src/GeneratorPythia8.cxx> @@ -71,6 +75,8 @@ set(headers include/Generators/GeneratorExternalParam.h include/Generators/GeneratorFromFile.h include/Generators/GeneratorFromO2KineParam.h + include/Generators/GeneratorFileOrCmd.h + include/Generators/GeneratorFileOrCmdParam.h include/Generators/PrimaryGenerator.h include/Generators/PrimaryGeneratorParam.h include/Generators/TriggerExternalParam.h @@ -79,6 +85,8 @@ set(headers include/Generators/QEDGenParam.h include/Generators/GenCosmicsParam.h include/Generators/GeneratorGeantinos.h + include/Generators/GeneratorTParticle.h + include/Generators/GeneratorTParticleParam.h ) if (pythia6_FOUND) diff --git a/Generators/include/Generators/GeneratorFileOrCmd.h b/Generators/include/Generators/GeneratorFileOrCmd.h new file mode 100644 index 0000000000000..0c9c618928549 --- /dev/null +++ b/Generators/include/Generators/GeneratorFileOrCmd.h @@ -0,0 +1,243 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author Christian Holm Christensen + +#ifndef ALICEO2_EVENTGEN_GENERATORFILEORCMD_H_ +#define ALICEO2_EVENTGEN_GENERATORFILEORCMD_H_ +#include +#include +#include + +namespace o2 +{ +namespace conf +{ +class SimConfig; +} +namespace eventgen +{ + +/** Service class for either reading from a file or executing a + program writing to a specific file */ +struct GeneratorFileOrCmd { + /** + * Configure the generator from parameters and the general + * simulation configuration. This is implemented as a member + * function so as to better facilitate changes. */ + void setup(const GeneratorFileOrCmdParam& param, + const conf::SimConfig& config); + /** + * Set command to execute in bacground rather than reading from + * existing file(s) + * + * @param cmd Command line. Can include options for the program to + * execute, but should not include pipes. + */ + void setCmd(const std::string& cmd) { mCmd = cmd; } + /** + * Set the number of events that a background command should + * generate. This should come from @c SimConfig::getNEents. + * + * @param nev Number of events to generate. This is passed via @c + * mNEventsSwitch to the command line. + */ + void setNEvents(unsigned int nev) { mNEvents = nev; } + /** + * Set the random number seed that a background command should use. + * This should come from @c SimConfig::getStartSeed + * + * @param seed Random number seed. Will be passed to the + * commandline using the @c mSeedSwitch. + */ + void setSeed(unsigned long seed) { mSeed = seed; } + /** + * Set the maximum impact parameter to sample by a background + * command. This should come from @c SimConfig::getBMax() + * + * @param bmax Maximum impact parameter, in fm, to sample. This is + * passed to the command line via the @c mBmaxSwitch. + */ + void setBmax(float bmax) { mBmax = bmax; } + /** + * Set the file names to read from. + * + * @param filenames A comma seperated list of files to read from. + */ + void setFileNames(const std::string& filenames); + /** + * Set the output switch. + * + * @param opt Command line switch (e.g., @c -o) to specify output + * file name. */ + void setOutputSwitch(const std::string& opt) { mOutputSwitch = opt; } + /** + * Set the seed switch. + * + * @param opt Command line switch (e.g., @c -s) to specify the + * random number seed to use when generating events. + */ + void setSeedSwitch(const std::string& opt) { mSeedSwitch = opt; } + /** + * Set the nevents switch. + * + * @param opt Command line switch (e.g., @c -n) to specify the + * number of events to generate. + */ + void setNEventsSwitch(const std::string& opt) { mNEventsSwitch = opt; } + /** + * Set the maximum impact parameter switch. + * + * @param opt Command line switch (e.g., @c -b) to specify the + * maximum impact parameter (in fm) to sample when generating + * events. + */ + void setBmaxSwitch(const std::string& opt) { mBmaxSwitch = opt; } + /** + * Set the background switch. + * + * @param opt Command line switch (e.g., @c &) to detach and send + * the event generator program into the background. + */ + void setBackgroundSwitch(const std::string& opt) { mBackgroundSwitch = opt; } + /** Set the wait time, in miliseconds, when waiting for data */ + void setWait(int miliseconds = 500) { mWait = miliseconds; } + + protected: + /** + * Format a command line using the set command line, option flags, + * and option values. + * + * @return formatted command line. + */ + virtual std::string makeCmdLine() const; + /** + * Execute a command line (presumably formatted by @c makeCmdLine). + * If the command failed to execute, then make it a fatal error. + * + * @param cmd Command line to execute, presumabley formatted by @c + * makeCmdLine. + + * @return true if the background command line was executed, false + * otherwise. + */ + virtual bool executeCmdLine(const std::string& cmd) const; + /** + * Create a temporary file (and close it immediately). On success, + * the list of file names is cleared and the name of the temporary + * file set as the sole element in that list. + * + * @return true if the temporary file name was generated + * successfully. + */ + virtual bool makeTemp(); + /** + * Remove the temporary file if it was set and it exists. + * + * @return true if the temporary file was removed. + */ + virtual bool removeTemp() const; + /** + * Make a fifo at the location of the first element of the list of + * file names (presumably a temporary file as created by + * makeTemp). + * + * @return true if the FIFo was made correctly + */ + virtual bool makeFifo() const; + /** + * Ensure that all files in the list of file names exists. If @e + * any of te file names point to a net resource (e.g., @c alien://or + * @c https://) then this member function should @e not be called + * + * The file names registered are replaced with their canonical path + * equivalents. + * + * @return true if all currently registered file names can be found. + */ + virtual bool ensureFiles(); + /** + * Wait for data to be available in case we're executing a + * background command + */ + virtual void waitForData(const std::string& filename) const; + /** + * Possible command line to execute. The command executed must + * accept the switches defined below. Note if @c mOutputSwitch is + * set to @c ">", then the program @e must write data to standard + * output + */ + std::string mCmd = ""; + /** + * List of file names to read. In case we're executing a command, + * then there will only be one file name in the list + */ + std::list mFileNames; + /** + * Name of temporary file, if it was created. + */ + std::string mTemporary; + /** + * Number of events to generate in case we're executing a command. + * This is passed to the program via the switch @c + * mNEventsSwitch + */ + unsigned int mNEvents = 0; + /** + * Random number seed to use in case we're executing a command. + * This is passed to the program via the switch @c + * mSeedSwitch + */ + unsigned long mSeed = 0; + /** + * Maximum impact parameter to sample in case we're executing a + * command. IF negative, then it is not passed to the command. + * This is passed to the command via the switch @c mBmaxSwitch + */ + float mBmax = -1.f; + /** + * Switch to direct output to specified file. In case of a fifo, + * this should often be @c ">" - i.e., the standard output of the + * program is redirected to the fifo. + */ + std::string mOutputSwitch = ">"; + /** + * The switch specify the random number seed to the program + * executed + */ + std::string mSeedSwitch = "-s"; + /** + * The switch to specify the number of events to generate to the + * program being executed + */ + std::string mNEventsSwitch = "-n"; + /** + * The switch to specify maximum impact parameter to sample by the + * program being executed. + */ + std::string mBmaxSwitch = "-b"; + /** + * The "switch" to put the program being executed in the + * background. + */ + std::string mBackgroundSwitch = "&"; + /** + * Time in miliseconds between each wait for data + */ + int mWait = 500; +}; + +} // namespace eventgen +} // namespace o2 +#endif +// Local Variables: +// mode: C++ +// End: diff --git a/Generators/include/Generators/GeneratorFileOrCmdParam.h b/Generators/include/Generators/GeneratorFileOrCmdParam.h new file mode 100644 index 0000000000000..fe6dfa3a80722 --- /dev/null +++ b/Generators/include/Generators/GeneratorFileOrCmdParam.h @@ -0,0 +1,45 @@ +// Copyright 2023-2099 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author Christian Holm Christensen + +#ifndef ALICEO2_EVENTGEN_GENERATORFILEORCMDPARAM_H_ +#define ALICEO2_EVENTGEN_GENERATORFILEORCMDPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" +#include + +namespace o2 +{ +namespace eventgen +{ + +/** + ** a parameter class/struct to keep the settings of + ** the Fileorcmd event generator and + ** allow the user to modify them + **/ +struct GeneratorFileOrCmdParam : public o2::conf::ConfigurableParamHelper { + std::string fileNames = ""; + std::string cmd = ""; // Program command line to spawn + std::string outputSwitch = ">"; + std::string seedSwitch = "-s"; + std::string bMaxSwitch = "-b"; + std::string nEventsSwitch = "-n"; + std::string backgroundSwitch = "&"; + O2ParamDef(GeneratorFileOrCmdParam, "GeneratorFileOrCmd"); +}; + +} // end namespace eventgen +} // end namespace o2 + +#endif // ALICEO2_EVENTGEN_GENERATORFILEORCMDPARAM_H_ diff --git a/Generators/include/Generators/GeneratorHepMC.h b/Generators/include/Generators/GeneratorHepMC.h index 341f4b8a0e38a..9a5c607f209da 100644 --- a/Generators/include/Generators/GeneratorHepMC.h +++ b/Generators/include/Generators/GeneratorHepMC.h @@ -15,7 +15,8 @@ #define ALICEO2_EVENTGEN_GENERATORHEPMC_H_ #include "Generators/Generator.h" -#include +#include "Generators/GeneratorFileOrCmd.h" +#include "Generators/GeneratorHepMCParam.h" #ifdef GENERATORS_WITH_HEPMC3_DEPRECATED namespace HepMC @@ -35,33 +36,51 @@ class FourVector; namespace o2 { +namespace conf +{ +class SimConfig; +} namespace eventgen { /*****************************************************************/ /*****************************************************************/ -class GeneratorHepMC : public Generator +class GeneratorHepMC : public Generator, public GeneratorFileOrCmd { public: /** default constructor **/ GeneratorHepMC(); /** constructor **/ - GeneratorHepMC(const Char_t* name, const Char_t* title = "ALICEo2 HepMC Generator"); + GeneratorHepMC(const Char_t* name, + const Char_t* title = "ALICEo2 HepMC Generator"); /** destructor **/ ~GeneratorHepMC() override; - /** Initialize the generator if needed **/ + /** Initialize the generator. **/ Bool_t Init() override; - /** methods to override **/ + /** + * Configure the generator from parameters and the general + * simulation configuration. This is implemented as a member + * function so as to better facilitate changes. */ + void setup(const GeneratorFileOrCmdParam& param0, + const GeneratorHepMCParam& param, + const conf::SimConfig& config); + /** + * Generate a single event. The event is read in from the current + * input file. Returns false if a new event could not be read. + **/ Bool_t generateEvent() override; + /** + * Import particles from the last read event into a vector + * TParticle. Returns false if no particles could be exported to + * the vector. + */ Bool_t importParticles() override; /** setters **/ - void setVersion(Int_t val) { mVersion = val; }; - void setFileName(std::string val) { mFileName = val; }; void setEventsToSkip(uint64_t val) { mEventsToSkip = val; }; protected: @@ -77,18 +96,17 @@ class GeneratorHepMC : public Generator const HepMC3::FourVector getBoostedVector(const HepMC3::FourVector& vector, Double_t boost); #endif + /** methods that can be overridded **/ + void updateHeader(o2::dataformats::MCEventHeader* eventHeader) override; + /** Make our reader */ + bool makeReader(); + /** HepMC interface **/ - std::ifstream mStream; //! - std::string mFileName; - Int_t mVersion; - uint64_t mEventsToSkip; -#ifdef GENERATORS_WITH_HEPMC3_DEPRECATED - HepMC::Reader* mReader; //! - HepMC::GenEvent* mEvent; //! -#else - HepMC3::Reader* mReader; //! - HepMC3::GenEvent* mEvent; //! -#endif + uint64_t mEventsToSkip = 0; + int mVersion = 0; + std::shared_ptr mReader; + /** Event structure */ + HepMC3::GenEvent* mEvent = nullptr; ClassDefOverride(GeneratorHepMC, 1); diff --git a/Generators/include/Generators/GeneratorHepMCParam.h b/Generators/include/Generators/GeneratorHepMCParam.h index 4c53918c70634..5df4013489f95 100644 --- a/Generators/include/Generators/GeneratorHepMCParam.h +++ b/Generators/include/Generators/GeneratorHepMCParam.h @@ -30,9 +30,9 @@ namespace eventgen **/ struct GeneratorHepMCParam : public o2::conf::ConfigurableParamHelper { - std::string fileName = ""; - int version = 2; + int version = 0; uint64_t eventsToSkip = 0; + std::string fileName = ""; O2ParamDef(GeneratorHepMCParam, "HepMC"); }; diff --git a/Generators/include/Generators/GeneratorTParticle.h b/Generators/include/Generators/GeneratorTParticle.h new file mode 100644 index 0000000000000..e4ddb5fa1f340 --- /dev/null +++ b/Generators/include/Generators/GeneratorTParticle.h @@ -0,0 +1,119 @@ +// Copyright 2023-2099 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author: Christian Holm Christensen +#ifndef ALICEO2_GENERATORTPARTICLE_H_ +#define ALICEO2_GENERATORTPARTICLE_H_ +#include +#include +#include +#include + +// Forward decls +class TChain; +class TParticle; +class TClonesArray; + +namespace o2 +{ +namespace conf +{ +class SimConfig; +} +namespace eventgen +{ +/// A class that reads in particles of class @c TParticle from a +/// branch in a @c TChain. +/// +/// Optionally, a program that generates such a @c TTree can be +/// spawn, and the @c TParticles written to a file from which this +/// object reads them in. This is done with +/// +/// --configKeyValues "TParticle.progCmd=" +/// +/// which will execute the specified EG program with the given +/// options. The EG program _must_ support the command line options +/// +/// -n NUMBER Number of events to generate +/// -o FILENAME Name of file to write to +/// +/// The tree name and particle branch names can be configured. +/// +/// --configKeyValues "TParticle.treeName=T,TParticle.branchName=P" +/// +/// File(s) to read are also configurable +/// +/// --configKeyValues "TParticle.fileNames=foo.root,bar.root" +/// +class GeneratorTParticle : public Generator, public GeneratorFileOrCmd +{ + public: + /** CTOR */ + GeneratorTParticle(); + /** CTOR */ + GeneratorTParticle(const std::string& name) + : Generator(name.c_str(), "ALICEo2 TParticle Generator") + { + } + /** DTOR */ + virtual ~GeneratorTParticle(); + + /** Initialize this generator. This will set up the chain. + * Optionally, if a command line was specified by @c + * TParticle.progCmd then that command line is executed in the + * background and events are read from the output file of that + * program */ + Bool_t Init() override; + + /** + * Configure the generator from parameters and the general + * simulation configuration. This is implemented as a member + * function so as to better facilitate changes. */ + void setup(const GeneratorFileOrCmdParam& param0, + const GeneratorTParticleParam& param, + const conf::SimConfig& config); + /** Read in the next entry from the chain. Returns false in case of + * errors or no more entries to read. */ + Bool_t generateEvent() override; + + /** Import the read-in particles into the steer particle stack */ + Bool_t importParticles() override; + + /** Set the name of the tree in the files. The tree _must_ reside + * in the top-level directory of the files. */ + void setTreeName(const std::string& val) { mTreeName = val; } + /** Set the branch name of the branch that holds a @c TClonesArray + * of @c TParticle objects */ + void setBranchName(const std::string& val) { mBranchName = val; } + + protected: + /** Name of the tree to read */ + std::string mTreeName = "T"; + /** Name of branch containing a TClonesArray of TParticle */ + std::string mBranchName = "Particles"; + /** Current entry */ + unsigned int mEntry = 0; + /** Chain of files */ + TChain* mChain = 0; + /** Array to read particles into */ + TClonesArray* mTParticles; + + ClassDefOverride(GeneratorTParticle, 1); +}; +} // namespace eventgen +} // namespace o2 +#endif +// Local Variables: +// mode: C++ +// End: +// +// EOF +// diff --git a/Generators/include/Generators/GeneratorTParticleParam.h b/Generators/include/Generators/GeneratorTParticleParam.h new file mode 100644 index 0000000000000..98059f3b0e1e6 --- /dev/null +++ b/Generators/include/Generators/GeneratorTParticleParam.h @@ -0,0 +1,39 @@ +// Copyright 2023-2099 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// @author: Christian Holm Christensen +#ifndef ALICEO2_EVENTGEN_GENERATORTPARTICLEPARAM_H_ +#define ALICEO2_EVENTGEN_GENERATORTPARTICLEPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" +#include +namespace o2 +{ +namespace eventgen +{ + +/** + * a parameter class/struct to keep the settings of the TGenerator + * event generator and allow the user to modify them + */ +struct GeneratorTParticleParam : public o2::conf::ConfigurableParamHelper { + std::string treeName = "T"; + std::string branchName = "Particles"; + O2ParamDef(GeneratorTParticleParam, "GeneratorTParticle"); +}; +} // end namespace eventgen +} // end namespace o2 + +#endif // ALICEO2_EVENTGEN_GENERATORHEPMCPARAM_H_ +// Local Variables: +// mode: C++ +// End: diff --git a/Generators/src/GeneratorFactory.cxx b/Generators/src/GeneratorFactory.cxx index abe22a6fe75fe..80e80dbefa091 100644 --- a/Generators/src/GeneratorFactory.cxx +++ b/Generators/src/GeneratorFactory.cxx @@ -18,6 +18,8 @@ #include #include #include +#include +#include #ifdef GENERATORS_WITH_PYTHIA6 #include #include @@ -86,6 +88,7 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair o2::O2DatabasePDG::addALICEParticles(TDatabasePDG::Instance()); auto genconfig = conf.getGenerator(); + LOG(info) << "** Generator to use: '" << genconfig << "'"; if (genconfig.compare("boxgen") == 0) { // a simple "box" generator configurable via BoxGunparam auto& boxparam = BoxGunParam::Instance(); @@ -156,16 +159,28 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair } } LOG(info) << "using external O2 kinematics"; + } else if (genconfig.compare("tparticle") == 0) { + // External ROOT file(s) with tree of TParticle in clones array, + // or external program generating such a file + auto& param0 = GeneratorFileOrCmdParam::Instance(); + auto& param = GeneratorTParticleParam::Instance(); + LOG(info) << "Init 'GeneratorTParticle' with the following parameters"; + LOG(info) << param0; + LOG(info) << param; + auto tgen = new o2::eventgen::GeneratorTParticle(); + tgen->setup(param0, param, conf); + primGen->AddGenerator(tgen); #ifdef GENERATORS_WITH_HEPMC3 } else if (genconfig.compare("hepmc") == 0) { - // external HepMC file + // external HepMC file, or external program writing HepMC event + // records to standard output. + auto& param0 = GeneratorFileOrCmdParam::Instance(); auto& param = GeneratorHepMCParam::Instance(); LOG(info) << "Init \'GeneratorHepMC\' with following parameters"; + LOG(info) << param0; LOG(info) << param; auto hepmcGen = new o2::eventgen::GeneratorHepMC(); - hepmcGen->setFileName(param.fileName); - hepmcGen->setVersion(param.version); - hepmcGen->setEventsToSkip(param.eventsToSkip); + hepmcGen->setup(param0, param, conf); primGen->AddGenerator(hepmcGen); #endif #ifdef GENERATORS_WITH_PYTHIA6 diff --git a/Generators/src/GeneratorFileOrCmd.cxx b/Generators/src/GeneratorFileOrCmd.cxx new file mode 100644 index 0000000000000..9ff45bcd9c867 --- /dev/null +++ b/Generators/src/GeneratorFileOrCmd.cxx @@ -0,0 +1,214 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author Christian Holm Christensen + +#include "SimulationDataFormat/MCUtils.h" +#include "Generators/GeneratorFileOrCmd.h" +// For fifo's and system call +#include +#include // POSIX only +#include // POISX only +#include +// For filesystem operations +#include +// Waits +#include +// Log messages +#include +#include + +namespace +{ +std::string ltrim(const std::string& s, const std::string& what = "\" ' ") +{ + auto start = s.find_first_not_of(what); + if (start == std::string::npos) { + return ""; + } + + return s.substr(start); +} + +std::string rtrim(const std::string& s, const std::string& what = "\"' ") +{ + auto end = s.find_last_not_of(what); + return s.substr(0, end + 1); +} + +std::string trim(const std::string& s, const std::string& what = "\"' ") +{ + return rtrim(ltrim(s, what), what); +} +} // namespace + +namespace o2 +{ +namespace eventgen +{ +// ----------------------------------------------------------------- +void GeneratorFileOrCmd::setup(const GeneratorFileOrCmdParam& param, + const conf::SimConfig& config) +{ + setFileNames(param.fileNames); + setCmd(param.cmd); + setOutputSwitch(trim(param.outputSwitch)); + setSeedSwitch(trim(param.seedSwitch)); + setBmaxSwitch(trim(param.bMaxSwitch)); + setNEventsSwitch(trim(param.nEventsSwitch)); + setBackgroundSwitch(trim(param.backgroundSwitch)); + setSeed(config.getStartSeed()); + setNEvents(config.getNEvents()); + setBmax(config.getBMax()); +} +// ----------------------------------------------------------------- +void GeneratorFileOrCmd::setFileNames(const std::string& filenames) +{ + std::stringstream s(filenames); + std::string f; + while (std::getline(s, f, ',')) { + mFileNames.push_back(f); + } +} +// ----------------------------------------------------------------- +std::string GeneratorFileOrCmd::makeCmdLine() const +{ + std::string fileName = mFileNames.front(); + std::stringstream s; + s << mCmd << " "; + if (not mSeedSwitch.empty() and mSeedSwitch != "none") { + s << mSeedSwitch << " " << mSeed << " "; + } + if (not mNEventsSwitch.empty() and mNEventsSwitch != "none") { + s << mNEventsSwitch << " " << mNEvents << " "; + } + if (not mBmaxSwitch.empty() and mBmax >= 0 and mBmaxSwitch != "none") { + s << mBmaxSwitch.c_str() << " " << mBmax << " "; + } + + s << mOutputSwitch << " " << fileName << " " + << mBackgroundSwitch; + return s.str(); +} +// ----------------------------------------------------------------- +bool GeneratorFileOrCmd::executeCmdLine(const std::string& cmd) const +{ + LOG(info) << "Command line to execute: \"" << cmd << "\""; + int ret = std::system(cmd.c_str()); + if (ret != 0) { + LOG(fatal) << "Failed to spawn \"" << cmd << "\""; + return false; + } + return true; +} +// ----------------------------------------------------------------- +bool GeneratorFileOrCmd::makeTemp() +{ + mFileNames.clear(); + char buf[] = "generatorFifoXXXXXX"; + auto fp = mkstemp(buf); + if (fp < 0) { + LOG(fatal) << "Failed to make temporary file: " + << std::strerror(errno); + return false; + } + mTemporary = std::string(buf); + mFileNames.push_back(mTemporary); + close(fp); + return true; +} +// ----------------------------------------------------------------- +bool GeneratorFileOrCmd::removeTemp() const +{ + if (mTemporary.empty()) { + LOG(info) << "Temporary file name empty, nothing to remove"; + return false; + } + + // Get the file we're reading from + std::filesystem::path p(mTemporary); + + // Check if the file exists + if (not std::filesystem::exists(p)) { + LOG(info) << "Temporary file " << p << " does not exist"; + return true; + } + + // Remove temporary file + std::error_code ec; + std::filesystem::remove(p, ec); + if (ec) { + LOG(warn) << "When removing " << p << ": " << ec.message(); + } + + // Ignore errors when removing the temporary file + return true; +} +// ----------------------------------------------------------------- +bool GeneratorFileOrCmd::makeFifo() const +{ + // First remove the temporary file if it exists, + // otherwise we may not be able to make the FIFO + removeTemp(); + + std::string fileName = mFileNames.front(); + + int ret = mkfifo(fileName.c_str(), 0600); + if (ret != 0) { + LOG(fatal) << "Failed to make fifo \"" << fileName << "\": " + << std::strerror(errno); + return false; + } + + return true; +} +// ----------------------------------------------------------------- +bool GeneratorFileOrCmd::ensureFiles() +{ + try { + for (auto& f : mFileNames) { + auto c = std::filesystem::canonical(std::filesystem::path(f)); + f = c.c_str(); + } + } catch (std::exception& e) { + LOG(error) << e.what(); + return false; + } + return true; +} +// ----------------------------------------------------------------- +void GeneratorFileOrCmd::waitForData(const std::string& filename) const +{ + using namespace std::chrono_literals; + + // Get the file we're reading from + std::filesystem::path p(filename); + + LOG(debug) << "Waiting for data on " << p; + + // Wait until child process creates the file + while (not std::filesystem::exists(p)) { + std::this_thread::sleep_for(mWait * 1ms); + } + + // Wait until we have more data in the file than just the file + // header + while (std::filesystem::file_size(p) <= 256) { + std::this_thread::sleep_for(mWait * 1ms); + } + + // Give the child process 1 second to post the data to the file + LOG(debug) << "Got data in " << p << ", sleeping for a while"; + std::this_thread::sleep_for(mWait * 2ms); +} + +} /* namespace eventgen */ +} /* namespace o2 */ diff --git a/Generators/src/GeneratorFileOrCmdParam.cxx b/Generators/src/GeneratorFileOrCmdParam.cxx new file mode 100644 index 0000000000000..e452f272c3735 --- /dev/null +++ b/Generators/src/GeneratorFileOrCmdParam.cxx @@ -0,0 +1,18 @@ +// Copyright 2023-2099 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author Christian Holm Christensen + +#include "Generators/GeneratorFileOrCmdParam.h" +O2ParamImpl(o2::eventgen::GeneratorFileOrCmdParam); +// +// EOF +// diff --git a/Generators/src/GeneratorHepMC.cxx b/Generators/src/GeneratorHepMC.cxx index 6c062268bfacc..3fec13ae490d2 100644 --- a/Generators/src/GeneratorHepMC.cxx +++ b/Generators/src/GeneratorHepMC.cxx @@ -14,14 +14,15 @@ #include "SimulationDataFormat/MCUtils.h" #include "Generators/GeneratorHepMC.h" #include "Generators/GeneratorHepMCParam.h" -#include "HepMC3/ReaderAscii.h" -#include "HepMC3/ReaderAsciiHepMC2.h" +#include "SimulationDataFormat/MCEventHeader.h" +#include "SimConfig/SimConfig.h" +#include "HepMC3/ReaderFactory.h" #include "HepMC3/GenEvent.h" #include "HepMC3/GenParticle.h" #include "HepMC3/GenVertex.h" #include "HepMC3/FourVector.h" +#include "HepMC3/Version.h" #include "TParticle.h" -#include "TSystem.h" #include #include "FairPrimaryGenerator.h" @@ -36,19 +37,14 @@ namespace eventgen /*****************************************************************/ GeneratorHepMC::GeneratorHepMC() - : Generator("ALICEo2", "ALICEo2 HepMC Generator"), mStream(), mFileName(), mVersion(3), mReader(nullptr), mEvent(nullptr) + : GeneratorHepMC("ALICEo2", "ALICEo2 HepMC Generator") { - /** default constructor **/ - - mEvent = new HepMC3::GenEvent(); - mInterface = reinterpret_cast(mEvent); - mInterfaceName = "hepmc"; } /*****************************************************************/ GeneratorHepMC::GeneratorHepMC(const Char_t* name, const Char_t* title) - : Generator(name, title), mStream(), mFileName(), mVersion(3), mReader(nullptr), mEvent(nullptr) + : Generator(name, title) { /** constructor **/ @@ -62,36 +58,66 @@ GeneratorHepMC::GeneratorHepMC(const Char_t* name, const Char_t* title) GeneratorHepMC::~GeneratorHepMC() { /** default destructor **/ - - if (mStream.is_open()) { - mStream.close(); - } + LOG(info) << "Destructing GeneratorHepMC"; if (mReader) { mReader->close(); - delete mReader; } if (mEvent) { delete mEvent; } + removeTemp(); } /*****************************************************************/ +void GeneratorHepMC::setup(const GeneratorFileOrCmdParam& param0, + const GeneratorHepMCParam& param, + const conf::SimConfig& config) +{ + if (not param.fileName.empty()) { + LOG(warn) << "The use of the key \"HepMC.fileName\" is " + << "deprecated, use \"GeneratorFileOrCmd.fileNames\" instead"; + } + + GeneratorFileOrCmd::setup(param0, config); + if (not param.fileName.empty()) { + setFileNames(param.fileName); + } + mVersion = param.version; + setEventsToSkip(param.eventsToSkip); + + if (param.version != 0 and mCmd.empty()) { + LOG(warn) << "The key \"HepMC.version\" is no longer used when " + << "reading from files. The format version of the input files " + << "are automatically deduced."; + } +} + +/*****************************************************************/ Bool_t GeneratorHepMC::generateEvent() { + LOG(debug) << "Generating an event"; /** generate event **/ + int tries = 0; + do { + LOG(debug) << " try # " << ++tries; + if (not mReader and not makeReader()) { + return false; + } - /** clear and read event **/ - mEvent->clear(); - mReader->read_event(*mEvent); - if (mReader->failed()) { - return kFALSE; - } - /** set units to desired output **/ - mEvent->set_units(HepMC3::Units::GEV, HepMC3::Units::MM); + /** clear and read event **/ + mEvent->clear(); + mReader->read_event(*mEvent); + if (not mReader->failed()) { + /** set units to desired output **/ + mEvent->set_units(HepMC3::Units::GEV, HepMC3::Units::MM); + LOG(debug) << "Read one event " << mEvent->event_number(); + return true; + } + } while (true); - /** success **/ - return kTRUE; + /** failure **/ + return false; } /*****************************************************************/ @@ -143,6 +169,213 @@ Bool_t GeneratorHepMC::importParticles() return kTRUE; } +namespace +{ +template +bool putAttributeInfoImpl(o2::dataformats::MCEventHeader* eventHeader, + const std::string& name, + const std::shared_ptr& a) +{ + if (auto* p = dynamic_cast(a.get())) { + eventHeader->putInfo(name, p->value()); + return true; + } + return false; +} + +void putAttributeInfo(o2::dataformats::MCEventHeader* eventHeader, + const std::string& name, + const std::shared_ptr& a) +{ + using IntAttribute = HepMC3::IntAttribute; + using LongAttribute = HepMC3::LongAttribute; + using FloatAttribute = HepMC3::FloatAttribute; + using DoubleAttribute = HepMC3::DoubleAttribute; + using StringAttribute = HepMC3::StringAttribute; + using CharAttribute = HepMC3::CharAttribute; + using LongLongAttribute = HepMC3::LongLongAttribute; + using LongDoubleAttribute = HepMC3::LongDoubleAttribute; + using UIntAttribute = HepMC3::UIntAttribute; + using ULongAttribute = HepMC3::ULongAttribute; + using ULongLongAttribute = HepMC3::ULongLongAttribute; + using BoolAttribute = HepMC3::BoolAttribute; + + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } +} +} // namespace + +/*****************************************************************/ + +void GeneratorHepMC::updateHeader(o2::dataformats::MCEventHeader* eventHeader) +{ + /** update header **/ + using Key = o2::dataformats::MCInfoKeys; + + eventHeader->putInfo(Key::generator, "hepmc"); + eventHeader->putInfo(Key::generatorVersion, HEPMC3_VERSION_CODE); + + auto xSection = mEvent->cross_section(); + auto pdfInfo = mEvent->pdf_info(); + auto hiInfo = mEvent->heavy_ion(); + + // Set default cross-section + if (xSection) { + eventHeader->putInfo(Key::xSection, xSection->xsec()); + eventHeader->putInfo(Key::xSectionError, xSection->xsec_err()); + eventHeader->putInfo(Key::acceptedEvents, + xSection->get_accepted_events()); + eventHeader->putInfo(Key::attemptedEvents, + xSection->get_attempted_events()); + } + + // Set weights and cross sections + size_t iw = 0; + for (auto w : mEvent->weights()) { + std::string post = (iw > 0 ? "_" + std::to_string(iw) : ""); + eventHeader->putInfo(Key::weight + post, w); + if (xSection) { + eventHeader->putInfo(Key::xSection, xSection->xsec(iw)); + eventHeader->putInfo(Key::xSectionError, xSection->xsec_err(iw)); + } + iw++; + } + + // Set the PDF information + if (pdfInfo) { + eventHeader->putInfo(Key::pdfParton1Id, pdfInfo->parton_id[0]); + eventHeader->putInfo(Key::pdfParton2Id, pdfInfo->parton_id[1]); + eventHeader->putInfo(Key::pdfX1, pdfInfo->x[0]); + eventHeader->putInfo(Key::pdfX2, pdfInfo->x[1]); + eventHeader->putInfo(Key::pdfScale, pdfInfo->scale); + eventHeader->putInfo(Key::pdfXF1, pdfInfo->xf[0]); + eventHeader->putInfo(Key::pdfXF2, pdfInfo->xf[1]); + eventHeader->putInfo(Key::pdfCode1, pdfInfo->pdf_id[0]); + eventHeader->putInfo(Key::pdfCode2, pdfInfo->pdf_id[1]); + } + + // Set heavy-ion information + if (hiInfo) { + eventHeader->putInfo(Key::impactParameter, + hiInfo->impact_parameter); + eventHeader->putInfo(Key::nPart, + hiInfo->Npart_proj + hiInfo->Npart_targ); + eventHeader->putInfo(Key::nPartProjectile, hiInfo->Npart_proj); + eventHeader->putInfo(Key::nPartTarget, hiInfo->Npart_targ); + eventHeader->putInfo(Key::nColl, hiInfo->Ncoll); + eventHeader->putInfo(Key::nCollHard, hiInfo->Ncoll_hard); + eventHeader->putInfo(Key::nCollNNWounded, + hiInfo->N_Nwounded_collisions); + eventHeader->putInfo(Key::nCollNWoundedN, + hiInfo->Nwounded_N_collisions); + eventHeader->putInfo(Key::nCollNWoundedNwounded, + hiInfo->Nwounded_Nwounded_collisions); + eventHeader->putInfo(Key::planeAngle, + hiInfo->event_plane_angle); + eventHeader->putInfo(Key::sigmaInelNN, + hiInfo->sigma_inel_NN); + eventHeader->putInfo(Key::centrality, hiInfo->centrality); + eventHeader->putInfo(Key::nSpecProjectileProton, hiInfo->Nspec_proj_p); + eventHeader->putInfo(Key::nSpecProjectileNeutron, hiInfo->Nspec_proj_n); + eventHeader->putInfo(Key::nSpecTargetProton, hiInfo->Nspec_targ_p); + eventHeader->putInfo(Key::nSpecTargetNeutron, hiInfo->Nspec_targ_n); + } + + for (auto na : mEvent->attributes()) { + std::string name = na.first; + if (name == "GenPdfInfo" || + name == "GenCrossSection" || + name == "GenHeavyIon") { + continue; + } + + for (auto ia : na.second) { + int no = ia.first; + auto at = ia.second; + std::string post = (no == 0 ? "" : std::to_string(no)); + + putAttributeInfo(eventHeader, name + post, at); + } + } +} + +/*****************************************************************/ + +bool GeneratorHepMC::makeReader() +{ + // Reset the reader smart pointer + LOG(debug) << "Reseting the reader"; + mReader.reset(); + + // Check that we have any file names left + if (mFileNames.size() < 1) { + LOG(debug) << "No more files to read, return false"; + return false; + } + + // If we have file names left, pop the top of the list (LIFO) + auto filename = mFileNames.front(); + mFileNames.pop_front(); + + LOG(debug) << "Next file to read: \"" << filename << "\" " + << mFileNames.size() << " left"; + + if (not mCmd.empty()) { + // For FIFO reading, we assume straight ASCII output always. + // Unfortunately, the HepMC3::deduce_reader `stat`s the filename + // which isn't supported on a FIFO, so we have to use the reader + // directly. Here, we allow for version 2 formats if the user + // specifies that + LOG(info) << "Creating ASCII reader of " << filename; + if (mVersion == 2) { + mReader.reset(new HepMC3::ReaderAsciiHepMC2(filename)); + } else { + mReader.reset(new HepMC3::ReaderAscii(filename)); + } + } else { + LOG(info) << "Deduce a reader of " << filename; + mReader = HepMC3::deduce_reader(filename); + } + + bool ret = bool(mReader) and not mReader->failed(); + LOG(info) << "Reader is " << mReader.get() << " " << ret; + return ret; +} + /*****************************************************************/ Bool_t GeneratorHepMC::Init() @@ -152,41 +385,81 @@ Bool_t GeneratorHepMC::Init() /** init base class **/ Generator::Init(); - /** open file **/ - std::string filename = gSystem->ExpandPathName(mFileName.c_str()); - mStream.open(filename); - if (!mStream.is_open()) { - LOG(fatal) << "Cannot open input file: " << filename << std::endl; - return kFALSE; - } - - /** create reader according to HepMC version **/ - switch (mVersion) { - case 2: - mStream.close(); - mReader = new HepMC3::ReaderAsciiHepMC2(filename); - break; - case 3: - mReader = new HepMC3::ReaderAscii(mStream); - break; - default: - LOG(fatal) << "Unsupported HepMC version: " << mVersion << std::endl; - return kFALSE; - } - - // skip events at the beginning - if (!mReader->failed()) { - LOGF(info, "%i events to skip.", mEventsToSkip); - for (auto ind = 0; ind < mEventsToSkip; ind++) { - if (!generateEvent()) { - LOGF(error, "The file %s only contains %i events!", mFileName, ind); - break; - } + // If a EG command line is given, then we make a fifo on a temporary + // file, and directs the EG to write to that fifo. We will then set + // up the HepMC3 reader to read from that fifo. + // + // o2-sim -g hepmc --configKeyValues "HepMC.progCmd=" ... + // + // where is the command line to run an event generator. The + // event generator should output HepMC event records to standard + // output. Nothing else, but the HepMC event record may be output + // to standard output. If the EG has other output to standard + // output, then a filter can be set-up. For example + // + // crmc -n 3 -o hepmc3 -c /optsw/inst/etc/crmc.param -f /dev/stdout \ + // | sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' + // + // What's more, the event generator program _must_ accept the + // following command line argument + // + // `-n NEVENTS` to set the number of events to produce. + // + // Optionally, the command line should also accept + // + // `-s SEED` to set the random number seed + // `-b FM` to set the maximum impact parameter to sample + // `-o OUTPUT` to set the output file name + // + // All of this can conviniently be achieved via a wrapper script + // around the actual EG program. + if (not mCmd.empty()) { + // Set filename to be a temporary name + if (not makeTemp()) { + return false; + } + + // Make a fifo + if (not makeFifo()) { + return false; + } + + // Build command line, rediret stdout to our fifo and put + std::string cmd = makeCmdLine(); + LOG(debug) << "EG command line is \"" << cmd << "\""; + + // Execute the command line + if (not executeCmdLine(cmd)) { + LOG(fatal) << "Failed to spawn \"" << cmd << "\""; + return false; + } + } else { + // If no command line was given, ensure that all files are present + // on the system. Note, in principle, HepMC3 can read from remote + // files + // + // root:// XRootD served + // http[s]:// Web served + // gsidcap:// DCap served + // + // These will all be handled in HepMC3 via ROOT's TFile protocol + // and the files are assumed to contain a TTree named + // `hepmc3_tree` and that tree has the branches + // + // `hepmc3_event` with object of type `HepMC3::GenEventData` + // `GenRunInfo` with object of type `HepMC3::GenRunInfoData` + // + // where the last branch is optional. + // + // However, here we will assume system local files. If _any_ of + // the listed files do not exist, then we fail. + if (not ensureFiles()) { + return false; } } - /** success **/ - return !mReader->failed(); + // Create reader for current (first) file + return true; } /*****************************************************************/ diff --git a/Generators/src/GeneratorPythia8.cxx b/Generators/src/GeneratorPythia8.cxx index aba74f7ce61ee..fb5e1da3499ac 100644 --- a/Generators/src/GeneratorPythia8.cxx +++ b/Generators/src/GeneratorPythia8.cxx @@ -222,12 +222,39 @@ Bool_t void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) { /** update header **/ - - eventHeader->putInfo("generator", "pythia8"); - eventHeader->putInfo("version", PYTHIA_VERSION_INTEGER); - eventHeader->putInfo("processName", mPythia.info.name()); - eventHeader->putInfo("processCode", mPythia.info.code()); - eventHeader->putInfo("weight", mPythia.info.weight()); + using Key = o2::dataformats::MCInfoKeys; + + eventHeader->putInfo(Key::generator, "pythia8"); + eventHeader->putInfo(Key::generatorVersion, PYTHIA_VERSION_INTEGER); + eventHeader->putInfo(Key::processName, mPythia.info.name()); + eventHeader->putInfo(Key::processCode, mPythia.info.code()); + eventHeader->putInfo(Key::weight, mPythia.info.weight()); + + auto& info = mPythia.info; + + // Set PDF information + eventHeader->putInfo(Key::pdfParton1Id, info.id1pdf()); + eventHeader->putInfo(Key::pdfParton2Id, info.id2pdf()); + eventHeader->putInfo(Key::pdfX1, info.x1pdf()); + eventHeader->putInfo(Key::pdfX2, info.x2pdf()); + eventHeader->putInfo(Key::pdfScale, info.QFac()); + eventHeader->putInfo(Key::pdfXF1, info.pdf1()); + eventHeader->putInfo(Key::pdfXF2, info.pdf2()); + + // Set cross section + eventHeader->putInfo(Key::xSection, info.sigmaGen() * 1e9); + eventHeader->putInfo(Key::xSectionError, info.sigmaErr() * 1e9); + + // Set weights (overrides cross-section for each weight) + size_t iw = 0; + auto xsecErr = info.weightContainerPtr->getTotalXsecErr(); + for (auto w : info.weightContainerPtr->getTotalXsec()) { + std::string post = (iw == 0 ? "" : "_" + std::to_string(iw)); + eventHeader->putInfo(Key::weight + post, info.weightValueByIndex(iw)); + eventHeader->putInfo(Key::xSection + post, w * 1e9); + eventHeader->putInfo(Key::xSectionError + post, xsecErr[iw] * 1e9); + iw++; + } #if PYTHIA_VERSION_INTEGER < 8300 auto hiinfo = mPythia.info.hiinfo; @@ -238,7 +265,7 @@ void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) if (hiinfo) { /** set impact parameter **/ eventHeader->SetB(hiinfo->b()); - eventHeader->putInfo("Bimpact", hiinfo->b()); + eventHeader->putInfo(Key::impactParameter, hiinfo->b()); auto bImp = hiinfo->b(); /** set Ncoll, Npart and Nremn **/ int nColl, nPart; @@ -250,7 +277,8 @@ void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) getNpart(nPartProtonProj, nPartNeutronProj, nPartProtonTarg, nPartNeutronTarg); getNremn(nRemnProtonProj, nRemnNeutronProj, nRemnProtonTarg, nRemnNeutronTarg); getNfreeSpec(nFreeNeutronProj, nFreeProtonProj, nFreeNeutronTarg, nFreeProtonTarg); - eventHeader->putInfo("Ncoll", nColl); + eventHeader->putInfo(Key::nColl, nColl); + // These are all non-HepMC3 fields - of limited use eventHeader->putInfo("Npart", nPart); eventHeader->putInfo("Npart_proj_p", nPartProtonProj); eventHeader->putInfo("Npart_proj_n", nPartNeutronProj); @@ -264,6 +292,18 @@ void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) eventHeader->putInfo("Nfree_proj_p", nFreeProtonProj); eventHeader->putInfo("Nfree_targ_n", nFreeNeutronTarg); eventHeader->putInfo("Nfree_targ_p", nFreeProtonTarg); + + // --- HepMC3 conforming information --- + // This is how the Pythia authors define Ncoll + // eventHeader->putInfo(Key::nColl, + // hiinfo->nAbsProj() + hiinfo->nDiffProj() + + // hiinfo->nAbsTarg() + hiinfo->nDiffTarg() - + // hiiinfo->nCollND() - hiinfo->nCollDD()); + eventHeader->putInfo(Key::nPartProjectile, + hiinfo->nAbsProj() + hiinfo->nDiffProj()); + eventHeader->putInfo(Key::nPartTarget, + hiinfo->nAbsTarg() + hiinfo->nDiffTarg()); + eventHeader->putInfo(Key::nCollHard, hiinfo->nCollNDTot()); } } @@ -322,6 +362,10 @@ void GeneratorPythia8::getNcoll(const Pythia8::Info& info, int& nColl) auto hiinfo = info.hiInfo; #endif + // This is how the Pythia authors define Ncoll + nColl = (hiinfo->nAbsProj() + hiinfo->nDiffProj() + + hiinfo->nAbsTarg() + hiinfo->nDiffTarg() - + hiinfo->nCollND() - hiinfo->nCollDD()); nColl = 0; if (!hiinfo) { @@ -350,6 +394,17 @@ void GeneratorPythia8::getNpart(const Pythia8::Info& info, int& nPart) /** compute number of participants as the sum of all participants nucleons **/ + // This is how the Pythia authors calculate Npart +#if PYTHIA_VERSION_INTEGER < 8300 + auto hiinfo = info.hiinfo; +#else + auto hiinfo = info.hiInfo; +#endif + if (hiinfo) { + nPart = (hiinfo->nAbsProj() + hiinfo->nDiffProj() + + hiinfo->nAbsTarg() + hiinfo->nDiffTarg()); + } + int nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg; getNpart(info, nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg); nPart = nProtonProj + nNeutronProj + nProtonTarg + nNeutronTarg; diff --git a/Generators/src/GeneratorTParticle.cxx b/Generators/src/GeneratorTParticle.cxx new file mode 100644 index 0000000000000..ab68f7f39b1bf --- /dev/null +++ b/Generators/src/GeneratorTParticle.cxx @@ -0,0 +1,154 @@ +// Copyright 2023-2099 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author Christian Holm Christensen +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace o2 +{ +namespace eventgen +{ +/*****************************************************************/ +GeneratorTParticle::GeneratorTParticle() +{ + setOutputSwitch("-o"); +} + +/*****************************************************************/ +GeneratorTParticle::~GeneratorTParticle() +{ + if (mChain) { + TFile* file = mChain->GetCurrentFile(); + if (file) { + mChain->RecursiveRemove(file); + } + delete mChain; + } + if (mCmd.empty()) { + return; + } + + removeTemp(); +} +/*****************************************************************/ +Bool_t GeneratorTParticle::Init() +{ + mChain = new TChain(mTreeName.c_str()); + mTParticles = new TClonesArray("TParticle"); + mChain->SetBranchAddress(mBranchName.c_str(), &mTParticles); + + if (not mCmd.empty()) { + // Set filename to be a temporary name + if (not makeTemp()) { + return false; + } + + // Build command line, Assumes command line parameter + std::string cmd = makeCmdLine(); + LOG(info) << "EG command line is \"" << cmd << "\""; + + // Execute the background command + if (not executeCmdLine(cmd)) { + LOG(fatal) << "Failed to spawn \"" << cmd << "\""; + return false; + } + } + for (auto filename : mFileNames) { + mChain->AddFile(filename.c_str()); + } + + // Clear the array of file names + mFileNames.clear(); + + return true; +} + +/*****************************************************************/ +void GeneratorTParticle::setup(const GeneratorFileOrCmdParam& param0, + const GeneratorTParticleParam& param, + const conf::SimConfig& config) +{ + GeneratorFileOrCmd::setup(param0, config); + setTreeName(param.treeName); + setBranchName(param.branchName); +} + +/*****************************************************************/ +Bool_t GeneratorTParticle::generateEvent() +{ + // If this is the first entry, and we're executing a command, then + // wait until the input file exists and actually contain some data. + if (mEntry == 0 and not mCmd.empty()) { + waitForData(mTemporary); + } + + // Read in the next entry in the chain + int read = mChain->GetEntry(mEntry); + mEntry++; + + // If we got an error while reading, then give error message + if (read < 0) { + LOG(error) << "Failed to read entry " << mEntry << " of chain"; + } + + // If we had an error or nothing was read back, then return false + if (read <= 0) { + return false; + } + + return true; +} + +Bool_t GeneratorTParticle::importParticles() +{ + for (auto* object : *mTParticles) { + TParticle* particle = static_cast(object); + auto statusCode = particle->GetStatusCode(); + if (!mcgenstatus::isEncoded(statusCode)) { + statusCode = mcgenstatus::MCGenStatusEncoding(statusCode, 0) + .fullEncoding; + } + + mParticles.emplace_back(particle->GetPdgCode(), + statusCode, + particle->GetFirstMother(), + particle->GetSecondMother(), + particle->GetFirstDaughter(), + particle->GetLastDaughter(), + particle->Px(), + particle->Py(), + particle->Pz(), + particle->Energy(), + particle->Vx(), + particle->Vy(), + particle->Vz(), + particle->T()); + auto& tgt = mParticles[mParticles.size() - 1]; + tgt.SetPolarTheta(particle->GetPolarTheta()); + tgt.SetPolarPhi(particle->GetPolarPhi()); + tgt.SetCalcMass(particle->GetCalcMass()); + tgt.SetWeight(particle->GetWeight()); + } + return true; +} +} // namespace eventgen +} // namespace o2 +// +// EOF +// diff --git a/Generators/src/GeneratorTParticleParam.cxx b/Generators/src/GeneratorTParticleParam.cxx new file mode 100644 index 0000000000000..abb2d39681a3e --- /dev/null +++ b/Generators/src/GeneratorTParticleParam.cxx @@ -0,0 +1,18 @@ +// Copyright 2023-2099 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author Christian Holm Christensen + +#include "Generators/GeneratorTParticleParam.h" +O2ParamImpl(o2::eventgen::GeneratorTParticleParam); +// +// EOF +// diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 0d42b2ce505b6..35e77febee172 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -67,5 +67,10 @@ #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::QEDGenParam> + ; #pragma link C++ class o2::eventgen::GenCosmicsParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GenCosmicsParam> + ; +#pragma link C++ class o2::eventgen::GeneratorTParticle + ; +#pragma link C++ class o2::eventgen::GeneratorTParticleParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GeneratorTParticleParam> + ; +#pragma link C++ class o2::eventgen::GeneratorFileOrCmdParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GeneratorFileOrCmdParam> + ; #endif diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt index 07f23328230dd..f9b0f5e220ea6 100644 --- a/run/CMakeLists.txt +++ b/run/CMakeLists.txt @@ -271,7 +271,7 @@ o2_add_test_command(NAME o2sim_hepmc -g hepmc --configKeyValues -"HepMC.fileName=${CMAKE_SOURCE_DIR}/Generators/share/data/pythia.hepmc;HepMC.version=2;align-geom.mDetectors=none" +"GeneratorFileOrCmd.fileNames=${CMAKE_SOURCE_DIR}/Generators/share/data/pythia.hepmc;HepMC.version=2;align-geom.mDetectors=none" -o o2simhepmc LABELS long sim hepmc3 diff --git a/run/SimExamples/HepMC/README.md b/run/SimExamples/HepMC/README.md new file mode 100644 index 0000000000000..0369ee9d90bdd --- /dev/null +++ b/run/SimExamples/HepMC/README.md @@ -0,0 +1,169 @@ + + +Here are pointers on how to use `GeneratorHepMC` selected by the +option `-g hepmc` for `o2-sim`. + +HepMC event structures can be read from any file format supported by +HepMC it self (see +[here](http://hepmc.web.cern.ch/hepmc/group__IO.html) and +[here](http://hepmc.web.cern.ch/hepmc/group__factory.html). + +## Reading HepMC files + +The generator `GeneratorHepMC` can read events from a +[HepMC(3)](http://hepmc.web.cern.ch/hepmc/) formatted file. These +files can be produced by a standalone event generator program (EG). +Examples of such programs are + +- [Pythia8](https://pythia.org) +- The [CRMC](https://gitlab.iap.kit.edu/AirShowerPhysics/crmc) suite +- [Herwig](https://herwig.hepforge.org/) +- [SMASH](https://smash-transport.github.io/) +- ... and many others + +Please refer to the documentation of these for more on how to make +event files in the HepMC format. + +To make a simulation reading from the file `events.hepmc`, do + + o2-sim -g hepmc --configKeyValues "GeneratorFileOrCmd.fileNames=events.hepmc" ... + +See also [`read.sh`](read.sh). + +## Reading HepMC events from child process + +`GeneratorHepMC` can not only read HepMC events from a file, but can +also spawn an child EG to produce events. Suppose we have a program +named `eg` which is some EG that writes HepMC event records to the +standard output. Then we can execute a simulation using this external +EG by + + o2-sim -g hepmc --configKeyValues "GeneratorFileOrCmd.cmd=eg" + +See also [`child.sh`](child.sh). + +There are some requirements on the program `eg`: + +- The EG program _must_ be able to write the HepMC event structures to + a specified file. The option passed to the program is specified via + the key `GeneratorFileOrCmd.outputSwitch`. This defaults to `>` + which means the EG program is assumed to write the HepMC event + structures to standard output, _and_ that nothing else is printed on + standard output. +- It _must_ accept an option to set the number of events to generate. + This is controlled by the configuration key + `GeneratorFileOrCmd.nEventsSwitch` and defaults to `-n`. Thus, the + EG application should accept `-n 10` to mean that it should generate + `10` events, for example. +- The EG application should accept a command line switch to set the + random number generator seed. This option is specified via the + configuration key `GeneratorFileOrCmd.seedSwitch` and defaults to + `-s`. Thus, the EG application must accept `-s 123456` to mean to + set the random number seed to `123456` for example. +- The EG application should accept a command line switch to set the + maximum impact parameter (in Fermi-metre) sampled. This is set via + the configuration key `GeneratorFileOrCmd.bMaxSwithc` and defaults + to `-b`. Thus, the EG application should take the command line + argument `-b 10` to mean that it should only generate events with an + impact parameter between 0fm and 10fm. + +If a program does not adhere to these requirements, it will often be +simple enough to make a small wrapper script that enforce this. For +example, `crmc` will write a lot of information to standard output. +We can filter that out via a shell script ([`crmc.sh`](crmc.sh)) like + + #!/bin/sh + crmc $@ -o hepmc3 -f /dev/stdout | sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' + +The `sed` command selects lines that begin with `HepMC::`, or one of +single characters `E` (event), `A` (attribute), `U` (units), `W` +(weight), `V` (vertex), or `P` (particle) followed by a space. This +should in most cases be enough to filter out extra stuff written on +standard output. + +The script above also passes any additional command line options on to +`crmc` via `$@`. We can utilise this with `o2-sim` to set options to +the CRMC suite. For example, if we want to simulate p-Pb collisions +using DpmJET, we can do + + o2-sim -g hepmc --configKeyValues "GeneratorFileOrCmd.cmd=crmc.sh -m 12 -i2212 -I 1002080820" + + +### Implementation details + +Internally `GeneratorHepMC` + +1. creates a unique temporary file name in the working directory, +2. then creates a FIFO (or named pipe, see + [Wikipedia](https://en.wikipedia.org/wiki/Named_pipe)), +3. builds a command line, e.g., + + eg options > fifo-name & + +4. and executes that command line + +## The configuration keys + +The `GeneratorHepMC` (and sister generator `GeneratorTParticle`) +allows customisation of the execution via configuration keys passed +via `--configKeyValues` + +- `HepMC.eventsToSkip=number` a number events to skip at the beginning + of each file read. + +- `HepMC.version` - when reading the events from files, this option is + no longer needed. The code itself figures out which format version + the input file is in. If executing a child process through + `GeneratorFileOrCmd.cmd` and the EG writes out HepMC2 format, then + this _must_ be set to `2`. Otherwise, HepMC3 is assumed. + +- `GeneratorFileOrCmd.fileNames=list` a comma separated list of HepMC + files to read. + +- `GeneratorFileOrCmd.cmd=command line` a command line to execute as a + background child process. If this is set (not the empty string), + then `GeneratorFileOrCmd.fileNames` is ignored. + +- A number of keys that specifies the command line option switch that + the child program accepts for certain things. If any of these are + set to the empty string, then that switch and corresponding option + value is not passed to the child program. + + - `GeneratorFileOrCmd.outputSwitch=switch` (default `>`) to specify + output file. The default of `>` assumes that the program write + HepMC events, and _only_ those, to standard output. + + - `GeneratorFileOrCmd.seedSwitch=switch` (default `-s`) to specify + the random number generator seed. The value passed is selected by + the `o2-sim` option `--seed` + + - `GeneratorFileOrCmd.bMaxSwitch=switch` (default `-b`) to specify + the upper limit on the impact parameters sampled. The value + passed is selected by the `o2-sim` option `--bMax` + + - `GeneratorFileOrCmd.nEventsSwitch=switch` (default `-n`) to + specify the number of events to generate. The value passed is + selected by the `o2-sim` option `--nEvents` or (`-n`) + + - `GeneratorFileOrCmd.backgroundSwitch=switch` (default `&`) to + specify how the program is put in the background. Typically this + should be `&`, but a program may itself fork to the background. + +- Some options are deprecated + + - `HepMC.fileName` - use `GeneratorFileOrCmd.fileNames` + +The command line build will now be + +> _commandLine_ _nEventsSwitch_ _nEvents_ _seedSwitch_ _seed_ +> _bMaxSwitch_ _bMax_ _outputSwitch_ _output_ _backgroundSwitch_ + +If any of the `Switch` keys are empty, then the corresponding option +is not propagated to the command line. For example, if _bMaxSwitch_ +is empty, then the build command line will be + +> _commandLine_ _nEventsSwitch_ _nEvents_ _seedSwitch_ _seed_ +> _outputSwitch_ _output_ _backgroundSwitch_ + diff --git a/run/SimExamples/HepMC/child.sh b/run/SimExamples/HepMC/child.sh new file mode 100755 index 0000000000000..89b563ec8d550 --- /dev/null +++ b/run/SimExamples/HepMC/child.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +cmd="./crmc.sh" +more="GeneratorFileOrCmd.bMaxSwitch=none" +seed=$RANDOM +nev=1 +out= + +usage() +{ + cat </dev/stderr + exit 1 + ;; + esac + shift +done + +if test "x$out" = "x" ; then + out=`echo $cmd | sed 's,^\./,,' | tr '[$/. ]' '_'` +fi +out=`echo "$out" | tr ' ' '_'` + +export VMCWORKDIR=${O2_ROOT}/share +o2-sim -g hepmc --configKeyValues "GeneratorFileOrCmd.cmd=$cmd;${more}" \ + --outPrefix "$out" --seed $seed --nEvents $nev $@ diff --git a/run/SimExamples/HepMC/crmc.sh b/run/SimExamples/HepMC/crmc.sh new file mode 100755 index 0000000000000..1c2d2f7827dbc --- /dev/null +++ b/run/SimExamples/HepMC/crmc.sh @@ -0,0 +1,7 @@ +#!/bin/sh +# This script _may not_ write to standard out, except for the HepMC +# event record. + +crmcParam=$(dirname $(dirname `which crmc`))/etc/crmc.param +exec crmc -c $crmcParam $@ -o hepmc -f /dev/stdout | \ + sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' diff --git a/run/SimExamples/HepMC/read.sh b/run/SimExamples/HepMC/read.sh new file mode 100755 index 0000000000000..e64f5561a775c --- /dev/null +++ b/run/SimExamples/HepMC/read.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +inp=events.hepmc +seed=$RANDOM +nev=1 +out= + +usage() +{ + cat </dev/stderr + exit 1 + ;; + esac + shift +done + +if test "x$out" = "x" ; then + out=`basename $inp .hepmc` +fi +out=`echo "$out" | tr ' ' '_'` + +export VMCWORKDIR=${O2_ROOT}/share +o2-sim -g hepmc --configKeyValues "GeneratorFileOrCmd.fileNames=$inp" \ + --outPrefix "$out" --seed $seed --nEvents $nev $@ diff --git a/run/SimExamples/HepMC_STARlight/run.sh b/run/SimExamples/HepMC_STARlight/run.sh index b75cee52b7117..3eb5b91f24a6d 100755 --- a/run/SimExamples/HepMC_STARlight/run.sh +++ b/run/SimExamples/HepMC_STARlight/run.sh @@ -10,9 +10,9 @@ set -x # PART a) env -i HOME="$HOME" USER="$USER" PATH="/bin:/usr/bin:/usr/local/bin" \ - ALIBUILD_WORK_DIR="$ALIBUILD_WORK_DIR" ./run-starlight.sh + ALIBUILD_WORK_DIR="$ALIBUILD_WORK_DIR" ./run-starlight.sh # PART b) NEV=1000 o2-sim -j 20 -n ${NEV} -g hepmc -m PIPE ITS -o sim \ - --configKeyValues "HepMC.fileName=starlight.hepmc;HepMC.version=2;Diamond.position[2]=0.1;Diamond.width[2]=0.05" + --configKeyValues "GeneratorFileOrCmd.fileNames=starlight.hepmc;Diamond.position[2]=0.1;Diamond.width[2]=0.05" diff --git a/run/SimExamples/README.md b/run/SimExamples/README.md index 2613f6bb2773c..ae2d15d47316c 100644 --- a/run/SimExamples/README.md +++ b/run/SimExamples/README.md @@ -11,6 +11,7 @@ * \subpage refrunSimExamplesAdaptive_Pythia8 * \subpage refrunSimExamplesAliRoot_Hijing * \subpage refrunSimExamplesAliRoot_AMPT +* \subpage refrunSimExamplesHepMC * \subpage refrunSimExamplesHepMC_STARlight * \subpage refrunSimExamplesJet_Embedding_Pythia8 * \subpage refrunSimExamplesStepMonitoringSimple1 @@ -20,4 +21,5 @@ * \subpage refrunSimExamplesSelective_Transport_pi0 * \subpage refrunSimExamplesCustom_EventInfo * \subpage refrunSimExamplesMCTrackToDPL +* \subpage refrunSimExamplesTParticle /doxy --> diff --git a/run/SimExamples/TParticle/MyEG.macro b/run/SimExamples/TParticle/MyEG.macro new file mode 100644 index 0000000000000..a067b4c1051b7 --- /dev/null +++ b/run/SimExamples/TParticle/MyEG.macro @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include + +//-------------------------------------------------------------------- +// Our generator class. Really simple. +class MyGenerator : public TGenerator +{ + public: + Long_t projectilePDG; + Long_t targetPDG; + Double_t sqrts; + MyGenerator() {} + void Initialize(Long_t projectile, + Long_t target, + Double_t sqrts) + { + this->projectilePDG = projectile; + this->targetPDG = target; + this->sqrts = sqrts; + } + void GenerateEvent() + { /* Do something */ + } + TObjArray* ImportParticles(Option_t* option = "") { return 0; } + Int_t ImportParticles(TClonesArray* particles, Option_t* option = "") + { + Int_t nParticles = 10; + Int_t iParticle = 0; + // Make beam particles + new ((*particles)[iParticle++]) TParticle(projectilePDG, 4, -1, -1, + 2, nParticles - 1, + 0, 0, sqrts / 2, + TMath::Sqrt(1 + sqrts * sqrts), + 0, 0, 0, 0); + new ((*particles)[iParticle++]) TParticle(projectilePDG, 4, -1, -1, + 2, nParticles - 1, + 0, 0, -sqrts / 2, + TMath::Sqrt(1 + sqrts * sqrts), + 0, 0, 0, 0); + for (; iParticle < nParticles; iParticle++) + new ((*particles)[iParticle]) + TParticle(211, 1, 0, 1, + -1, -1, + 0.1 * iParticle, + 0.1 * iParticle, + 0.1 * iParticle, + TMath::Sqrt(0.03 * iParticle * iParticle + 0.14 * 0.14), + 0, 0, 0, 0); + + return nParticles; + } +}; +//-------------------------------------------------------------------- +// Our steering class +struct MySteer { + TGenerator* generator; + TFile* file; + TTree* tree; + TClonesArray* particles; + Int_t every; + MySteer(TGenerator* generator, const TString& output, Int_t every) + : generator(generator), + file(TFile::Open(output, "RECREATE")), + tree(new TTree("T", "T")), + particles(new TClonesArray("TParticle")), + every(every) + { + tree->SetDirectory(file); + tree->Branch("Particles", &particles); + } + ~MySteer() + { + close(); + } + void event() + { + particles->Clear(); + generator->GenerateEvent(); + generator->ImportParticles(particles); + tree->Fill(); + } + void sync() + { + // Important so that GeneratorTParticle picks up the events as + // they come. + tree->AutoSave("SaveSelf FlushBaskets Overwrite"); + } + void run(Int_t nev) + { + for (Int_t iev = 0; iev < nev; iev++) { + event(); + + if (every > 0 and (iev % every == 0) and iev != 0) + sync(); + } + } + void close() + { + if (not file) + return; + file->Write(); + file->Close(); + file = nullptr; + } +}; + +//-------------------------------------------------------------------- +// Our steering function +void MyEG(Int_t nev, const TString& out, Int_t seed, Int_t every = 1) +{ + gRandom->SetSeed(seed); + + MyGenerator* eg = new MyGenerator(); + eg->Initialize(2212, 2212, 5200); + + MySteer steer(eg, out, every); + steer.run(nev); +} +// Local Variables: +// mode: C++ +// End: +// +// EOF +// diff --git a/run/SimExamples/TParticle/README.md b/run/SimExamples/TParticle/README.md new file mode 100644 index 0000000000000..c9df40665d829 --- /dev/null +++ b/run/SimExamples/TParticle/README.md @@ -0,0 +1,265 @@ + + +Here are pointers on how to use `GeneratorTParticle` selected by the +option `-g tparticle` for `o2-sim`. + +## Reading TParticle files + +The generator `GeneratorTParticle` can read events from a ROOT file +containing a `TTree` with a branch holding a `TClonesArray` of +`TParticle` objects. These files can be produced by a standalone event +generator program (EG). + +To make a simulation reading from the file `particles.root`, do + + o2-sim -g tparticle --configKeyValues "GeneratorFileOrCmd.fileNames=particles.root" ... + +See also [`read.sh`](read.sh). Do + + ./read.sh --help + +for a list of options. This expects an input file with a `TTree` with +a single `TBranch` holding a `TClonesArray` of `TParticle` objects. +One such example file can be made with [`myeg.sh`]. Do + + ./myeg.sh --help + +for a list of options. + +### Configurations + +- The name of the `TTree` to read can be set by the configuration key + `GeneratorTParticle.treeName`. The default is `T` +- The name of the `TBranch` holding the `TClonesArray` of `TParticle` + objects can be set by the configuration key + `GeneratorTParticle.branchName`. The default is `Particles` + +For example + + o2-sim -g tparticle --configKeyValues "GeneratorFileOrCmd.fileNames=particles.root;GeneratorTParticle.treeName=Events;GeneratorTParticle.branchName=Tracks" ... + +## Reading TParticle events from child process + +`GeneratorTParticle` can not only read events from a file, but can +also spawn an child EG to produce events. Suppose we have a program +named `eg` which is some EG that writes `TParticle` event records to a +file . Then we can execute a simulation using this external EG by + + o2-sim -g tgenerator --configKeyValues "GeneratorFileOrCmd.cmd=eg" + +See also [`child.sh`](child.sh). Do + + ./child.sh --help + +for a list of options. + +There are some requirements on the program `eg`: + +- The EG program _must_ be able to write the HepMC event structures to + a specified file. The option passed to the program is specified via + the key `GeneratorFileOrCmd.outputSwitch`. This defaults to `-o`. +- It _must_ accept an option to set the number of events to generate. + This is controlled by the configuration key + `GeneratorFileOrCmd.nEventsSwitch` and defaults to `-n`. Thus, the + EG application should accept `-n 10` to mean that it should generate + `10` events, for example. +- The EG application should accept a command line switch to set the + random number generator seed. This option is specified via the + configuration key `GeneratorFileOrCmd.seedSwitch` and defaults to + `-s`. Thus, the EG application must accept `-s 123456` to mean to + set the random number seed to `123456` for example. +- The EG application should accept a command line switch to set the + maximum impact parameter (in Fermi-metre) sampled. This is set via + the configuration key `GeneratorFileOrCmd.bMaxSwithc` and defaults + to `-b`. Thus, the EG application should take the command line + argument `-b 10` to mean that it should only generate events with an + impact parameter between 0fm and 10fm. + +If a program does not adhere to these requirements, it will often be +simple enough to make a small wrapper script that enforce this. + +### Configurations + +Same as above. + +### Example EG + +The child-process feature allows us to use almost any EG for which we +have a `TGenerator` interface without compiling it in to O2. Suppose +we have defined the class `MyGenerator` to produce events. + + class MyGenerator : public TGenerator { + public: + MyGenerator(); + void Initialize(Long_t projectile, + Long_t target, + Double_t sqrts); + void GenerateEvent(); + Int_t ImportParticles(TClonesArray* particles,Option_t*option=""); + }; + +and a steering class + + struct MySteer { + TGenerator* generator; + TFile* file; + TTree* tree; + TClonesArray* particle; + Int_t flushEvery; + MySteer(TGenerator* generator, + const TString& output, + Int_t flushEvery) + : generator(generator) + file(TFile::Open(output,"RECREATE")), + tree("T","Particle tree"), + particles(new TClonesArray("TParticle")), + flushEvery(flushEvery) + { + tree->SetDirectory(file); + tree->Branch("Particles",&particles); + } + ~MySteer() { close(); } + void event() { + particles->Clear(); + generator->GenerateEvent(); + generator->ImportParticles(particles); + tree->Fill(); + } + void sync() { + tree->AutoSave("SaveSelf FlushBaskets Overwrite"); + } + void run(Int_t nev) { + for (Int_t iev = 0; iev < nev; iev++) { + event(); + if (flushEvery > 0 and (iev % flushEvery == 0) and iev != 0) + sync(); + } + } + void close() { + if (not file) return; + file->Write(); + file->Close(); + file = nullptr; + } + }; + +Then we could make the script [`MyEG.macro` (complete code)](MyEG.macro) like + + void MyEG(Int_t nev,const TString& out,Int_t every=1) + { + MyGenerator* eg = new MyGenerator(); + eg->Initialize(2212, 2212, 5200); + + MySteer steer(eg, out, every); + steer.run(nev); + } + +and a simple shell-script [`myeg.sh`](myeg.sh) to pass arguments to +the `MyEG.macro` script + + #!/bin/sh + + nev=1 + out=particles.root + + while test $# -gt 0 ; do + case $1 in + -n) nev=$2 ; shift ;; + -o) out=$2 ; shift ;; + *) ;; + esac + shift + done + + root -l MyEG.macro -- $nev \"$out\" + +We can then do + + o2-sim -g tgenerator --configKeyValues "GeneratorFileOrCmd.cmd=./myeg.sh" + +to produce events with our generator `MyGenerator`. + + +### Implementation details + +Internally `GeneratorTParticle` + +1. creates a unique temporary file name in the working directory, +2. builds a command line, e.g., + + eg options -o temporary-name & + +3. and executes that command line + +## The future + +The `GeneratorTParticle` (and sister generator `GeneratorHepMC`) is +configured through configuration keys set via `--configKeyValues` + +- `GeneratorTParticle.treeName=name` the name of the `TTree` in the + input files. + +- `GeneratorTParticle.branchName=name` the name of the `TBranch` in + the `TTree` that holds the `TClonesArray` of `TParticle` objects. + +- `GeneratorFileOrCmd.fileNames=list` a comma separated list of HepMC + files to read + +- `GeneratorFileOrCmd.cmd=command line` a command line to execute as a + background child process. If this is set (not the empty string), + then `GeneratorFileOrCmd.fileNames` is ignored. + +- A number of keys that specifies the command line option switch that + the child program accepts for certain things. If any of these are + set to the empty string or special value `none`, then that switch + and corresponding option value is not passed to the child program. + + - `GeneratorFileOrCmd.outputSwitch=switch` (default `>`) to specify + output file. The default of `>` assumes that the program write + events, and _only_ those, to standard output. + + - `GeneratorFileOrCmd.seedSwitch=switch` (default `-s`) to specify + the random number generator seed. The value passed is selected by + the `o2-sim` option `--seed`. + + - `GeneratorFileOrCmd.bMaxSwitch=switch` (default `-b`) to specify + the upper limit on the impact parameters sampled. The value + passed is selected by the `o2-sim` option `--bMax`. + + - `GeneratorFileOrCmd.nEventsSwitch=switch` (default `-n`) to + specify the number of events to generate. The value passed is + selected by the `o2-sim` option `--nEvents` or (`-n`). + + - `GeneratorFileOrCmd.backgroundSwitch=switch` (default `&`) to + specify how the program is put in the background. Typically this + should be `&`, but a program may itself fork to the background. + +The command line build will now be + +> _commandLine_ _nEventsSwitch_ _nEvents_ _seedSwitch_ _seed_ +> _bMaxSwitch_ _bMax_ _outputSwitch_ _output_ _backgroundSwitch_ + +If any of the `Switch` keys are empty or set to `none`, then the +corresponding option is not propagated to the command line. For +example, if _bMaxSwitch_ is empty, then the build command line will be + +> _commandLine_ _nEventsSwitch_ _nEvents_ _seedSwitch_ _seed_ +> _outputSwitch_ _output_ _backgroundSwitch_ + + +## TODO + +### Header information + +The class `GeneratorTParticle` will take a key parameter, say +`headerName` which will indicate a branch that contains header +information. Under that branch, the class will then search for leaves +(`TLeaf`) that correspond to standard header information keys (see +`o2::dataformats::MCInfoKeys`). If any of those leaves are present, +then the corresponding keys will be set on the generated event header. + +Thus, as long as the generator observes the convention used, we can +also import auxiliary information (impact parameter, Npart, ...) from +the input files in addition to the particle information. diff --git a/run/SimExamples/TParticle/child.sh b/run/SimExamples/TParticle/child.sh new file mode 100755 index 0000000000000..ae188024808d0 --- /dev/null +++ b/run/SimExamples/TParticle/child.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +cmd="./myeg.sh" +seed=$RANDOM +nev=1 +out= +opt= + +usage() +{ + cat </dev/stderr + exit 1 + ;; + esac + shift +done + +if test "x$out" = "x" ; then + out=`echo $cmd | sed 's,^\./,,' | tr '[$/. ]' '_'` +fi +out=`echo "$out" | tr ' ' '_'` + +set -x +export VMCWORKDIR=${O2_ROOT}/share +o2-sim -g tparticle \ + --configKeyValues "GeneratorFileOrCmd.cmd=$cmd $opt;GeneratorFileOrCmd.outputSwitch=-o" \ + --outPrefix "$out" --seed $seed --nEvents $nev $@ + diff --git a/run/SimExamples/TParticle/myeg.sh b/run/SimExamples/TParticle/myeg.sh new file mode 100755 index 0000000000000..4e76c8a8a02d8 --- /dev/null +++ b/run/SimExamples/TParticle/myeg.sh @@ -0,0 +1,37 @@ +#!/bin/sh + + +nev=1 +out=particles.root +seed=0 +opt= + +usage() +{ + cat </dev/stderr + exit 1 + ;; + esac + shift +done + +if test "x$out" = "x" ; then + out=`basename $inp .root` +fi +out=`echo "$out" | tr ' ' '_'` + +set -e +export VMCWORKDIR=${O2_ROOT}/share +o2-sim -g tparticle --configKeyValues "GeneratorFileOrCmd.fileNames=${inp}" \ + --outPrefix "$out" --seed $seed --nEvents $nev $@ + From 9566b5378e780e12d632b9d90f57b32a199886a9 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Fri, 20 Oct 2023 20:34:33 +0200 Subject: [PATCH 315/324] MatLUT: faster phi-sector determination; reduction of divisions (#12030) Following ticket https://alice.its.cern.ch/jira/browse/O2-4170, Profile analysis has shown that material budget calculations used in tracking, spent most time in (a) determination of a cylindrical layer (b) determination of a phi sector in a layer This commit proposes an improvement for (b): - Instead of using system function phi = atan2(y, x), we use a faster - approximate version. We can do this, since we never need to use the precise result of phi in a calculation. Instead, phi is merely used to lookup a slice/sector. The error of the approximate version is ~1e-5, which is enough to get the correct phi sector in 99.999 of the cases. (Rare cases, where we end up in a wrong neighbouring phi sector are probably ok ... since the material budget lookup is anyways an approximation.) In addition, we propose a smaller code mofication for ray.CrossZ to reduce the number of divisions and if statements. A previous check for ray orthogonal to z can not happen in the code since there is a previous condition `if (zID != zIDLast)`. ITS reco is shown to improve by ~15% in speed for larger PbPb MC timeframes (on Linux - tested on CC7 and Ubuntu22.04) --- Detectors/Base/include/DetectorsBase/Ray.h | 56 +++++++++++++++++++++- Detectors/Base/src/MatLayerCylSet.cxx | 9 ++-- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/Detectors/Base/include/DetectorsBase/Ray.h b/Detectors/Base/include/DetectorsBase/Ray.h index 1701e65c2d638..9f087363707c4 100644 --- a/Detectors/Base/include/DetectorsBase/Ray.h +++ b/Detectors/Base/include/DetectorsBase/Ray.h @@ -46,7 +46,7 @@ class Ray static constexpr float InvalidT = -1e9; static constexpr float Tiny = 1e-9; - GPUd() Ray() : mP{0.f}, mD{0.f}, mDistXY2(0.f), mDistXY2i(0.f), mDistXYZ(0.f), mXDxPlusYDy(0.f), mXDxPlusYDyRed(0.f), mXDxPlusYDy2(0.f), mR02(0.f), mR12(0.f) + GPUd() Ray() : mP{0.f}, mD{0.f}, mDistXY2(0.f), mDistXY2i(0.f), mDistXYZ(0.f), mXDxPlusYDy(0.f), mXDxPlusYDyRed(0.f), mXDxPlusYDy2(0.f), mR02(0.f), mR12(0.f), mInvDz(Tiny) { } GPUdDefault() ~Ray() CON_DEFAULT; @@ -61,6 +61,7 @@ class Ray GPUd() float crossRadial(const MatLayerCyl& lr, int sliceID) const; GPUd() float crossRadial(float cs, float sn) const; GPUd() float crossZ(float z) const; + GPUd() float crossZ_fast(float z) const; // without check GPUd() void getCrossParams(int i, float& par1, float& par2) const { @@ -84,6 +85,49 @@ class Ray return p; } + // fast, approximate arctan calculation - sufficient for phi sector determination in material budget layers + // source of inspirations: + // - https://mazzo.li/posts/vectorized-atan2.html + // - https://www.coranac.com/documents/arctangent/ + GPUd() float atan_approx_5terms(float x) const + { + // fast atan implementation + // function has a max error of ~1.16825e-05f + float a1 = 0.9998660f; + float a3 = -0.3302995f; + float a5 = 0.1801410f; + float a7 = -0.0851330f; + float a9 = 0.0208351f; + + float x_sq = x * x; + // todo: force fuse-multiply add + return x * (a1 + x_sq * (a3 + x_sq * (a5 + x_sq * (a7 + x_sq * a9)))); + } + + GPUd() float atan2_approx(float y, float x) const + { + const bool swap = fabs(x) < fabs(y); + const float atan_input = (swap ? x : y) / (swap ? y : x); + const float pi2 = M_PI_2; + const float pi = M_PI; + float res = atan_approx_5terms(atan_input); + + // if swapped, adjust atan output + res = swap ? (atan_input >= 0.0f ? pi2 : -pi2) - res : res; + // adjust quadrants + if (x < 0.0f) { + res = ((y < 0.0f) ? -pi : pi) + res; + } + return res; + } + + GPUd() float getPhi_approx(float t) const + { + float p = atan2_approx(mP[1] + t * mD[1], mP[0] + t * mD[0]); + o2::math_utils::bringTo02Pi(p); + return p; + } + GPUd() float getZ(float t) const { return mP[2] + t * mD[2]; } GPUd() bool validateZRange(float& cpar1, float& cpar2, const MatLayerCyl& lr) const; @@ -101,6 +145,7 @@ class Ray float mR12; ///< radius^2 of mP1 float mCrossParams1[2]; ///< parameters of crossing the layer (first parameter) float mCrossParams2[2]; ///< parameters of crossing the layer (second parameter) + float mInvDz; ClassDefNV(Ray, 1); }; @@ -119,6 +164,7 @@ inline Ray::Ray(const math_utils::Point3D point0, const math_utils::Point mXDxPlusYDy2 = mXDxPlusYDy * mXDxPlusYDy; mR02 = point0.Perp2(); mR12 = point1.Perp2(); + mInvDz = 1.f / mD[2]; } #endif // !GPUCA_ALIGPUCODE @@ -134,6 +180,7 @@ GPUdi() Ray::Ray(float x0, float y0, float z0, float x1, float y1, float z1) mXDxPlusYDy2 = mXDxPlusYDy * mXDxPlusYDy; mR02 = x0 * x0 + y0 * y0; mR12 = x1 * x1 + y1 * y1; + mInvDz = 1.f / mD[2]; } //______________________________________________________ @@ -175,6 +222,13 @@ GPUdi() float Ray::crossZ(float z) const return mD[2] != 0. ? (z - mP[2]) / mD[2] : InvalidT; } +//______________________________________________________ +GPUdi() float Ray::crossZ_fast(float z) const +{ + // calculate t of crossing XY plane at Z + return (z - mP[2]) * mInvDz; +} + //______________________________________________________ GPUdi() bool Ray::validateZRange(float& cpar1, float& cpar2, const MatLayerCyl& lr) const { diff --git a/Detectors/Base/src/MatLayerCylSet.cxx b/Detectors/Base/src/MatLayerCylSet.cxx index fb2e720427016..6ee8a006db002 100644 --- a/Detectors/Base/src/MatLayerCylSet.cxx +++ b/Detectors/Base/src/MatLayerCylSet.cxx @@ -294,8 +294,8 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa for (int ic = nc; ic--;) { float cross1, cross2; ray.getCrossParams(ic, cross1, cross2); // tmax,tmin of crossing the layer - - auto phi0 = ray.getPhi(cross1), phi1 = ray.getPhi(cross2), dPhi = phi0 - phi1; + auto phi0 = ray.getPhi_approx(cross1), phi1 = ray.getPhi_approx(cross2), dPhi = phi0 - phi1; + // auto phi0 = ray.getPhi(cross1), phi1 = ray.getPhi(cross2), dPhi = phi0 - phi1; auto phiID = lr.getPhiSliceID(phi0), phiIDLast = lr.getPhiSliceID(phi1); // account for eventual wrapping around 0 if (dPhi > 0.f) { @@ -339,10 +339,7 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa tEndZ = tEndPhi; checkMoreZ = false; } else { - tEndZ = ray.crossZ(lr.getZBinMin(stepZID > 0 ? zID + 1 : zID)); - if (tEndZ == Ray::InvalidT) { // track normal to Z axis, abandon Zbin change test - break; - } + tEndZ = ray.crossZ_fast(lr.getZBinMin(stepZID > 0 ? zID + 1 : zID)); } // account materials of this step float step = tEndZ > tStartZ ? tEndZ - tStartZ : tStartZ - tEndZ; // the real step is ray.getDist(tEnd-tStart), will rescale all later From 85977983831325160a70923288acef3cdfd6555f Mon Sep 17 00:00:00 2001 From: Matthias Kleiner <48915672+matthias-kleiner@users.noreply.github.com> Date: Fri, 20 Oct 2023 20:37:07 +0200 Subject: [PATCH 316/324] Debug streamer: Add downsampling by tsalis (#12112) * Debug streamer: Add downsampling by tsalis * Adding time series for vertex position - adding time series for DCA to vertex for ITS-TPC tracks * increase ClassDef for TimeSeriesITSTPC * fix typo --- .../Utils/include/CommonUtils/DebugStreamer.h | 25 ++ Common/Utils/src/DebugStreamer.cxx | 43 +++- .../IntegratedClusterCalibrator.h | 94 ++++++- .../TPC/workflow/src/TPCTimeSeriesSpec.cxx | 235 +++++++++++++----- 4 files changed, 319 insertions(+), 78 deletions(-) diff --git a/Common/Utils/include/CommonUtils/DebugStreamer.h b/Common/Utils/include/CommonUtils/DebugStreamer.h index 8952842d5fc89..6464a5dde128b 100644 --- a/Common/Utils/include/CommonUtils/DebugStreamer.h +++ b/Common/Utils/include/CommonUtils/DebugStreamer.h @@ -50,6 +50,7 @@ enum SamplingTypes { sampleID = 2, ///< sample every n IDs (per example track) sampleIDGlobal = 3, ///< in case different streamers have access to the same IDs use this gloabl ID sampleWeights = 4, ///< perform sampling on weights, defined where the streamer is called + sampleTsalis = 5, ///< perform sampling on tsalis pdf }; #if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) @@ -163,10 +164,34 @@ class DebugStreamer /// \return returns integer index for given streamer flag static int getIndex(const StreamFlags streamFlag); + /// Random downsampling trigger function using Tsalis/Hagedorn spectra fit (sqrt(s) = 62.4 GeV to 13 TeV) as in https://iopscience.iop.org/article/10.1088/2399-6528/aab00f/pdf + /// \return flat q/pt trigger + /// \param pt pat of particle + /// \param factorPt defines the sampling + /// \param sqrts centre of mass energy + /// \param weight weight which is internally calculated + /// \param rnd random value between (0->1) used to check for sampling + /// \param mass particles mass (use pion if not known) + static bool downsampleTsalisCharged(float pt, float factorPt, float sqrts, float& weight, float rnd, float mass = 0.13957); + + /// get random value between min and max + static float getRandom(float min = 0, float max = 1); + private: using StreamersPerFlag = tbb::concurrent_unordered_map>; StreamersPerFlag mTreeStreamer; ///< streamer which is used for the debugging + /// Tsalis/Hagedorn function describing charged pt spectra (m s = 62.4 GeV to 13 TeV) as in https://iopscience.iop.org/article/10.1088/2399-6528/aab00f/pdf + /// https://github.com/alisw/AliPhysics/blob/523f2dc8b45d913e9b7fda9b27e746819cbe5b09/PWGPP/AliAnalysisTaskFilteredTree.h#L145 + /// \param pt - transverse momentum + /// \param mass - mass of particle + /// \param sqrts - centre of mass energy + /// \return - invariant yields of the charged particle *pt + /// n(sqrts)= a + b/sqrt(s) - formula 6 + /// T(sqrts)= c + d/sqrt(s) - formula 7 + /// a = 6.81 ± 0.06 and b = 59.24 ± 3.53 GeV - for charged particles page 3 + /// c = 0.082 ± 0.002 GeV and d = 0.151 ± 0.048 (GeV) - for charged particles page 4 + static float tsalisCharged(float pt, float mass, float sqrts); #else // empty implementation of the class for GPU or when the debug streamer is not build for CPU diff --git a/Common/Utils/src/DebugStreamer.cxx b/Common/Utils/src/DebugStreamer.cxx index 30de7c8de2e24..5debffbfb73ff 100644 --- a/Common/Utils/src/DebugStreamer.cxx +++ b/Common/Utils/src/DebugStreamer.cxx @@ -65,27 +65,22 @@ bool o2::utils::DebugStreamer::checkStream(const StreamFlags streamFlag, const s // check sampling frequency const auto sampling = getSamplingTypeFrequency(streamFlag); if (sampling.first != SamplingTypes::sampleAll) { - // init random number generator for each thread - static thread_local std::mt19937 generator(std::random_device{}()); - std::uniform_real_distribution<> distr(0, 1); - auto sampleTrack = [&]() { if (samplingID == -1) { LOGP(fatal, "Sampling type sampleID not supported for stream flag {}", streamFlag); } - std::uniform_real_distribution<> distr(0, 1); // sample on samplingID (e.g. track level) static thread_local std::unordered_map> idMap; // in case of first call samplingID in idMap is 0 and always false and first ID rejected if (idMap[streamFlag].first != samplingID) { - idMap[streamFlag] = std::pair{samplingID, (distr(generator) < sampling.second)}; + idMap[streamFlag] = std::pair{samplingID, (getRandom() < sampling.second)}; } return idMap[streamFlag].second; }; if (sampling.first == SamplingTypes::sampleRandom) { // just sample randomly - return (distr(generator) < sampling.second); + return (getRandom() < sampling.second); } else if (sampling.first == SamplingTypes::sampleID) { return sampleTrack(); } else if (sampling.first == SamplingTypes::sampleIDGlobal) { @@ -106,12 +101,44 @@ bool o2::utils::DebugStreamer::checkStream(const StreamFlags streamFlag, const s } } else if (sampling.first == SamplingTypes::sampleWeights) { // sample with weight - return (weight * distr(generator) < sampling.second); + return (weight * getRandom() < sampling.second); } } return true; } +float o2::utils::DebugStreamer::tsalisCharged(float pt, float mass, float sqrts) +{ + const float a = 6.81; + const float b = 59.24; + const float c = 0.082; + const float d = 0.151; + const float mt = std::sqrt(mass * mass + pt * pt); + const float n = a + b / sqrts; + const float T = c + d / sqrts; + const float p0 = n * T; + const float result = std::pow((1. + mt / p0), -n) * pt; + return result; +} + +bool o2::utils::DebugStreamer::downsampleTsalisCharged(float pt, float factorPt, float sqrts, float& weight, float rnd, float mass) +{ + const float prob = tsalisCharged(pt, mass, sqrts); + const float probNorm = tsalisCharged(1., mass, sqrts); + weight = prob / probNorm; + const bool isSampled = (rnd * (weight * pt * pt)) < factorPt; + return isSampled; +} + +float o2::utils::DebugStreamer::getRandom(float min, float max) +{ + // init random number generator for each thread + static thread_local std::mt19937 generator(std::random_device{}()); + std::uniform_real_distribution<> distr(min, max); + const float rnd = distr(generator); + return rnd; +} + int o2::utils::DebugStreamer::getIndex(const StreamFlags streamFlag) { // see: https://stackoverflow.com/a/71539401 diff --git a/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h b/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h index 82189ab6fdb9c..3b29cd3f00adb 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h +++ b/Detectors/Calibration/include/DetectorsCalibration/IntegratedClusterCalibrator.h @@ -362,11 +362,28 @@ struct ITSTPC_Matching { }; struct TimeSeriesITSTPC { - TimeSeries mTSTPC; ///< TPC standalone DCAs - TimeSeries mTSITSTPC; ///< ITS-TPC standalone DCAs - ITSTPC_Matching mITSTPCAll; ///< ITS-TPC matching efficiency for ITS standalone + afterburner - ITSTPC_Matching mITSTPCStandalone; ///< ITS-TPC matching efficiency for ITS standalone - ITSTPC_Matching mITSTPCAfterburner; ///< ITS-TPC matchin efficiency fir ITS afterburner + TimeSeries mTSTPC; ///< TPC standalone DCAs + TimeSeries mTSITSTPC; ///< ITS-TPC standalone DCAs + ITSTPC_Matching mITSTPCAll; ///< ITS-TPC matching efficiency for ITS standalone + afterburner + ITSTPC_Matching mITSTPCStandalone; ///< ITS-TPC matching efficiency for ITS standalone + ITSTPC_Matching mITSTPCAfterburner; ///< ITS-TPC matchin efficiency fir ITS afterburner + std::vector nPrimVertices; ///< number of primary vertices + std::vector nVertexContributors_Median; ///< number of primary vertices + std::vector nVertexContributors_RMS; ///< number of primary vertices + std::vector vertexX_Median; ///< vertex x position + std::vector vertexY_Median; ///< vertex y position + std::vector vertexZ_Median; ///< vertex z position + std::vector vertexX_RMS; ///< vertex x RMS + std::vector vertexY_RMS; ///< vertex y RMS + std::vector vertexZ_RMS; ///< vertex z RMS + std::vector mDCAr_comb_A_Median; ///< DCAr for ITS-TPC track - A-side + std::vector mDCAz_comb_A_Median; ///< DCAz for ITS-TPC track - A-side + std::vector mDCAr_comb_A_RMS; ///< DCAr RMS for ITS-TPC track - A-side + std::vector mDCAz_comb_A_RMS; ///< DCAz RMS for ITS-TPC track - A-side + std::vector mDCAr_comb_C_Median; ///< DCAr for ITS-TPC track - C-side + std::vector mDCAz_comb_C_Median; ///< DCAz for ITS-TPC track - C-side + std::vector mDCAr_comb_C_RMS; ///< DCAr RMS for ITS-TPC track - C-side + std::vector mDCAz_comb_C_RMS; ///< DCAz RMS for ITS-TPC track - C-side // dump this object to a tree void dumpToTree(const char* outFileName, const int nHBFPerTF = 32); @@ -390,6 +407,8 @@ struct TimeSeriesITSTPC { bool areSameSize() const { return (mTSTPC.areSameSize() && mTSITSTPC.areSameSize()); } ///< check if stored currents have same number of entries bool isEmpty() const { return mTSTPC.isEmpty(); } ///< check if values are empty size_t getEntries() const { return mTSTPC.getEntries(); } ///< \return returns number of values stored + void fill(const std::vector& vecFrom, std::vector& vecTo, const unsigned int posIndex) { std::copy(vecFrom.begin(), vecFrom.end(), vecTo.begin() + posIndex); } + void insert(std::vector& vec, const std::vector& vecTmp) { vec.insert(vec.begin(), vecTmp.begin(), vecTmp.end()); } /// acummulate integrated currents at given index /// \param posIndex index where data will be copied to @@ -401,6 +420,25 @@ struct TimeSeriesITSTPC { mITSTPCAll.fill(posIndex, data.mITSTPCAll); mITSTPCStandalone.fill(posIndex, data.mITSTPCStandalone); mITSTPCAfterburner.fill(posIndex, data.mITSTPCAfterburner); + fill(data.mDCAr_comb_A_Median, mDCAr_comb_A_Median, posIndex); + fill(data.mDCAz_comb_A_Median, mDCAz_comb_A_Median, posIndex); + fill(data.mDCAr_comb_A_RMS, mDCAr_comb_A_RMS, posIndex); + fill(data.mDCAz_comb_A_RMS, mDCAz_comb_A_RMS, posIndex); + fill(data.mDCAr_comb_C_Median, mDCAr_comb_C_Median, posIndex); + fill(data.mDCAz_comb_C_Median, mDCAz_comb_C_Median, posIndex); + fill(data.mDCAr_comb_C_RMS, mDCAr_comb_C_RMS, posIndex); + fill(data.mDCAz_comb_C_RMS, mDCAz_comb_C_RMS, posIndex); + + const int iTF = posIndex / mTSTPC.getNBins(); + nPrimVertices[iTF] = data.nPrimVertices.front(); + nVertexContributors_Median[iTF] = data.nVertexContributors_Median.front(); + nVertexContributors_RMS[iTF] = data.nVertexContributors_RMS.front(); + vertexX_Median[iTF] = data.vertexX_Median.front(); + vertexY_Median[iTF] = data.vertexY_Median.front(); + vertexZ_Median[iTF] = data.vertexZ_Median.front(); + vertexX_RMS[iTF] = data.vertexX_RMS.front(); + vertexY_RMS[iTF] = data.vertexY_RMS.front(); + vertexZ_RMS[iTF] = data.vertexZ_RMS.front(); } /// \param nDummyValues number of empty values which are inserted at the beginning of the accumulated integrated currents @@ -411,6 +449,27 @@ struct TimeSeriesITSTPC { mITSTPCAll.insert(nDummyValues); mITSTPCStandalone.insert(nDummyValues); mITSTPCAfterburner.insert(nDummyValues); + std::vector vecTmp(nDummyValues, 0); + insert(mDCAr_comb_A_Median, vecTmp); + insert(mDCAz_comb_A_Median, vecTmp); + insert(mDCAr_comb_A_RMS, vecTmp); + insert(mDCAz_comb_A_RMS, vecTmp); + insert(mDCAr_comb_C_Median, vecTmp); + insert(mDCAz_comb_C_Median, vecTmp); + insert(mDCAr_comb_C_RMS, vecTmp); + insert(mDCAz_comb_C_RMS, vecTmp); + + const int nDummyValuesVtx = nDummyValues / mTSTPC.getNBins(); + std::vector vecTmpVtx(nDummyValuesVtx, 0); + insert(nPrimVertices, vecTmp); + insert(nVertexContributors_Median, vecTmp); + insert(nVertexContributors_RMS, vecTmp); + insert(vertexX_Median, vecTmp); + insert(vertexY_Median, vecTmp); + insert(vertexZ_Median, vecTmp); + insert(vertexX_RMS, vecTmp); + insert(vertexY_RMS, vecTmp); + insert(vertexZ_RMS, vecTmp); } /// resize buffer for accumulated currents @@ -421,9 +480,28 @@ struct TimeSeriesITSTPC { mITSTPCAll.resize(nTotal); mITSTPCStandalone.resize(nTotal); mITSTPCAfterburner.resize(nTotal); - } - - ClassDefNV(TimeSeriesITSTPC, 1); + mDCAr_comb_A_Median.resize(nTotal); + mDCAz_comb_A_Median.resize(nTotal); + mDCAr_comb_A_RMS.resize(nTotal); + mDCAz_comb_A_RMS.resize(nTotal); + mDCAr_comb_C_Median.resize(nTotal); + mDCAz_comb_C_Median.resize(nTotal); + mDCAr_comb_C_RMS.resize(nTotal); + mDCAz_comb_C_RMS.resize(nTotal); + + const int nTotalVtx = nTotal / mTSTPC.getNBins(); + nPrimVertices.resize(nTotalVtx); + nVertexContributors_Median.resize(nTotalVtx); + nVertexContributors_RMS.resize(nTotalVtx); + vertexX_Median.resize(nTotalVtx); + vertexY_Median.resize(nTotalVtx); + vertexZ_Median.resize(nTotalVtx); + vertexX_RMS.resize(nTotalVtx); + vertexY_RMS.resize(nTotalVtx); + vertexZ_RMS.resize(nTotalVtx); + } + + ClassDefNV(TimeSeriesITSTPC, 2); }; } // end namespace tpc diff --git a/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx b/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx index dc500cb5ee774..93b19a0c99677 100644 --- a/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx +++ b/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx @@ -71,11 +71,14 @@ class TPCTimeSeries : public Task mNThreads = ic.options().get("threads"); maxITSTPCDCAr = ic.options().get("max-ITS-TPC-DCAr"); maxITSTPCDCAz = ic.options().get("max-ITS-TPC-DCAz"); + maxITSTPCDCAr_comb = ic.options().get("max-ITS-TPC-DCAr_comb"); + maxITSTPCDCAz_comb = ic.options().get("max-ITS-TPC-DCAz_comb"); mTimeWindowMUS = ic.options().get("time-window-mult-mus"); mMIPdEdx = ic.options().get("MIP-dedx"); mUseQMax = ic.options().get("use-qMax"); mMaxSnp = ic.options().get("max-snp"); mXCoarse = ic.options().get("mX-coarse"); + mSqrt = ic.options().get("sqrts"); mBufferVals.resize(mNThreads); mBufferDCA.setBinning(mPhiBins, mTglBins, mQPtBins); } @@ -120,7 +123,28 @@ class TPCTimeSeries : public Task const auto primMatchedTracks = pc.inputs().get>("pvtx_trmtc"); const auto primMatchedTracksRef = pc.inputs().get>("pvtx_tref"); - LOGP(detail, "Processing {} vertices, {} primary matched tracks, {} TPC tracks, {} ITS-TPC tracks", vertices.size(), primMatchedTracks.size(), tracksTPC.size(), tracksITSTPC.size()); + LOGP(info, "Processing {} vertices, {} primary matched tracks, {} TPC tracks, {} ITS-TPC tracks", vertices.size(), primMatchedTracks.size(), tracksTPC.size(), tracksITSTPC.size()); + + // calculate mean vertex, RMS and count vertices + std::array avgVtx; + for (auto& avg : avgVtx) { + avg.reserve(vertices.size()); + } + for (const auto& vtx : vertices) { + avgVtx[0].addValue(vtx.getX()); + avgVtx[1].addValue(vtx.getY()); + avgVtx[2].addValue(vtx.getZ()); + avgVtx[3].addValue(vtx.getNContributors()); + } + mBufferDCA.vertexX_Median.front() = avgVtx[0].getMedian(); + mBufferDCA.vertexY_Median.front() = avgVtx[1].getMedian(); + mBufferDCA.vertexZ_Median.front() = avgVtx[2].getMedian(); + mBufferDCA.vertexX_RMS.front() = avgVtx[0].getStdDev(); + mBufferDCA.vertexY_RMS.front() = avgVtx[1].getStdDev(); + mBufferDCA.vertexZ_RMS.front() = avgVtx[2].getStdDev(); + mBufferDCA.nPrimVertices.front() = vertices.size(); + mBufferDCA.nVertexContributors_Median.front() = avgVtx[3].getMedian(); + mBufferDCA.nVertexContributors_RMS.front() = avgVtx[3].getStdDev(); // storing collision vertex to ITS-TPC track index std::unordered_map indicesITSTPC_vtx; // ITS-TPC track index -> collision vertex ID @@ -169,6 +193,8 @@ class TPCTimeSeries : public Task mAvgCDCAr[i][type].clear(); mAvgADCAz[i][type].clear(); mAvgCDCAz[i][type].clear(); + } + for (int type = 0; type < mMIPdEdxRatioA[i].size(); ++type) { mMIPdEdxRatioA[i][type].clear(); mMIPdEdxRatioC[i][type].clear(); mTPCChi2A[i][type].clear(); @@ -200,6 +226,8 @@ class TPCTimeSeries : public Task mAvgCDCAr[i][type].reserve(loopEnd); mAvgADCAz[i][type].reserve(loopEnd); mAvgCDCAz[i][type].reserve(loopEnd); + } + for (int type = 0; type < mMIPdEdxRatioA[i].size(); ++type) { mMIPdEdxRatioA[i][type].reserve(loopEnd); mMIPdEdxRatioC[i][type].reserve(loopEnd); mTPCChi2A[i][type].reserve(loopEnd); @@ -215,8 +243,8 @@ class TPCTimeSeries : public Task } } for (int iThread = 0; iThread < mNThreads; ++iThread) { - mBufferVals[iThread].front().reserve(loopEnd); - mBufferVals[iThread].back().reserve(loopEnd); + mBufferVals[iThread].front().reserve(loopEnd, 1); + mBufferVals[iThread].back().reserve(loopEnd, 0); } using timer = std::chrono::high_resolution_clock; @@ -278,17 +306,26 @@ class TPCTimeSeries : public Task const auto dcaz = val.dcaz[i]; const auto dcarW = val.dcarW[i]; const int binInt = nBins - 1; + const bool fillCombDCA = ((type == 1) && (val.dcarcomb[i] != -1) && (val.dcazcomb[i] != -1)); const std::array bins{tglBin, phiBin, qPtBin, binInt}; // fill bins for (auto bin : bins) { if (val.side[i] == Side::C) { mAvgCDCAr[bin][type].addValue(dcar, dcarW); + if (fillCombDCA) { + mAvgCDCAr[bin][2].addValue(val.dcarcomb[i], dcarW); + mAvgCDCAz[bin][2].addValue(val.dcazcomb[i], dcarW); + } // fill only in case of valid value if (dcaz != 0) { mAvgCDCAz[bin][type].addValue(dcaz, dcarW); } } else { mAvgADCAr[bin][type].addValue(dcar, dcarW); + if (fillCombDCA) { + mAvgADCAr[bin][2].addValue(val.dcarcomb[i], dcarW); + mAvgADCAz[bin][2].addValue(val.dcazcomb[i], dcarW); + } // fill only in case of valid value if (dcaz != 0) { mAvgADCAz[bin][type].addValue(dcaz, dcarW); @@ -329,6 +366,24 @@ class TPCTimeSeries : public Task bufferDCA.mDCAz_C_WeightedMean[slice] = std::get<1>(dcaCz); bufferDCA.mDCAz_C_RMS[slice] = std::get<2>(dcaCz); bufferDCA.mDCAz_C_NTracks[slice] = std::get<3>(dcaCz); + // store combined ITS-TPC DCAs + if (type == 1) { + const auto dcaArComb = mAvgADCAr[slice][2].filterPointsMedian(mCutDCA, mCutRMS); + mBufferDCA.mDCAr_comb_A_Median[slice] = std::get<0>(dcaArComb); + mBufferDCA.mDCAr_comb_A_RMS[slice] = std::get<2>(dcaArComb); + + const auto dcaAzCom = mAvgADCAz[slice][2].filterPointsMedian(mCutDCA, mCutRMS); + mBufferDCA.mDCAz_comb_A_Median[slice] = std::get<0>(dcaAzCom); + mBufferDCA.mDCAz_comb_A_RMS[slice] = std::get<2>(dcaAzCom); + + const auto dcaCrComb = mAvgCDCAr[slice][2].filterPointsMedian(mCutDCA, mCutRMS); + mBufferDCA.mDCAr_comb_C_Median[slice] = std::get<0>(dcaCrComb); + mBufferDCA.mDCAr_comb_C_RMS[slice] = std::get<2>(dcaCrComb); + + const auto dcaCzComb = mAvgCDCAz[slice][2].filterPointsMedian(mCutDCA, mCutRMS); + mBufferDCA.mDCAz_comb_C_Median[slice] = std::get<0>(dcaCzComb); + mBufferDCA.mDCAz_comb_C_RMS[slice] = std::get<2>(dcaCzComb); + } } } @@ -446,7 +501,7 @@ class TPCTimeSeries : public Task private: /// buffer struct for multithreading struct FillVals { - void reserve(int n) + void reserve(int n, int type) { side.reserve(n); tglBin.reserve(n); @@ -455,12 +510,17 @@ class TPCTimeSeries : public Task dcar.reserve(n); dcaz.reserve(n); dcarW.reserve(n); - hasITS.reserve(n); - chi2Match.reserve(n); dedxRatio.reserve(n); sqrtChi2TPC.reserve(n); nClTPC.reserve(n); - gID.reserve(n); + if (type == 1) { + hasITS.reserve(n); + chi2Match.reserve(n); + gID.reserve(n); + } else if (type == 0) { + dcarcomb.reserve(n); + dcazcomb.reserve(n); + } } void clear() @@ -478,6 +538,8 @@ class TPCTimeSeries : public Task sqrtChi2TPC.clear(); nClTPC.clear(); gID.clear(); + dcarcomb.clear(); + dcazcomb.clear(); } void emplace_back(Side sideTmp, int tglBinTmp, int phiBinTmp, int qPtBinTmp, float dcarTmp, float dcazTmp, float dcarWTmp, float dedxRatioTmp, float sqrtChi2TPCTmp, float nClTPCTmp, o2::dataformats::GlobalTrackID::Source gIDTmp = o2::dataformats::GlobalTrackID::Source::NSources, float chi2MatchTmp = -2, int hasITSTmp = -1) @@ -499,6 +561,22 @@ class TPCTimeSeries : public Task } } + void emplace_back_ITSTPC(Side sideTmp, int tglBinTmp, int phiBinTmp, int qPtBinTmp, float dcarTmp, float dcazTmp, float dcarWTmp, float dedxRatioTmp, float sqrtChi2TPCTmp, float nClTPCTmp, float dcarCombTmp, float dcazCombTmp) + { + side.emplace_back(sideTmp); + tglBin.emplace_back(tglBinTmp); + phiBin.emplace_back(phiBinTmp); + qPtBin.emplace_back(qPtBinTmp); + dcar.emplace_back(dcarTmp); + dcaz.emplace_back(dcazTmp); + dcarW.emplace_back(dcarWTmp); + dedxRatio.emplace_back(dedxRatioTmp); + sqrtChi2TPC.emplace_back(sqrtChi2TPCTmp); + nClTPC.emplace_back(nClTPCTmp); + dcarcomb.emplace_back(dcarCombTmp); + dcazcomb.emplace_back(dcazCombTmp); + } + std::vector side; std::vector tglBin; std::vector phiBin; @@ -511,6 +589,8 @@ class TPCTimeSeries : public Task std::vector dedxRatio; std::vector sqrtChi2TPC; std::vector nClTPC; + std::vector dcarcomb; + std::vector dcazcomb; std::vector gID; }; std::shared_ptr mCCDBRequest; ///< info for CCDB request @@ -520,10 +600,10 @@ class TPCTimeSeries : public Task int mTglBins{3}; ///< number of tgl bins int mQPtBins{20}; ///< number of qPt bins TimeSeriesITSTPC mBufferDCA; ///< buffer for integrate DCAs - std::vector> mAvgADCAr; ///< for averaging the DCAr for TPC and ITS-TPC tracks for A-side - std::vector> mAvgCDCAr; ///< for averaging the DCAr for TPC and ITS-TPC tracks for C-side - std::vector> mAvgADCAz; ///< for averaging the DCAz for TPC and ITS-TPC tracks for A-side - std::vector> mAvgCDCAz; ///< for averaging the DCAz for TPC and ITS-TPC tracks for C-side + std::vector> mAvgADCAr; ///< for averaging the DCAr for TPC and ITS-TPC tracks for A-side + std::vector> mAvgCDCAr; ///< for averaging the DCAr for TPC and ITS-TPC tracks for C-side + std::vector> mAvgADCAz; ///< for averaging the DCAz for TPC and ITS-TPC tracks for A-side + std::vector> mAvgCDCAz; ///< for averaging the DCAz for TPC and ITS-TPC tracks for C-side std::vector> mMIPdEdxRatioA; ///< for averaging MIP/dEdx std::vector> mMIPdEdxRatioC; ///< for averaging MIP/dEdx std::vector> mTPCChi2A; ///< for averaging chi2 TPC A @@ -547,6 +627,8 @@ class TPCTimeSeries : public Task int mNThreads{1}; ///< number of parallel threads float maxITSTPCDCAr{0.2}; ///< maximum abs DCAr value for ITS-TPC tracks float maxITSTPCDCAz{10}; ///< maximum abs DCAz value for ITS-TPC tracks + float maxITSTPCDCAr_comb{0.2}; ///< max abs DCA for ITS-TPC DCA to vertex + float maxITSTPCDCAz_comb{0.2}; ///< max abs DCA for ITS-TPC DCA to vertex gsl::span mTPCTrackClIdx{}; ///< cluster refs for debugging std::vector> mBufferVals; ///< buffer for multithreading uint32_t mFirstTFOrbit{0}; ///< first TF orbit @@ -559,6 +641,7 @@ class TPCTimeSeries : public Task bool mUseQMax{false}; ///< use dedx qmax for MIP/dEdx monitoring float mMaxSnp{0.85}; ///< max sinus phi for propagation float mXCoarse{40}; ///< perform propagation with coarse steps up to this mx + float mSqrt{13600}; ///< centre of mass energy /// check if track passes coarse cuts bool acceptTrack(const TrackTPC& track) const @@ -669,66 +752,91 @@ class TPCTimeSeries : public Task // make cut on abs(DCA) if ((std::abs(dcaITSTPC[0]) < maxITSTPCDCAr) && (std::abs(dcaITSTPC[1]) < maxITSTPCDCAz)) { // store TPC only DCAs + // propagate to vertex in case the track belongs to vertex + const bool contributeToVertex = (idxITSTPC.back() != -1); + o2::gpu::gpustd::array dcaITSTPCTmp{-1, -1}; + + if (contributeToVertex) { + propagator->propagateToDCA(vertex.getXYZ(), trackITSTPCTmp, propagator->getNominalBz(), mFineStep, mMatType, &dcaITSTPCTmp); + } + + // make cut around DCA to vertex due to gammas + if ((std::abs(dcaITSTPCTmp[0]) < maxITSTPCDCAr_comb) && (std::abs(dcaITSTPCTmp[1]) < maxITSTPCDCAz_comb)) { + dcaITSTPCTmp[0] = -1; + dcaITSTPCTmp[1] = -1; + } + if (track.hasCSideClustersOnly()) { - mBufferVals[iThread].back().emplace_back(Side::C, tglBin, phiBin, qPtBin, dca[0], dcaZFromDeltaTime, dcarW, dedxRatio, sqrtChi2TPC, nClTPC); + mBufferVals[iThread].back().emplace_back_ITSTPC(Side::C, tglBin, phiBin, qPtBin, dca[0], dcaZFromDeltaTime, dcarW, dedxRatio, sqrtChi2TPC, nClTPC, dcaITSTPCTmp[0], dcaITSTPCTmp[1]); } else if (track.hasASideClustersOnly()) { - mBufferVals[iThread].back().emplace_back(Side::A, tglBin, phiBin, qPtBin, dca[0], dcaZFromDeltaTime, dcarW, dedxRatio, sqrtChi2TPC, nClTPC); + mBufferVals[iThread].back().emplace_back_ITSTPC(Side::A, tglBin, phiBin, qPtBin, dca[0], dcaZFromDeltaTime, dcarW, dedxRatio, sqrtChi2TPC, nClTPC, dcaITSTPCTmp[0], dcaITSTPCTmp[1]); } } } } GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamTimeSeries)) { - auto clusterMask = makeClusterBitMask(track); - const auto& trkOrig = tracksTPC[iTrk]; - const bool isNearestVtx = (idxITSTPC.back() == -1); // is nearest vertex in case no vertex was found - const float mx_ITS = hasITSTPC ? tracksITSTPC[idxITSTPC.front()].getX() : -1; - int typeSide = 2; // A- and C-Side cluster - if (track.hasASideClustersOnly()) { - typeSide = 0; - } else if (track.hasCSideClustersOnly()) { - typeSide = 1; + const auto sampling = o2::utils::DebugStreamer::getSamplingTypeFrequency(o2::utils::StreamFlags::streamTimeSeries); + const float factorPt = sampling.second; + bool writeData = true; + float weight = 0; + if (sampling.first == o2::utils::SamplingTypes::sampleTsalis) { + writeData = o2::utils::DebugStreamer::downsampleTsalisCharged(tracksTPC[iTrk].getPt(), factorPt, mSqrt, weight, o2::utils::DebugStreamer::getRandom()); } + if (writeData) { + auto clusterMask = makeClusterBitMask(track); + const auto& trkOrig = tracksTPC[iTrk]; + const bool isNearestVtx = (idxITSTPC.back() == -1); // is nearest vertex in case no vertex was found + const float mx_ITS = hasITSTPC ? tracksITSTPC[idxITSTPC.front()].getX() : -1; + int typeSide = 2; // A- and C-Side cluster + if (track.hasASideClustersOnly()) { + typeSide = 0; + } else if (track.hasCSideClustersOnly()) { + typeSide = 1; + } - o2::utils::DebugStreamer::instance()->getStreamer("time_series", "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName("treeTimeSeries").data() - // DCAs - << "dcar_tpc=" << dca[0] - << "dcaz_tpc=" << dca[1] - << "dcar_itstpc=" << dcaITSTPC[0] - << "dcaz_itstpc=" << dcaITSTPC[1] - << "dcarW=" << dcarW - << "dcaZFromDeltaTime=" << dcaZFromDeltaTime - << "hasITSTPC=" << hasITSTPC - // vertex - << "vertex_x=" << vertex.getX() - << "vertex_y=" << vertex.getY() - << "vertex_z=" << vertex.getZ() - << "vertex_time=" << vertex.getTimeStamp().getTimeStamp() - << "vertex_nContributors=" << vertex.getNContributors() - << "isNearestVertex=" << isNearestVtx - // tpc track properties - << "pt=" << trkOrig.getPt() - << "tpc_timebin=" << trkOrig.getTime0() - << "qpt=" << trkOrig.getParam(4) - << "ncl=" << trkOrig.getNClusters() - << "tgl=" << trkOrig.getTgl() - << "side_type=" << typeSide - << "phi=" << trkOrig.getPhi() - << "clusterMask=" << clusterMask - << "dedxTotTPC=" << trkOrig.getdEdx().dEdxTotTPC - << "dedxTotIROC=" << trkOrig.getdEdx().dEdxTotIROC - << "dedxTotOROC1=" << trkOrig.getdEdx().dEdxTotOROC1 - << "dedxTotOROC2=" << trkOrig.getdEdx().dEdxTotOROC2 - << "dedxTotOROC3=" << trkOrig.getdEdx().dEdxTotOROC3 - << "chi2=" << trkOrig.getChi2() - << "mX=" << trkOrig.getX() - << "mX_ITS=" << mx_ITS - // meta - << "mult=" << mNTracksWindow[iTrk] - << "time_window_mult=" << mTimeWindowMUS - << "firstTFOrbit=" << mFirstTFOrbit - << "mVDrift=" << mVDrift - << "\n"; + o2::utils::DebugStreamer::instance()->getStreamer("time_series", "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName("treeTimeSeries").data() + // DCAs + << "factorPt=" << factorPt + << "weight=" << weight + << "dcar_tpc=" << dca[0] + << "dcaz_tpc=" << dca[1] + << "dcar_itstpc=" << dcaITSTPC[0] + << "dcaz_itstpc=" << dcaITSTPC[1] + << "dcarW=" << dcarW + << "dcaZFromDeltaTime=" << dcaZFromDeltaTime + << "hasITSTPC=" << hasITSTPC + // vertex + << "vertex_x=" << vertex.getX() + << "vertex_y=" << vertex.getY() + << "vertex_z=" << vertex.getZ() + << "vertex_time=" << vertex.getTimeStamp().getTimeStamp() + << "vertex_nContributors=" << vertex.getNContributors() + << "isNearestVertex=" << isNearestVtx + // tpc track properties + << "pt=" << trkOrig.getPt() + << "tpc_timebin=" << trkOrig.getTime0() + << "qpt=" << trkOrig.getParam(4) + << "ncl=" << trkOrig.getNClusters() + << "tgl=" << trkOrig.getTgl() + << "side_type=" << typeSide + << "phi=" << trkOrig.getPhi() + << "clusterMask=" << clusterMask + << "dedxTotTPC=" << trkOrig.getdEdx().dEdxTotTPC + << "dedxTotIROC=" << trkOrig.getdEdx().dEdxTotIROC + << "dedxTotOROC1=" << trkOrig.getdEdx().dEdxTotOROC1 + << "dedxTotOROC2=" << trkOrig.getdEdx().dEdxTotOROC2 + << "dedxTotOROC3=" << trkOrig.getdEdx().dEdxTotOROC3 + << "chi2=" << trkOrig.getChi2() + << "mX=" << trkOrig.getX() + << "mX_ITS=" << mx_ITS + // meta + << "mult=" << mNTracksWindow[iTrk] + << "time_window_mult=" << mTimeWindowMUS + << "firstTFOrbit=" << mFirstTFOrbit + << "mVDrift=" << mVDrift + << "\n"; + } }) } } @@ -914,9 +1022,12 @@ o2::framework::DataProcessorSpec getTPCTimeSeriesSpec(const bool disableWriter, {"threads", VariantType::Int, 4, {"Number of parallel threads"}}, {"max-ITS-TPC-DCAr", VariantType::Float, 0.2f, {"Maximum absolut DCAr value for ITS-TPC tracks"}}, {"max-ITS-TPC-DCAz", VariantType::Float, 10.f, {"Maximum absolut DCAz value for ITS-TPC tracks - larger due to vertex spread"}}, + {"max-ITS-TPC-DCAr_comb", VariantType::Float, 0.2f, {"Maximum absolut DCAr value for ITS-TPC tracks to vertex for combined DCA"}}, + {"max-ITS-TPC-DCAz_comb", VariantType::Float, 0.2f, {"Maximum absolut DCAr value for ITS-TPC tracks to vertex for combined DCA"}}, {"MIP-dedx", VariantType::Float, 50.f, {"MIP dEdx for MIP/dEdx monitoring"}}, {"time-window-mult-mus", VariantType::Float, 50.f, {"Time window in micro s for multiplicity estimate"}}, - {"use-qMax", VariantType::Bool, false, {"Using qMax for MIP/dedx monitoring"}}}}; + {"use-qMax", VariantType::Bool, false, {"Using qMax for MIP/dedx monitoring"}}, + {"sqrts", VariantType::Float, 13600.f, {"Centre of mass energy used for downsampling"}}}}; } } // namespace tpc From 03833f67bde967c1307ac045fbd0df7e55fc8440 Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 20 Oct 2023 19:38:42 +0200 Subject: [PATCH 317/324] Add methods to get beam energy in GeV, make getSqrtS to return GeV/nucleon pair --- .../include/DataFormatsParameters/GRPLHCIFData.h | 15 +++++++++++++++ DataFormats/Parameters/src/GRPLHCIFData.cxx | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/DataFormats/Parameters/include/DataFormatsParameters/GRPLHCIFData.h b/DataFormats/Parameters/include/DataFormatsParameters/GRPLHCIFData.h index 7ac6cd6b00133..ddcda8f66507c 100644 --- a/DataFormats/Parameters/include/DataFormatsParameters/GRPLHCIFData.h +++ b/DataFormats/Parameters/include/DataFormatsParameters/GRPLHCIFData.h @@ -41,6 +41,7 @@ class GRPLHCIFData std::pair getBeamEnergyPerZWithTime() const { return mBeamEnergyPerZ; } int32_t getBeamEnergyPerZ() const { return mBeamEnergyPerZ.second; } + float getBeamEnergyPerZinGeV() const { return mBeamEnergyPerZ.second * 0.12; } long getBeamEnergyPerZTime() const { return mBeamEnergyPerZ.first; } void setBeamEnergyPerZWithTime(std::pair p) { mBeamEnergyPerZ = p; } void setBeamEnergyPerZWithTime(long t, int32_t v) { mBeamEnergyPerZ = std::make_pair(t, v); } @@ -84,12 +85,18 @@ class GRPLHCIFData /// getters/setters for given beam A and Z info, encoded as A<<16+Z int getBeamZ(beamDirection beam) const { return mBeamAZ[static_cast(beam)] & 0xffff; } int getBeamA(beamDirection beam) const { return mBeamAZ[static_cast(beam)] >> 16; } + int getBeamZ(int beam) const { return mBeamAZ[beam] & 0xffff; } + int getBeamA(int beam) const { return mBeamAZ[beam] >> 16; } float getBeamZoverA(beamDirection beam) const; + float getBeamZoverA(int beam) const; void setBeamAZ(int a, int z, beamDirection beam) { mBeamAZ[static_cast(beam)] = (a << 16) + z; } void setBeamAZ(beamDirection beam); void setBeamAZ(); /// getters/setters for beam energy per charge and per nucleon float getBeamEnergyPerNucleon(beamDirection beam) const { return mBeamEnergyPerZ.second * getBeamZoverA(beam); } + float getBeamEnergyPerNucleon(int beam) const { return mBeamEnergyPerZ.second * getBeamZoverA(beam); } + float getBeamEnergyPerNucleonInGeV(beamDirection beam) const { return getBeamEnergyPerZinGeV() * getBeamZoverA(beam); } + float getBeamEnergyPerNucleonInGeV(int beam) const { return getBeamEnergyPerZinGeV() * getBeamZoverA(beam); } /// calculate center of mass energy per nucleon collision float getSqrtS() const; /// helper function for BunchFilling @@ -119,6 +126,14 @@ inline float GRPLHCIFData::getBeamZoverA(beamDirection b) const return a ? getBeamZ(b) / static_cast(a) : 0.f; } +//______________________________________________ +inline float GRPLHCIFData::getBeamZoverA(int b) const +{ + // Z/A of beam 0 or 1 + int a = getBeamA(b); + return a ? getBeamZ(b) / static_cast(a) : 0.f; +} + } // namespace parameters } // namespace o2 #endif diff --git a/DataFormats/Parameters/src/GRPLHCIFData.cxx b/DataFormats/Parameters/src/GRPLHCIFData.cxx index dcbca0932cf69..8e779ef452191 100644 --- a/DataFormats/Parameters/src/GRPLHCIFData.cxx +++ b/DataFormats/Parameters/src/GRPLHCIFData.cxx @@ -60,8 +60,8 @@ void GRPLHCIFData::setBeamAZ() float GRPLHCIFData::getSqrtS() const { // get center of mass energy - double e0 = getBeamEnergyPerNucleon(BeamC); - double e1 = getBeamEnergyPerNucleon(BeamA); + double e0 = getBeamEnergyPerNucleonInGeV(BeamC); + double e1 = getBeamEnergyPerNucleonInGeV(BeamA); if (e0 <= MassProton || e1 <= MassProton) { return 0.f; } From 88822261c6c0383d6cdafc0a4bb63f5b58d270e7 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 19 Oct 2023 17:32:14 +0200 Subject: [PATCH 318/324] DPL: Should always check if we sent something before sending CCDB message --- Framework/Core/src/CommonServices.cxx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Framework/Core/src/CommonServices.cxx b/Framework/Core/src/CommonServices.cxx index 9d577ca5b990a..7852b9267f6d1 100644 --- a/Framework/Core/src/CommonServices.cxx +++ b/Framework/Core/src/CommonServices.cxx @@ -403,11 +403,9 @@ o2::framework::ServiceSpec CommonServices::ccdbSupportSpec() if (!service) { return; } - if (pc.services().get().streaming == StreamingState::EndOfStreaming) { - if (pc.outputs().countDeviceOutputs(true) == 0) { - LOGP(debug, "We are in EoS w/o outputs, do not automatically add DISTSUBTIMEFRAME to outgoing messages"); - return; - } + if (pc.outputs().countDeviceOutputs(true) == 0) { + LOGP(debug, "We are w/o outputs, do not automatically add DISTSUBTIMEFRAME to outgoing messages"); + return; } const auto ref = pc.inputs().getFirstValid(true); const auto* dh = DataRefUtils::getHeader(ref); From f68863bbc5c71705622a452593dc233cbbfd8958 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 19 Oct 2023 17:33:10 +0200 Subject: [PATCH 319/324] DPL: Take runNumber and timeSlice for CCDB message from timingInfo, instead of first random message --- Framework/Core/src/CommonServices.cxx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Framework/Core/src/CommonServices.cxx b/Framework/Core/src/CommonServices.cxx index 7852b9267f6d1..460702d654213 100644 --- a/Framework/Core/src/CommonServices.cxx +++ b/Framework/Core/src/CommonServices.cxx @@ -407,9 +407,7 @@ o2::framework::ServiceSpec CommonServices::ccdbSupportSpec() LOGP(debug, "We are w/o outputs, do not automatically add DISTSUBTIMEFRAME to outgoing messages"); return; } - const auto ref = pc.inputs().getFirstValid(true); - const auto* dh = DataRefUtils::getHeader(ref); - const auto* dph = DataRefUtils::getHeader(ref); + auto& timingInfo = pc.services().get(); // For any output that is a FLP/DISTSUBTIMEFRAME with subspec != 0, // we create a new message. @@ -424,9 +422,9 @@ o2::framework::ServiceSpec CommonServices::ccdbSupportSpec() continue; } auto& stfDist = pc.outputs().make(Output{concrete.origin, concrete.description, concrete.subSpec, output.matcher.lifetime}); - stfDist.id = dph->startTime; - stfDist.firstOrbit = dh->firstTForbit; - stfDist.runNumber = dh->runNumber; + stfDist.id = timingInfo.timeslice; + stfDist.firstOrbit = timingInfo.firstTForbit; + stfDist.runNumber = timingInfo.runNumber; } } }, .kind = ServiceKind::Global}; From 031dd8ac4551a3e9a6c9491613b6b5aad7abc89a Mon Sep 17 00:00:00 2001 From: Maximiliano Puccio Date: Sun, 22 Oct 2023 18:04:09 +0200 Subject: [PATCH 320/324] Flatten cell neighbours structure (#12121) --- .../tracking/include/ITStracking/TimeFrame.h | 12 +++--- .../ITSMFT/ITS/tracking/src/TimeFrame.cxx | 6 +-- .../ITSMFT/ITS/tracking/src/TrackerTraits.cxx | 41 ++++++++++++------- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h index 914479602469b..eda156a910bed 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h @@ -156,7 +156,8 @@ class TimeFrame std::vector>& getCellSeedsChi2() { return mCellSeedsChi2; } std::vector>& getCellsLookupTable(); - std::vector>>& getCellsNeighbours(); + std::vector>& getCellsNeighbours(); + std::vector>& getCellsNeighboursLUT(); std::vector>& getRoads(); std::vector& getTracks(int rof) { return mTracks[rof]; } std::vector& getTracksLabel(const int rof) { return mTracksLabel[rof]; } @@ -256,7 +257,8 @@ class TimeFrame std::vector> mCellSeeds; std::vector> mCellSeedsChi2; std::vector> mCellsLookupTable; - std::vector>> mCellsNeighbours; + std::vector> mCellsNeighbours; + std::vector> mCellsNeighboursLUT; std::vector> mRoads; std::vector> mTracksLabel; std::vector> mTracks; @@ -550,10 +552,8 @@ inline std::vector>& TimeFrame::getCellsLookupTable() return mCellsLookupTable; } -inline std::vector>>& TimeFrame::getCellsNeighbours() -{ - return mCellsNeighbours; -} +inline std::vector>& TimeFrame::getCellsNeighbours() { return mCellsNeighbours; } +inline std::vector>& TimeFrame::getCellsNeighboursLUT() { return mCellsNeighboursLUT; } inline std::vector>& TimeFrame::getRoads() { return mRoads; } diff --git a/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx b/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx index 11da548c377b0..bdf76ae9bdd23 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx @@ -266,6 +266,7 @@ void TimeFrame::initialise(const int iteration, const TrackingParameters& trkPar mCellSeedsChi2.resize(trkParam.CellsPerRoad()); mCellsLookupTable.resize(trkParam.CellsPerRoad() - 1); mCellsNeighbours.resize(trkParam.CellsPerRoad() - 1); + mCellsNeighboursLUT.resize(trkParam.CellsPerRoad() - 1); mCellLabels.resize(trkParam.CellsPerRoad()); mTracklets.resize(std::min(trkParam.TrackletsPerRoad(), maxLayers - 1)); mTrackletLabels.resize(trkParam.TrackletsPerRoad()); @@ -406,6 +407,7 @@ void TimeFrame::initialise(const int iteration, const TrackingParameters& trkPar if (iLayer < (int)mCells.size() - 1) { mCellsLookupTable[iLayer].clear(); mCellsNeighbours[iLayer].clear(); + mCellsNeighboursLUT[iLayer].clear(); } } } @@ -420,9 +422,7 @@ unsigned long TimeFrame::getArtefactsMemory() size += sizeof(Cell) * cells.size(); } for (auto& cellsN : mCellsNeighbours) { - for (auto& vec : cellsN) { - size += sizeof(int) * vec.size(); - } + size += sizeof(int) * cellsN.size(); } return size + sizeof(Road<5>) * mRoads.size(); } diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx index ff4642a99f7c3..8149a9a7ce38c 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx @@ -15,6 +15,7 @@ #include "ITStracking/TrackerTraits.h" +#include #include #include @@ -394,8 +395,13 @@ void TrackerTraits::findCellsNeighbours(const int iteration) int layerCellsNum{static_cast(mTimeFrame->getCells()[iLayer].size())}; const int nextLayerCellsNum{static_cast(mTimeFrame->getCells()[iLayer + 1].size())}; - mTimeFrame->getCellsNeighbours()[iLayer].resize(nextLayerCellsNum); + mTimeFrame->getCellsNeighboursLUT()[iLayer].clear(); + mTimeFrame->getCellsNeighboursLUT()[iLayer].resize(nextLayerCellsNum, 0); + std::vector> cellsNeighbours; + cellsNeighbours.reserve(nextLayerCellsNum); + + std::vector> easyWay(nextLayerCellsNum); for (int iCell{0}; iCell < layerCellsNum; ++iCell) { const Cell& currentCell{mTimeFrame->getCells()[iLayer][iCell]}; @@ -426,8 +432,9 @@ void TrackerTraits::findCellsNeighbours(const int iteration) continue; } - mTimeFrame->getCellsNeighbours()[iLayer][iNextCell].push_back(iCell); - + mTimeFrame->getCellsNeighboursLUT()[iLayer][iNextCell]++; + cellsNeighbours.push_back(std::make_pair(iCell, iNextCell)); + easyWay[iNextCell].push_back(iCell); const int currentCellLevel{currentCell.getLevel()}; if (currentCellLevel >= nextCell.getLevel()) { @@ -435,6 +442,15 @@ void TrackerTraits::findCellsNeighbours(const int iteration) } } } + std::sort(cellsNeighbours.begin(), cellsNeighbours.end(), [](const std::pair& a, const std::pair& b) { + return a.second < b.second; + }); + mTimeFrame->getCellsNeighbours()[iLayer].clear(); + mTimeFrame->getCellsNeighbours()[iLayer].reserve(cellsNeighbours.size()); + for (auto& cellNeighboursIndex : cellsNeighbours) { + mTimeFrame->getCellsNeighbours()[iLayer].push_back(cellNeighboursIndex.first); + } + std::inclusive_scan(mTimeFrame->getCellsNeighboursLUT()[iLayer].begin(), mTimeFrame->getCellsNeighboursLUT()[iLayer].end(), mTimeFrame->getCellsNeighboursLUT()[iLayer].begin()); } } @@ -457,11 +473,11 @@ void TrackerTraits::findRoads(const int iteration) if (iLevel == 1) { continue; } - const int cellNeighboursNum{static_cast( - mTimeFrame->getCellsNeighbours()[iLayer - 1][iCell].size())}; + const int startNeighbourId{iCell ? mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][iCell - 1] : 0}; + const int endNeighbourId{mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][iCell]}; bool isFirstValidNeighbour = true; - for (int iNeighbourCell{0}; iNeighbourCell < cellNeighboursNum; ++iNeighbourCell) { - const int neighbourCellId = mTimeFrame->getCellsNeighbours()[iLayer - 1][iCell][iNeighbourCell]; + for (int iNeighbourCell{startNeighbourId}; iNeighbourCell < endNeighbourId; ++iNeighbourCell) { + const int neighbourCellId = mTimeFrame->getCellsNeighbours()[iLayer - 1][iNeighbourCell]; const Cell& neighbourCell = mTimeFrame->getCells()[iLayer - 1][neighbourCellId]; if (iLevel - 1 != neighbourCell.getLevel()) { continue; @@ -973,14 +989,11 @@ void TrackerTraits::traverseCellsTree(const int currentCellId, const int current mTimeFrame->getRoads().back().addCell(currentLayerId, currentCellId); if (currentLayerId > 0 && currentCellLevel > 1) { - const int cellNeighboursNum{static_cast( - mTimeFrame->getCellsNeighbours()[currentLayerId - 1][currentCellId].size())}; bool isFirstValidNeighbour = true; - - for (int iNeighbourCell{0}; iNeighbourCell < cellNeighboursNum; ++iNeighbourCell) { - - const int neighbourCellId = - mTimeFrame->getCellsNeighbours()[currentLayerId - 1][currentCellId][iNeighbourCell]; + const int startNeighbourId = currentCellId ? mTimeFrame->getCellsNeighboursLUT()[currentLayerId - 1][currentCellId - 1] : 0; + const int endNeighbourId = mTimeFrame->getCellsNeighboursLUT()[currentLayerId - 1][currentCellId]; + for (int iNeighbourCell{startNeighbourId}; iNeighbourCell < endNeighbourId; ++iNeighbourCell) { + const int neighbourCellId = mTimeFrame->getCellsNeighbours()[currentLayerId - 1][iNeighbourCell]; const Cell& neighbourCell = mTimeFrame->getCells()[currentLayerId - 1][neighbourCellId]; if (currentCellLevel - 1 != neighbourCell.getLevel()) { From 41e504d7b65f492df15b1b060584e7d972c7d418 Mon Sep 17 00:00:00 2001 From: Ruben Shahoyan Date: Sun, 22 Oct 2023 19:21:33 +0200 Subject: [PATCH 321/324] Protect MatLut against dZ=0 (#12124) Co-authored-by: shahoian --- Detectors/Base/include/DetectorsBase/Ray.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/Base/include/DetectorsBase/Ray.h b/Detectors/Base/include/DetectorsBase/Ray.h index 9f087363707c4..5787aeaf33572 100644 --- a/Detectors/Base/include/DetectorsBase/Ray.h +++ b/Detectors/Base/include/DetectorsBase/Ray.h @@ -164,7 +164,7 @@ inline Ray::Ray(const math_utils::Point3D point0, const math_utils::Point mXDxPlusYDy2 = mXDxPlusYDy * mXDxPlusYDy; mR02 = point0.Perp2(); mR12 = point1.Perp2(); - mInvDz = 1.f / mD[2]; + mInvDz = std::abs(mD[2]) > Tiny ? (1.f / mD[2]) : (mD[2] > 0 ? 1.f / Tiny : -1.f / Tiny); } #endif // !GPUCA_ALIGPUCODE @@ -180,7 +180,7 @@ GPUdi() Ray::Ray(float x0, float y0, float z0, float x1, float y1, float z1) mXDxPlusYDy2 = mXDxPlusYDy * mXDxPlusYDy; mR02 = x0 * x0 + y0 * y0; mR12 = x1 * x1 + y1 * y1; - mInvDz = 1.f / mD[2]; + mInvDz = std::abs(mD[2]) > Tiny ? (1.f / mD[2]) : (mD[2] > 0 ? 1.f / Tiny : -1.f / Tiny); } //______________________________________________________ From 2751f04724257d8edeefcffe7b4e15ea1093fecb Mon Sep 17 00:00:00 2001 From: Matteo Concas Date: Mon, 23 Oct 2023 08:51:24 +0200 Subject: [PATCH 322/324] Update CODEOWNERS for upgrades (#12125) --- CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 4fed61cf41a5c..b6a04d3ad052c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -41,7 +41,7 @@ /DataFormats/Detectors/TOF @noferini /DataFormats/Detectors/TPC @davidrohr @wiechula @shahor02 /DataFormats/Detectors/TRD @f3sch @bazinski @martenole -/DataFormats/Detectors/Upgrades @qgp @marcovanleeuwen @mconcas +/DataFormats/Detectors/Upgrades @mconcas /DataFormats/Detectors/Upgrades/ITS3 @fgrosa @arossi81 /DataFormats/Detectors/ZDC @coppedis @@ -72,7 +72,7 @@ /Detectors/TOF @noferini /Detectors/TPC @davidrohr @wiechula @shahor02 /Detectors/TRD @f3sch @bazinski @martenole -/Detectors/Upgrades @qgp @mconcas +/Detectors/Upgrades @mconcas /Detectors/Upgrades/ITS3 @fgrosa @arossi81 @mconcas /Detectors/ZDC @coppedis /Detectors/CTF @shahor02 From 14f0c2ffe8abcb0feaeed03e6bd3b955990d80b9 Mon Sep 17 00:00:00 2001 From: ddobrigk Date: Mon, 23 Oct 2023 10:39:19 +0200 Subject: [PATCH 323/324] Revert "Protect MatLut against dZ=0 (#12124)" This reverts commit 04ce1274f237a6fd89368ac00134a0a408bed39a. --- Detectors/Base/include/DetectorsBase/Ray.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/Base/include/DetectorsBase/Ray.h b/Detectors/Base/include/DetectorsBase/Ray.h index 5787aeaf33572..9f087363707c4 100644 --- a/Detectors/Base/include/DetectorsBase/Ray.h +++ b/Detectors/Base/include/DetectorsBase/Ray.h @@ -164,7 +164,7 @@ inline Ray::Ray(const math_utils::Point3D point0, const math_utils::Point mXDxPlusYDy2 = mXDxPlusYDy * mXDxPlusYDy; mR02 = point0.Perp2(); mR12 = point1.Perp2(); - mInvDz = std::abs(mD[2]) > Tiny ? (1.f / mD[2]) : (mD[2] > 0 ? 1.f / Tiny : -1.f / Tiny); + mInvDz = 1.f / mD[2]; } #endif // !GPUCA_ALIGPUCODE @@ -180,7 +180,7 @@ GPUdi() Ray::Ray(float x0, float y0, float z0, float x1, float y1, float z1) mXDxPlusYDy2 = mXDxPlusYDy * mXDxPlusYDy; mR02 = x0 * x0 + y0 * y0; mR12 = x1 * x1 + y1 * y1; - mInvDz = std::abs(mD[2]) > Tiny ? (1.f / mD[2]) : (mD[2] > 0 ? 1.f / Tiny : -1.f / Tiny); + mInvDz = 1.f / mD[2]; } //______________________________________________________ From ef65346b129194de39cee1e6bc6f4ee8f2cce91a Mon Sep 17 00:00:00 2001 From: Ruben Shahoyan Date: Mon, 23 Oct 2023 11:00:16 +0200 Subject: [PATCH 324/324] Revert "MatLUT: faster phi-sector determination; reduction of divisions (#12030)" This reverts commit 030e39648d85863cc4d89e57df98498c4f53cfc1. --- Detectors/Base/include/DetectorsBase/Ray.h | 56 +--------------------- Detectors/Base/src/MatLayerCylSet.cxx | 9 ++-- 2 files changed, 7 insertions(+), 58 deletions(-) diff --git a/Detectors/Base/include/DetectorsBase/Ray.h b/Detectors/Base/include/DetectorsBase/Ray.h index 9f087363707c4..1701e65c2d638 100644 --- a/Detectors/Base/include/DetectorsBase/Ray.h +++ b/Detectors/Base/include/DetectorsBase/Ray.h @@ -46,7 +46,7 @@ class Ray static constexpr float InvalidT = -1e9; static constexpr float Tiny = 1e-9; - GPUd() Ray() : mP{0.f}, mD{0.f}, mDistXY2(0.f), mDistXY2i(0.f), mDistXYZ(0.f), mXDxPlusYDy(0.f), mXDxPlusYDyRed(0.f), mXDxPlusYDy2(0.f), mR02(0.f), mR12(0.f), mInvDz(Tiny) + GPUd() Ray() : mP{0.f}, mD{0.f}, mDistXY2(0.f), mDistXY2i(0.f), mDistXYZ(0.f), mXDxPlusYDy(0.f), mXDxPlusYDyRed(0.f), mXDxPlusYDy2(0.f), mR02(0.f), mR12(0.f) { } GPUdDefault() ~Ray() CON_DEFAULT; @@ -61,7 +61,6 @@ class Ray GPUd() float crossRadial(const MatLayerCyl& lr, int sliceID) const; GPUd() float crossRadial(float cs, float sn) const; GPUd() float crossZ(float z) const; - GPUd() float crossZ_fast(float z) const; // without check GPUd() void getCrossParams(int i, float& par1, float& par2) const { @@ -85,49 +84,6 @@ class Ray return p; } - // fast, approximate arctan calculation - sufficient for phi sector determination in material budget layers - // source of inspirations: - // - https://mazzo.li/posts/vectorized-atan2.html - // - https://www.coranac.com/documents/arctangent/ - GPUd() float atan_approx_5terms(float x) const - { - // fast atan implementation - // function has a max error of ~1.16825e-05f - float a1 = 0.9998660f; - float a3 = -0.3302995f; - float a5 = 0.1801410f; - float a7 = -0.0851330f; - float a9 = 0.0208351f; - - float x_sq = x * x; - // todo: force fuse-multiply add - return x * (a1 + x_sq * (a3 + x_sq * (a5 + x_sq * (a7 + x_sq * a9)))); - } - - GPUd() float atan2_approx(float y, float x) const - { - const bool swap = fabs(x) < fabs(y); - const float atan_input = (swap ? x : y) / (swap ? y : x); - const float pi2 = M_PI_2; - const float pi = M_PI; - float res = atan_approx_5terms(atan_input); - - // if swapped, adjust atan output - res = swap ? (atan_input >= 0.0f ? pi2 : -pi2) - res : res; - // adjust quadrants - if (x < 0.0f) { - res = ((y < 0.0f) ? -pi : pi) + res; - } - return res; - } - - GPUd() float getPhi_approx(float t) const - { - float p = atan2_approx(mP[1] + t * mD[1], mP[0] + t * mD[0]); - o2::math_utils::bringTo02Pi(p); - return p; - } - GPUd() float getZ(float t) const { return mP[2] + t * mD[2]; } GPUd() bool validateZRange(float& cpar1, float& cpar2, const MatLayerCyl& lr) const; @@ -145,7 +101,6 @@ class Ray float mR12; ///< radius^2 of mP1 float mCrossParams1[2]; ///< parameters of crossing the layer (first parameter) float mCrossParams2[2]; ///< parameters of crossing the layer (second parameter) - float mInvDz; ClassDefNV(Ray, 1); }; @@ -164,7 +119,6 @@ inline Ray::Ray(const math_utils::Point3D point0, const math_utils::Point mXDxPlusYDy2 = mXDxPlusYDy * mXDxPlusYDy; mR02 = point0.Perp2(); mR12 = point1.Perp2(); - mInvDz = 1.f / mD[2]; } #endif // !GPUCA_ALIGPUCODE @@ -180,7 +134,6 @@ GPUdi() Ray::Ray(float x0, float y0, float z0, float x1, float y1, float z1) mXDxPlusYDy2 = mXDxPlusYDy * mXDxPlusYDy; mR02 = x0 * x0 + y0 * y0; mR12 = x1 * x1 + y1 * y1; - mInvDz = 1.f / mD[2]; } //______________________________________________________ @@ -222,13 +175,6 @@ GPUdi() float Ray::crossZ(float z) const return mD[2] != 0. ? (z - mP[2]) / mD[2] : InvalidT; } -//______________________________________________________ -GPUdi() float Ray::crossZ_fast(float z) const -{ - // calculate t of crossing XY plane at Z - return (z - mP[2]) * mInvDz; -} - //______________________________________________________ GPUdi() bool Ray::validateZRange(float& cpar1, float& cpar2, const MatLayerCyl& lr) const { diff --git a/Detectors/Base/src/MatLayerCylSet.cxx b/Detectors/Base/src/MatLayerCylSet.cxx index 6ee8a006db002..fb2e720427016 100644 --- a/Detectors/Base/src/MatLayerCylSet.cxx +++ b/Detectors/Base/src/MatLayerCylSet.cxx @@ -294,8 +294,8 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa for (int ic = nc; ic--;) { float cross1, cross2; ray.getCrossParams(ic, cross1, cross2); // tmax,tmin of crossing the layer - auto phi0 = ray.getPhi_approx(cross1), phi1 = ray.getPhi_approx(cross2), dPhi = phi0 - phi1; - // auto phi0 = ray.getPhi(cross1), phi1 = ray.getPhi(cross2), dPhi = phi0 - phi1; + + auto phi0 = ray.getPhi(cross1), phi1 = ray.getPhi(cross2), dPhi = phi0 - phi1; auto phiID = lr.getPhiSliceID(phi0), phiIDLast = lr.getPhiSliceID(phi1); // account for eventual wrapping around 0 if (dPhi > 0.f) { @@ -339,7 +339,10 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa tEndZ = tEndPhi; checkMoreZ = false; } else { - tEndZ = ray.crossZ_fast(lr.getZBinMin(stepZID > 0 ? zID + 1 : zID)); + tEndZ = ray.crossZ(lr.getZBinMin(stepZID > 0 ? zID + 1 : zID)); + if (tEndZ == Ray::InvalidT) { // track normal to Z axis, abandon Zbin change test + break; + } } // account materials of this step float step = tEndZ > tStartZ ? tEndZ - tStartZ : tStartZ - tEndZ; // the real step is ray.getDist(tEnd-tStart), will rescale all later