diff --git a/Detectors/TRD/calibration/include/TRDCalibration/DCSProcessor.h b/Detectors/TRD/calibration/include/TRDCalibration/DCSProcessor.h index 5b5323ada0e9a..7ff85499835f4 100644 --- a/Detectors/TRD/calibration/include/TRDCalibration/DCSProcessor.h +++ b/Detectors/TRD/calibration/include/TRDCalibration/DCSProcessor.h @@ -64,10 +64,27 @@ class DCSProcessor bool updateCurrentsDPsCCDB(); bool updateEnvDPsCCDB(); bool updateRunDPsCCDB(); + // LB: new DPs for Fed + bool updateFedChamberStatusDPsCCDB(); + bool updateFedCFGtagDPsCCDB(); // 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; } + // LB: Env DPs have no alias pattern, processor uses this function to identify if alias is Env + bool isAliasFromEnvDP(const char* dpalias) const + { + std::vector envaliases = {"CavernTemperature", "temperature_P2_external", "AtmosPressure", "UXC2Humidity"}; + for (const auto& envalias : envaliases) { + if (std::strstr(dpalias, envalias.c_str()) != nullptr) { + return true; + } + } + return false; + } // allow access to the CCDB objects from DPL processor CcdbObjectInfo& getccdbGasDPsInfo() { return mCcdbGasDPsInfo; } @@ -75,15 +92,22 @@ class DCSProcessor CcdbObjectInfo& getccdbCurrentsDPsInfo() { return mCcdbCurrentsDPsInfo; } CcdbObjectInfo& getccdbEnvDPsInfo() { return mCcdbEnvDPsInfo; } CcdbObjectInfo& getccdbRunDPsInfo() { return mCcdbRunDPsInfo; } + CcdbObjectInfo& getccdbFedChamberStatusDPsInfo() { return mCcdbFedChamberStatusDPsInfo; } + CcdbObjectInfo& getccdbFedCFGtagDPsInfo() { return mCcdbFedCFGtagDPsInfo; } 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::array& getTRDFedChamberStatusDPsInfo() const { return mTRDDCSFedChamberStatus; } + const std::array& getTRDFedCFGtagDPsInfo() const { return mTRDDCSFedCFGtag; } // 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; } + void setUVariationTriggerForUpdate(float utrigger) { mUVariationTriggerForUpdate = utrigger; } // reset methods void clearGasDPsInfo(); @@ -91,6 +115,9 @@ class DCSProcessor void clearCurrentsDPsInfo(); void clearEnvDPsInfo(); void clearRunDPsInfo(); + // LB: new DPs for Fed + void clearFedChamberStatusDPsInfo(); + void clearFedCFGtagDPsInfo(); // helper functions int getChamberIdFromAlias(const char* alias) const; @@ -100,14 +127,11 @@ class DCSProcessor std::unordered_map mTRDDCSGas; ///< gas DPs (CO2, O2, H20 and from the chromatograph CO2, N2, Xe) std::unordered_map mTRDDCSCurrents; ///< anode and drift currents 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 + std::unordered_map mTRDDCSEnv; ///< environment parameters (temperatures, pressures, humidity) + std::unordered_map mTRDDCSRun; ///< run number (run type ignored) + // LB: new DPs for Fed + std::array mTRDDCSFedChamberStatus; ///< fed chamber status + std::array mTRDDCSFedCFGtag; ///< fed config tag // helper variables std::unordered_map mPids; ///< flag for each DP whether it has been processed at least once @@ -117,24 +141,47 @@ class DCSProcessor CcdbObjectInfo mCcdbCurrentsDPsInfo; CcdbObjectInfo mCcdbEnvDPsInfo; CcdbObjectInfo mCcdbRunDPsInfo; + // LB: new DPs for Fed + CcdbObjectInfo mCcdbFedChamberStatusDPsInfo; + CcdbObjectInfo mCcdbFedCFGtagDPsInfo; + 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 + TFType mFedChamberStatusStartTS; + TFType mFedCFGtagStartTS; 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 + bool mFedChamberStatusStartTSSet{false}; + bool mFedCFGtagStartTSSet{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{522}; + float mUVariationTriggerForUpdate{1.0}; ClassDefNV(DCSProcessor, 0); }; diff --git a/Detectors/TRD/calibration/macros/makeTRDCCDBEntryForDCS.C b/Detectors/TRD/calibration/macros/makeTRDCCDBEntryForDCS.C index 55de2e0759aa1..462f803ff7098 100644 --- a/Detectors/TRD/calibration/macros/makeTRDCCDBEntryForDCS.C +++ b/Detectors/TRD/calibration/macros/makeTRDCCDBEntryForDCS.C @@ -30,15 +30,27 @@ int makeTRDCCDBEntryForDCS(const std::string url = "http://localhost:8080") std::vector aliasesFloat; std::vector aliasesInt; std::vector aliasesString; + + // Gas DPs aliasesFloat.insert(aliasesFloat.end(), {"trd_gasCO2", "trd_gasH2O", "trd_gasO2"}); aliasesFloat.insert(aliasesFloat.end(), {"trd_gaschromatographCO2", "trd_gaschromatographN2", "trd_gaschromatographXe"}); + + // Current and Voltages DPs 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"}); - 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]"}); + + // FED DPs + aliasesInt.insert(aliasesInt.end(), {"trd_chamberStatus[00..539]"}); + aliasesString.insert(aliasesString.end(), {"trd_CFGtag[00..539]"}); + + // Environment DPs + aliasesFloat.insert(aliasesFloat.end(), {"CavernTemperature", "temperature_P2_external"}); + aliasesFloat.insert(aliasesFloat.end(), {"CavernAtmosPressure", "SurfaceAtmosPressure", "CavernAtmosPressure2"}); + aliasesFloat.insert(aliasesFloat.end(), {"UXC2Humidity"}); + + // Run DPs + aliasesInt.insert(aliasesInt.end(), {"trd_fed_runNo"}); + + // Ignorded DPs: trd_fed_runType, trd_envTemp[00..539], trd_gasOverpressure* 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..0d577691d1fb0 100644 --- a/Detectors/TRD/calibration/macros/readTRDDCSentries.C +++ b/Detectors/TRD/calibration/macros/readTRDDCSentries.C @@ -24,13 +24,15 @@ #include #endif -void readTRDDCSentries(std::string ccdb = "http://localhost:8080", long ts = -1) +void readTRDDCSentries(std::string ccdb = "http://localhost:8080", long ts = -1, bool printGas = true, bool printChamber = true, + bool printI = true, bool printU = true, bool printEnv = true) { auto& ccdbmgr = o2::ccdb::BasicCCDBManager::instance(); 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); @@ -44,21 +46,67 @@ void readTRDDCSentries(std::string ccdb = "http://localhost:8080", long ts = -1) std::cout << std::endl; // now, access the actual calibration object from CCDB - auto cal = ccdbmgr.get>("TRD/Calib/DCSDPsGas"); + // Access Gas DPs + if (printGas) { + auto calgas = ccdbmgr.get>("TRD/Calib/DCSDPsGas"); - std::cout << "Printing a single object from the map (trd_gasCO2):" << std::endl; - o2::dcs::DataPointIdentifier dpid; // used as key to access the map - o2::dcs::DataPointIdentifier::FILL(dpid, "trd_gasCO2", o2::dcs::DeliveryType::DPVAL_DOUBLE); - auto obj = cal->at(dpid); - obj.print(); - std::cout << std::endl; + // LB: use this as template for reading only a single object + // std::cout << "Printing a single object from the map (trd_gasCO2):" << std::endl; + // o2::dcs::DataPointIdentifier dpid; // used as key to access the map + // o2::dcs::DataPointIdentifier::FILL(dpid, "trd_gasCO2", o2::dcs::DeliveryType::DPVAL_DOUBLE); + // auto obj = calgas->at(dpid); + // obj.print(); + // std::cout << std::endl; - std::cout << "And lastly print all objects from the map, together with their DataPointIdentifier:" << std::endl; - for (const auto& entry : *cal) { - std::cout << entry.first << std::endl; - entry.second.print(); + std::cout << "Print all objects from the map (DCSDPsGas), together with their DataPointIdentifier:" << std::endl; + for (const auto& entry : *calgas) { + std::cout << entry.first << std::endl; + entry.second.print(); + std::cout << std::endl; + } + } + + // Access ChamberStatus and CFGtag DPs + if (printChamber) { + auto calchamberstatus = ccdbmgr.get>("TRD/Calib/DCSDPsFedChamberStatus"); + auto calcfgtag = ccdbmgr.get>("TRD/Calib/DCSDPsFedCFGtag"); + std::cout << "Print all objects from the chambers (DCSDPsFedChamberStatus and DCSDPsFedCFGtag), together with their chamber ID:" << std::endl; + for (int i = 0; i < o2::trd::constants::MAXCHAMBER; i++) { + std::cout << "Chamber ID = " << i << ",\tstatus = " << (*calchamberstatus)[i] << ",\tcfgtag = " << (*calcfgtag)[i] << std::endl; + } + std::cout << std::endl; + } + + // Access Current DPs + if (printI) { + auto cali = ccdbmgr.get>("TRD/Calib/DCSDPsI"); + std::cout << "Print all objects from the map (DCSDPsI), together with their DataPointIdentifier:" << std::endl; + for (const auto& entry : *cali) { + std::cout << entry.first << std::endl; + entry.second.print(); + std::cout << std::endl; + } + } + + // Access Voltages DPs + if (printU) { + auto calu = ccdbmgr.get>("TRD/Calib/DCSDPsU"); + std::cout << "Print all objects from the map (DCSDPsU), together with their DataPointIdentifier:" << std::endl; + for (const auto& entry : *calu) { + std::cout << "id = " << entry.first << ",\tvalue = " << entry.second << std::endl; + } + } + + // Access Env DPs + if (printEnv) { + auto calenv = ccdbmgr.get>("TRD/Calib/DCSDPsEnv"); + std::cout << "Print all objects from the map (DCSDPsEnv), together with their DataPointIdentifier:" << std::endl; + for (const auto& entry : *calenv) { + 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..ec86cbbd5df4d 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 mFedMinimunDPsForUpdate (522) => all DPs were sent + if (std::strstr(it.id.get_alias(), "trd_chamberStatus") != nullptr) { + ChamberStatusDPsCounter++; + } else if (std::strstr(it.id.get_alias(), "trd_CFGtag") != 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) { @@ -137,7 +168,7 @@ int DCSProcessor::processDP(const DPCOM& dpcom) if (etime != mLastDPTimeStamps[dpid]) { int chamberId = getChamberIdFromAlias(dpid.get_alias()); if (mVoltageSet.test(chamberId)) { - if (std::fabs(dpInfoVoltages - o2::dcs::getValue(dpcom)) > 1.f) { + if (std::fabs(dpInfoVoltages - o2::dcs::getValue(dpcom)) > mUVariationTriggerForUpdate) { // trigger update of voltage CCDB object mShouldUpdateVoltages = true; // OS: this will still overwrite the current voltage value of the object going into the CCDB @@ -151,7 +182,7 @@ int DCSProcessor::processDP(const DPCOM& dpcom) } // check if DP is env value - if (std::strstr(dpid.get_alias(), "trd_aliEnv") != nullptr) { + if (isAliasFromEnvDP(dpid.get_alias())) { if (!mEnvStartTSSet) { mEnvStartTS = mCurrentTS; mEnvStartTSSet = true; @@ -164,41 +195,97 @@ int DCSProcessor::processDP(const DPCOM& dpcom) } } } + if (type == DPVAL_INT) { - if (std::strstr(dpid.get_alias(), "trd_runNo") != nullptr) { // DP is trd_runNo + if (std::strstr(dpid.get_alias(), "trd_fed_runNo") != nullptr) { // DP is trd_fed_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); + + // 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; + // LB: reset alarm counters + mFedChamberStatusAlarmCounter = 0; + mFedCFGtagAlarmCounter = 0; + mRunEndTS = mCurrentTS; + } + + // LB: Save current run number + mCurrentRunNumber = o2::dcs::getValue(dpcom); + // Save to mTRDDCSRun + runNumber = mCurrentRunNumber; } - } else if (std::strstr(dpid.get_alias(), "trd_runType") != nullptr) { // DP is trd_runType - if (!mRunStartTSSet) { - mRunStartTS = mCurrentTS; - mRunStartTSSet = true; + + if (mVerbosity > 2) { + LOG(info) << "Current Run Number: " << mCurrentRunNumber; } - 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); + + } else if (std::strstr(dpid.get_alias(), "trd_chamberStatus") != nullptr) { // DP is trd_chamberStatus + if (!mFedChamberStatusStartTSSet) { + mFedChamberStatusStartTS = mCurrentTS; + mFedChamberStatusStartTSSet = true; + } + + // LB: for ChamberStatus, grab the chamber number from alias + int chamberId = getChamberIdFromAlias(dpid.get_alias()); + auto& dpInfoFedChamberStatus = mTRDDCSFedChamberStatus[chamberId]; + 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 + // LB: set both to warnings, conditions are kept if future changes are needed + if (mFedChamberStatusAlarmCounter < mFedAlarmCounterMax) { + LOG(warn) << "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 (std::strstr(dpid.get_alias(), "trd_CFGtag") != nullptr) { // DP is trd_CFGtag + if (!mFedCFGtagStartTSSet) { + mFedCFGtagStartTS = mCurrentTS; + mFedCFGtagStartTSSet = true; + } + + // LB: for CFGtag, grab the chamber number from alias + int chamberId = getChamberIdFromAlias(dpid.get_alias()); + auto& dpInfoFedCFGtag = mTRDDCSFedCFGtag[chamberId]; + 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 +436,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]; } } } @@ -371,11 +458,11 @@ bool DCSProcessor::updateEnvDPsCCDB() 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_aliEnv") != nullptr) { + if (isAliasFromEnvDP(it.first.get_alias())) { 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(); } @@ -383,7 +470,7 @@ bool DCSProcessor::updateEnvDPsCCDB() } } std::map md; - md["responsible"] = "Ole Schmidt"; + md["responsible"] = "Leonardo Barreto"; o2::calibration::Utils::prepareCCDBobjectInfo(mTRDDCSEnv, mCcdbEnvDPsInfo, "TRD/Calib/DCSDPsEnv", md, mEnvStartTS, mEnvStartTS + 3 * o2::ccdb::CcdbObjectInfo::DAY); return retVal; @@ -398,8 +485,8 @@ bool DCSProcessor::updateRunDPsCCDB() 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_run") != nullptr) { + if (type == o2::dcs::DPVAL_INT) { + if (std::strstr(it.first.get_alias(), "trd_fed_run") != nullptr) { if (it.second == true) { // we processed the DP at least 1x retVal = true; } @@ -410,9 +497,80 @@ 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_chamberStatus") != nullptr) { + if (it.second == true) { // we processed the DP at least 1x + retVal = true; + } + if (mVerbosity > 1) { + int chamberId = getChamberIdFromAlias(it.first.get_alias()); + LOG(info) << "PID = " << it.first.get_alias() << ". Value = " << mTRDDCSFedChamberStatus[chamberId]; + } + } + } + } + + std::map md; + md["responsible"] = "Leonardo Barreto"; + md["runNumber"] = std::to_string(mCurrentRunNumber); + // LB: set start timestamp 30 seconds before DPs are received + o2::calibration::Utils::prepareCCDBobjectInfo(mTRDDCSFedChamberStatus, mCcdbFedChamberStatusDPsInfo, + "TRD/Calib/DCSDPsFedChamberStatus", md, mFedChamberStatusStartTS - 30, + 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_CFGtag") != nullptr) { + if (it.second == true) { // we processed the DP at least 1x + retVal = true; + } + if (mVerbosity > 1) { + int chamberId = getChamberIdFromAlias(it.first.get_alias()); + LOG(info) << "PID = " << it.first.get_alias() << ". Value = " << mTRDDCSFedCFGtag[chamberId]; + } + } + } + } + + std::map md; + md["responsible"] = "Leonardo Barreto"; + md["runNumber"] = std::to_string(mCurrentRunNumber); + // LB: set start timestamp 30 seconds before DPs are received + o2::calibration::Utils::prepareCCDBobjectInfo(mTRDDCSFedCFGtag, mCcdbFedCFGtagDPsInfo, + "TRD/Calib/DCSDPsFedCFGtag", md, mFedCFGtagStartTS - 30, + mFedCFGtagStartTS + 3 * o2::ccdb::CcdbObjectInfo::DAY); + return retVal; } @@ -453,7 +611,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,11 +626,11 @@ 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) { - if (std::strstr(it.first.get_alias(), "trd_aliEnv") != nullptr) { + if (isAliasFromEnvDP(it.first.get_alias())) { it.second = false; } } @@ -485,11 +642,45 @@ 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 (std::strstr(it.first.get_alias(), "trd_run") != nullptr) { + if (type == o2::dcs::DPVAL_INT) { + if (std::strstr(it.first.get_alias(), "trd_fed_run") != nullptr) { + it.second = false; + } + } + } +} + +void DCSProcessor::clearFedChamberStatusDPsInfo() +{ + // mTRDDCSFedChamberStatus should not be cleared after upload giving alarm/warn logic + mFedChamberStatusStartTSSet = false; + mFedChamberStatusCompleteDPs = false; + mFirstRunEntryForFedChamberStatusUpdate = 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_INT) { + if (std::strstr(it.first.get_alias(), "trd_chamberStatus") != nullptr) { + it.second = false; + } + } + } +} + +void DCSProcessor::clearFedCFGtagDPsInfo() +{ + // mTRDDCSFedCFGtag should not be cleared after upload giving alarm/warn logic + mFedCFGtagStartTSSet = false; + mFedCFGtagCompleteDPs = false; + mFirstRunEntryForFedCFGtagUpdate = 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_STRING) { + if (std::strstr(it.first.get_alias(), "trd_CFGtag") != nullptr) { it.second = false; } } diff --git a/Detectors/TRD/calibration/workflow/TRDDCSDataProcessorSpec.h b/Detectors/TRD/calibration/workflow/TRDDCSDataProcessorSpec.h index 456d1af4328e2..551a9af93ef69 100644 --- a/Detectors/TRD/calibration/workflow/TRDDCSDataProcessorSpec.h +++ b/Detectors/TRD/calibration/workflow/TRDDCSDataProcessorSpec.h @@ -68,6 +68,7 @@ class TRDDCSDataProcessor : public o2::framework::Task mVoltagesDPsUpdateInterval = 600; } mMinUpdateIntervalU = ic.options().get("DPs-min-update-interval-voltages"); + // LB: Env DPs, only update every 30 min mEnvDPsUpdateInterval = ic.options().get("DPs-update-interval-env"); if (mEnvDPsUpdateInterval == 0) { LOG(error) << "TRD DPs update interval set to zero seconds --> changed to 1800s"; @@ -92,12 +93,12 @@ class TRDDCSDataProcessor : public o2::framework::Task aliasesFloat.insert(aliasesFloat.end(), {"trd_gasCO2", "trd_gasH2O", "trd_gasO2"}); aliasesFloat.insert(aliasesFloat.end(), {"trd_gaschromatographCO2", "trd_gaschromatographN2", "trd_gaschromatographXe"}); 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]"}); - aliasesInt.insert(aliasesInt.end(), {"trd_runNo", "trd_runType"}); - // aliasesInt.insert(aliasesInt.end(), {"trd_fedChamberStatus[00..539]"}); - // aliasesString.insert(aliasesString.end(), {"trd_fedCFGtag[00..539]"}); + aliasesFloat.insert(aliasesFloat.end(), {"CavernTemperature", "temperature_P2_external"}); + aliasesFloat.insert(aliasesFloat.end(), {"CavernAtmosPressure", "SurfaceAtmosPressure", "CavernAtmosPressure2"}); + aliasesFloat.insert(aliasesFloat.end(), {"UXC2Humidity"}); + aliasesInt.insert(aliasesInt.end(), {"trd_fed_runNo"}); + aliasesInt.insert(aliasesInt.end(), {"trd_chamberStatus[00..539]"}); + aliasesString.insert(aliasesString.end(), {"trd_CFGtag[00..539]"}); for (const auto& i : o2::dcs::expandAliases(aliasesFloat)) { vect.emplace_back(i, o2::dcs::DPVAL_DOUBLE); @@ -116,16 +117,47 @@ 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 522"; + } + + // LB: set minimum voltage variation to update Anode/DriftUmon + int utrigger = ic.options().get("DPs-voltage-variation-trigger"); + if (utrigger > 0) { + LOG(info) << "Setting voltage variation trigger of DPs to update Anode/DriftUMon to " << utrigger; + mProcessor->setUVariationTriggerForUpdate(utrigger); + } else { + LOG(info) << "Invalid voltage variation trigger of DPs to update Anode/DriftUMon to " << utrigger << ", using default value of 1 V"; + } + mProcessor->init(vect); mTimerGas = std::chrono::high_resolution_clock::now(); mTimerVoltages = mTimerGas; mTimerCurrents = mTimerGas; mTimerEnv = mTimerGas; + // LB: new DPs for Fed + mTimerFedChamberStatus = mTimerGas; + mTimerFedCFGtag = mTimerGas; mReportTiming = ic.options().get("report-timing") || verbosity > 0; } @@ -169,6 +201,15 @@ 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()); + } + if (mProcessor->shouldUpdateRun()) { sendDPsoutputRun(pc.outputs()); } @@ -185,6 +226,9 @@ class TRDDCSDataProcessor : public o2::framework::Task sendDPsoutputCurrents(ec.outputs()); sendDPsoutputEnv(ec.outputs()); sendDPsoutputRun(ec.outputs()); + // LB: new DPs for Fed + sendDPsoutputFedChamberStatus(ec.outputs()); + sendDPsoutputFedCFGtag(ec.outputs()); } private: @@ -194,11 +238,18 @@ 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 + std::chrono::high_resolution_clock::time_point mTimerFedChamberStatus; + std::chrono::high_resolution_clock::time_point mTimerFedCFGtag; + int64_t mGasDPsUpdateInterval; int64_t mVoltagesDPsUpdateInterval; int64_t mCurrentsDPsUpdateInterval; int64_t mMinUpdateIntervalU; int64_t mEnvDPsUpdateInterval; + // LB: new DPs for Fed + int64_t mFedChamberStatusDPsUpdateInterval; + int64_t mFedCFGtagDPsUpdateInterval; void sendDPsoutputVoltages(DataAllocator& output) { @@ -289,6 +340,47 @@ 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"; } } @@ -314,6 +406,12 @@ 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 + // 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"}); return DataProcessorSpec{ "trd-dcs-data-processor", @@ -328,7 +426,10 @@ 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-voltage-variation-trigger", VariantType::Int64, 1ll, {"Voltage variation trigger for upload of CCDB object"}}, + {"DPs-update-interval-gas", VariantType::Int64, 900ll, {"Interval (in s) after which to update the DPs CCDB entry for gas 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, 522, {"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..b2f2a47b13054 100644 --- a/Detectors/TRD/calibration/workflow/trd-dcs-sim-workflow.cxx +++ b/Detectors/TRD/calibration/workflow/trd-dcs-sim-workflow.cxx @@ -31,20 +31,21 @@ o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext co dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_hvDriftImon[00..539]", 0, 50.}); 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"}); + // FED parameters + dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_chamberStatus[00..539]", 1, 5}); + dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_CFGtag[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_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_runNo", 254, 255}); - dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_runType", 254, 255}); + // Env parameters (temperatures, pressures, humidity) + dphints.emplace_back(o2::dcs::test::DataPointHint{"CavernTemperature", 0, 100.}); + dphints.emplace_back(o2::dcs::test::DataPointHint{"temperature_P2_external", 0, 100.}); + dphints.emplace_back(o2::dcs::test::DataPointHint{"CavernAtmosPressure", 800, 1000.}); + dphints.emplace_back(o2::dcs::test::DataPointHint{"SurfaceAtmosPressure", 800, 1000.}); + dphints.emplace_back(o2::dcs::test::DataPointHint{"CavernAtmosPressure2", 800, 1000.}); + dphints.emplace_back(o2::dcs::test::DataPointHint{"UXC2Humidity", 0, 100.}); + + // Run parameters + dphints.emplace_back(o2::dcs::test::DataPointHint{"trd_fed_runNo", 254, 255}); return o2::framework::WorkflowSpec{o2::dcs::test::getDCSRandomDataGeneratorSpec(dphints, "TRD")}; }