From 3fa6589c6e4da53d094e0149ca57aea27ee2f38a Mon Sep 17 00:00:00 2001 From: mmusich Date: Wed, 19 Jun 2024 16:49:44 +0200 Subject: [PATCH 1/2] allow DetectorStateFilter to check on combinations of different partitions --- .../plugins/DetectorStateFilter.cc | 153 +++++++++++++++++- 1 file changed, 150 insertions(+), 3 deletions(-) diff --git a/DQM/TrackerCommon/plugins/DetectorStateFilter.cc b/DQM/TrackerCommon/plugins/DetectorStateFilter.cc index 04d0e6431243a..f43da5848b573 100644 --- a/DQM/TrackerCommon/plugins/DetectorStateFilter.cc +++ b/DQM/TrackerCommon/plugins/DetectorStateFilter.cc @@ -27,6 +27,7 @@ class DetectorStateFilter : public edm::stream::EDFilter<> { uint64_t nEvents_, nSelectedEvents_; bool detectorOn_; const std::string detectorType_; + const std::vector combinations_; // Vector of strings specifying accepted combinations const edm::EDGetTokenT dcsStatusLabel_; const edm::EDGetTokenT dcsRecordToken_; @@ -34,6 +35,8 @@ class DetectorStateFilter : public edm::stream::EDFilter<> { bool checkSubdet(const T& DCS, const int index); template bool checkDCS(const T& DCS); + template + bool checkDCSCombinations(const T& DCS, const std::vector& combinations); bool checkDCSStatus(const DcsStatusCollection& dcsStatus); bool checkDCSRecord(const DCSRecord& dcsRecord); @@ -44,7 +47,43 @@ class DetectorStateFilter : public edm::stream::EDFilter<> { // namespace DetStateFilter { enum parts { BPix = 0, FPix = 1, TIBTID = 2, TOB = 3, TECp = 4, TECm = 5, Invalid }; -} + + // Map from string to enum + parts partNameToEnum(const std::string& partName) { + if (partName == "BPix") + return BPix; + if (partName == "FPix") + return FPix; + if (partName == "TIBTID") + return TIBTID; + if (partName == "TOB") + return TOB; + if (partName == "TECp") + return TECp; + if (partName == "TECm") + return TECm; + return Invalid; + } + + // Single function to parse and split the vector of strings + std::vector> parseAndSplit(const std::vector& input, char delimiter) { + std::vector> parsedResult; + + for (const auto& str : input) { + std::vector splitStrings; + std::stringstream ss(str); + std::string item; + + while (std::getline(ss, item, delimiter)) { + splitStrings.push_back(item); + } + + parsedResult.push_back(splitStrings); + } + + return parsedResult; + } +} // namespace DetStateFilter // // -- Constructor @@ -52,6 +91,7 @@ namespace DetStateFilter { DetectorStateFilter::DetectorStateFilter(const edm::ParameterSet& pset) : verbose_(pset.getUntrackedParameter("DebugOn", false)), detectorType_(pset.getUntrackedParameter("DetectorType", "sistrip")), + combinations_(pset.getUntrackedParameter>("acceptedCombinations")), dcsStatusLabel_(consumes( pset.getUntrackedParameter("DcsStatusLabel", edm::InputTag("scalersRawToDigi")))), dcsRecordToken_(consumes( @@ -136,6 +176,104 @@ DetectorStateFilter::checkDCS(const T& DCS) return accepted; } +template +bool +//*********************************************************************// +DetectorStateFilter::checkDCSCombinations(const T& DCS, const std::vector& combinations) +//*********************************************************************// +{ + // check that the configuration is sound + if (detectorType_ != "pixel" && detectorType_ != "sistrip") { + throw cms::Exception("Wrong Configuration") + << "Stated DetectorType '" << detectorType_ + << "' is neither 'pixel' or 'sistrip', please check your configuration!"; + } + + bool accepted = false; + + // first get the combinations to check + std::vector> vec_to_check = DetStateFilter::parseAndSplit(combinations, '+'); + + if (verbose_) { + edm::LogInfo("DetectorStatusFilter") << "Debug Mode: Printing all possible combinations"; + for (const auto& combination : vec_to_check) { + std::string combinationStr; + for (const auto& part : combination) { + if (!combinationStr.empty()) { + combinationStr += " + "; + } + combinationStr += part; + } + edm::LogInfo("DetectorStatusFilter") << "Combination: " << combinationStr; + } + } + + // Initialize a vector to store the pass results + std::vector bitset(vec_to_check.size(), false); + for (size_t i = 0; i < vec_to_check.size(); ++i) { + const auto& subdetectors = vec_to_check[i]; + std::vector partsToCheck; + partsToCheck.reserve(subdetectors.size()); + + // fill vector of parts to check + for (const auto& sub : subdetectors) { + DetStateFilter::parts partEnum = DetStateFilter::partNameToEnum(sub); + if (partEnum == DetStateFilter::Invalid) { + throw cms::Exception("InvalidSubdetector", "Subdetector name '" + sub + "' is invalid."); + } + partsToCheck.push_back(partEnum); + } + + if (detectorType_ == "pixel") { + for (const auto& part : partsToCheck) { + if (part >= DetStateFilter::TIBTID) { + throw cms::Exception("InvalidSubdetector", "Detector type 'pixel' cannot have partitions TIBTID or larger"); + } + } + } else if (detectorType_ == "sistrip") { + for (const auto& part : partsToCheck) { + if (part < DetStateFilter::TIBTID) { + throw cms::Exception("InvalidSubdetector", + "Detector type 'strip' cannot have partitions smaller than TIBTID"); + } + } + } + + // Use std::all_of to compute the logical AND of checkSubdet(DCS, part) + bool passes = std::all_of(partsToCheck.begin(), partsToCheck.end(), [this, &DCS](DetStateFilter::parts part) { + return checkSubdet(DCS, part); + }); + + // Set the corresponding bit in bitset + bitset[i] = passes; + } + + // Set the value of accepted to the OR of all the bits in the bitset + accepted = std::any_of(bitset.begin(), bitset.end(), [](bool bit) { return bit; }); + + if (accepted) + nSelectedEvents_++; + + if (detectorType_ == "pixel") { + if (verbose_) { + edm::LogInfo("DetectorStatusFilter") + << " Total Events " << nEvents_ << " Selected Events " << nSelectedEvents_ << " DCS States : " + << " BPix " << checkSubdet(DCS, DetStateFilter::BPix) << " FPix " << checkSubdet(DCS, DetStateFilter::FPix) + << " Detector State " << accepted << std::endl; + } + } else if (detectorType_ == "sistrip") { + if (verbose_) { + edm::LogInfo("DetectorStatusFilter") + << " Total Events " << nEvents_ << " Selected Events " << nSelectedEvents_ << " DCS States : " + << " TEC- " << checkSubdet(DCS, DetStateFilter::TECm) << " TEC+ " << checkSubdet(DCS, DetStateFilter::TECp) + << " TIB/TID " << checkSubdet(DCS, DetStateFilter::TIBTID) << " TOB " << checkSubdet(DCS, DetStateFilter::TOB) + << " Detector States " << accepted << std::endl; + } + } + + return accepted; +} + //*********************************************************************// bool DetectorStateFilter::filter(edm::Event& evt, edm::EventSetup const& es) //*********************************************************************// @@ -150,10 +288,18 @@ bool DetectorStateFilter::filter(edm::Event& evt, edm::EventSetup const& es) if (dcsStatus.isValid() && !dcsStatus->empty()) { // if the old style DCS status is valid (Run1 + Run2) - detectorOn_ = checkDCS(*dcsStatus); + if (combinations_.empty()) { + detectorOn_ = checkDCS(*dcsStatus); + } else { + detectorOn_ = checkDCSCombinations(*dcsStatus, combinations_); + } } else if (dcsRecord.isValid()) { // in case of real data check for DCSRecord content (Run >=3) - detectorOn_ = checkDCS(*dcsRecord); + if (combinations_.empty()) { + detectorOn_ = checkDCS(*dcsRecord); + } else { + detectorOn_ = checkDCSCombinations(*dcsRecord, combinations_); + } } else { edm::LogError("DetectorStatusFilter") << "Error! can't get the products, neither DCSRecord, nor scalersRawToDigi: accept in any case!"; @@ -176,6 +322,7 @@ void DetectorStateFilter::fillDescriptions(edm::ConfigurationDescriptions& descr desc.setComment("filters on the HV status of the Tracker (either pixels or strips)"); desc.addUntracked("DebugOn", false)->setComment("activates debugging"); desc.addUntracked("DetectorType", "sistrip")->setComment("either strips or pixels"); + desc.addUntracked>("acceptedCombinations", {}); desc.addUntracked("DcsStatusLabel", edm::InputTag("scalersRawToDigi")) ->setComment("event data for DCS (Run2)"); desc.addUntracked("DCSRecordLabel", edm::InputTag("onlineMetaDataDigis")) From 772ffbe2089d931056a3dbb5b19a25886466a72a Mon Sep 17 00:00:00 2001 From: mmusich Date: Thu, 20 Jun 2024 11:13:40 +0200 Subject: [PATCH 2/2] update test_DetectorStateFilter to test DCS bits combinations --- .../test/test_DetectorStateFilter.sh | 45 +++++++++++++++++++ .../test/test_DetectorStateFilter_cfg.py | 9 +++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/DQM/TrackerCommon/test/test_DetectorStateFilter.sh b/DQM/TrackerCommon/test/test_DetectorStateFilter.sh index f0be7dd6ee6ca..024d4c6fdbf87 100755 --- a/DQM/TrackerCommon/test/test_DetectorStateFilter.sh +++ b/DQM/TrackerCommon/test/test_DetectorStateFilter.sh @@ -53,3 +53,48 @@ else echo "WARNING!!! The number of events in the strip filter file ($stripCounts) does NOT match expectations (10)." exit 1 fi + +# Now take as input file an express FEVT file from 2024 pp running, run 380032 +# https://cmsoms.cern.ch/cms/runs/lumisection?cms_run=380032 +# it has all partitions ON excepted TIBTID (which was affected by a bad setting of the DCS bit) + +INPUTFILE="/store/express/Run2024C/ExpressPhysics/FEVT/Express-v1/000/380/032/00000/26a18459-49a8-4e3c-849c-9b3e4c09712e.root" + +# test Strips +printf "TESTING Strips with all partitions...\n\n" +cmsRun ${SCRAM_TEST_PATH}/test_DetectorStateFilter_cfg.py maxEvents=10 isStrip=True inputFiles=$INPUTFILE outputFile=outStrips_run380032_all.root || die "Failure filtering on strips" $? + +printf "TESTING Strips with only TIBTID partitions...\n\n" +cmsRun ${SCRAM_TEST_PATH}/test_DetectorStateFilter_cfg.py maxEvents=10 isStrip=True inputFiles=$INPUTFILE testCombinations='TIBTID' outputFile=outStrips_run380032_TIBTID.root || die "Failure filtering on strips" $? + +printf "TESTING Strips with several OK partition combinations...\n\n" +cmsRun ${SCRAM_TEST_PATH}/test_DetectorStateFilter_cfg.py maxEvents=10 isStrip=True inputFiles=$INPUTFILE testCombinations='TOB+TECp+TECm','TIBTID+TECp+TECm','TECp+TECm' outputFile=outStrips_run380032_OKCombos.root || die "Failure filtering on strips" $? + +# count events +allPartsCounts=`countEvents outStrips_run380032_all_numEvent10.root` +onlyTIBTIDCounts=`countEvents outStrips_run380032_TIBTID_numEvent10.root` +combinationCounts=`countEvents outStrips_run380032_OKCombos_numEvent10.root` + +if [[ $allPartsCounts -eq 0 ]] +then + echo "The number of events in the all partitions filter file matches expectations ($allPartsCounts)." +else + echo "WARNING!!! The number of events in the pixel filter file ($allPartsCounts) does NOT match expectations (0)." + exit 1 +fi + +if [[ $onlyTIBTIDCounts -eq 0 ]] +then + echo "The number of events in the all partitions filter file matches expectations ($onlyTIBTIDCounts)." +else + echo "WARNING!!! The number of events in the pixel filter file ($onlyTIBTIDCounts) does NOT match expectations (0)." + exit 1 +fi + +if [[ $combinationCounts -eq 10 ]] +then + echo "The number of events in the all partitions filter file matches expectations ($combinationCounts)." +else + echo "WARNING!!! The number of events in the pixel filter file ($combinationCounts) does NOT match expectations (10)." + exit 1 +fi diff --git a/DQM/TrackerCommon/test/test_DetectorStateFilter_cfg.py b/DQM/TrackerCommon/test/test_DetectorStateFilter_cfg.py index 9476c52dc49c1..be52004108409 100644 --- a/DQM/TrackerCommon/test/test_DetectorStateFilter_cfg.py +++ b/DQM/TrackerCommon/test/test_DetectorStateFilter_cfg.py @@ -16,6 +16,12 @@ VarParsing.VarParsing.multiplicity.singleton, # singleton or list VarParsing.VarParsing.varType.bool, # string, int, or float "true filters on Strips, false filters on Pixels") +# Register the option as a list of strings +options.register('testCombinations', + '', # Default value as an empty string + VarParsing.VarParsing.multiplicity.list, # Allows multiple values + VarParsing.VarParsing.varType.string, # Specifies that the values are strings + "List of combinations of partitions to test") options.parseArguments() # import of standard configurations @@ -71,7 +77,8 @@ DebugOn = True) process.SiStripFilter = detectorStateFilter.clone(DetectorType = 'sistrip', - DebugOn = True) + DebugOn = True, + acceptedCombinations = options.testCombinations) #process.analysis_step = cms.Path(process.detectorStateFilter) if(options.isStrip) :