diff --git a/CalibTracker/SiStripLorentzAngle/interface/SiStripLorentzAngleCalibrationHelpers.h b/CalibTracker/SiStripLorentzAngle/interface/SiStripLorentzAngleCalibrationHelpers.h index 9fc48f7040bca..8ca1d0f498b99 100644 --- a/CalibTracker/SiStripLorentzAngle/interface/SiStripLorentzAngleCalibrationHelpers.h +++ b/CalibTracker/SiStripLorentzAngle/interface/SiStripLorentzAngleCalibrationHelpers.h @@ -5,6 +5,7 @@ #include "CondFormats/SiStripObjects/interface/SiStripLatency.h" #include "DataFormats/SiStripDetId/interface/SiStripDetId.h" #include "DataFormats/TrackerCommon/interface/TrackerTopology.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" // system includes #include @@ -16,6 +17,19 @@ namespace siStripLACalibration { + /** + * @brief Generates a module location type string based on the detector ID and topology information. + * + * Given a module ID and the corresponding TrackerTopology, this function constructs a module + * location type string in the format "subdet_LlayerType", where subdet is the subdetector name (TIB or TOB), + * layer is the layer number, and Type is 'a' for axial or 's' for stereo. + * + * @param mod The module ID. + * @param tTopo Pointer to the TrackerTopology object providing information about the detector. + * @return A module location type string. + */ + + //_____________________________________________________________________ inline std::string moduleLocationType(const uint32_t& mod, const TrackerTopology* tTopo) { const SiStripDetId detid(mod); std::string subdet = ""; @@ -36,6 +50,50 @@ namespace siStripLACalibration { return d_l_t; } + /** + * @brief Process a string in the format "subdet_LlayerType" and compute values. + * + * This function takes a string in the format "subdet_LlayerType" and parses it to extract + * information about the layer and type. It then computes and returns a std::pair where + * the first element is 1 if type is "a" and 2 if type is "s", + * and the second element is the processed value of layer if subdet is "TIB" or layer + 4 if subdet is "TOB". + * + * @param locType The input string in the format "subdet_LlayerType". + * @return A std::pair containing the processed values. If the input format is invalid, + * the pair (-1, -1) is returned. + * + * @example + * std::string d_l_t = "TIB_L3a"; + * std::pair result = processString(d_l_t); + * // The result will contain processed values based on the input. + */ + + //_____________________________________________________________________ + inline std::pair locationTypeIndex(const std::string& locType) { + // Assuming input format is "subdet_LlayerType" + // Example: "TIB_L3a" + + std::string subdet, layerType; + int layer; + + // Parse the input string + if (sscanf(locType.c_str(), "%3s_L%d%1[a-zA-Z]", &subdet[0], &layer, &layerType[0]) == 3) { + // Process subdet and layerType to compute the values + LogTrace("locationTypeIndex") << "subdet " << &subdet[0] << ") layer " << layer << " type " << layerType[0] + << std::endl; + + int firstElement = (layerType[0] == 'a') ? 1 : 2; + int secondElement = (std::string(&subdet[0]) == "TIB") ? layer : (layer + 4); + + return std::make_pair(firstElement, secondElement); + } else { + // Handle invalid input format + // FIXME use MessageLogger + std::cerr << "Invalid input format: " << locType << std::endl; + return std::make_pair(-1, -1); // Indicates error + } + } + // SiStripLatency::singleReadOutMode() returns // 1: all in peak, 0: all in deco, -1: mixed state enum { k_DeconvolutionMode = 0, k_PeakMode = 1 }; diff --git a/CalibTracker/SiStripLorentzAngle/interface/SiStripLorentzAngleCalibrationStruct.h b/CalibTracker/SiStripLorentzAngle/interface/SiStripLorentzAngleCalibrationStruct.h index bb99e599409c2..a7bbc95a872b5 100644 --- a/CalibTracker/SiStripLorentzAngle/interface/SiStripLorentzAngleCalibrationStruct.h +++ b/CalibTracker/SiStripLorentzAngle/interface/SiStripLorentzAngleCalibrationStruct.h @@ -44,6 +44,9 @@ struct SiStripLorentzAngleCalibrationHistograms { std::map hp_; + dqm::reco::MonitorElement* h2_byLayerLA_; + dqm::reco::MonitorElement* h2_byLayerDiff_; + // info std::map nlayers_; std::vector modtypes_; diff --git a/CalibTracker/SiStripLorentzAngle/plugins/SiStripLorentzAnglePCLHarvester.cc b/CalibTracker/SiStripLorentzAngle/plugins/SiStripLorentzAnglePCLHarvester.cc index 8e37f1995285c..36dd0357bc864 100644 --- a/CalibTracker/SiStripLorentzAngle/plugins/SiStripLorentzAnglePCLHarvester.cc +++ b/CalibTracker/SiStripLorentzAngle/plugins/SiStripLorentzAnglePCLHarvester.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -78,7 +79,6 @@ class SiStripLorentzAnglePCLHarvester : public DQMEDHarvester { static constexpr float teslaToInverseGeV_ = 2.99792458e-3f; std::pair theFitRange_{0., 0.}; - SiStripLorentzAngleCalibrationHistograms hists_; const SiStripLorentzAngle* currentLorentzAngle_; std::unique_ptr theTrackerTopology_; }; @@ -222,6 +222,54 @@ void SiStripLorentzAnglePCLHarvester::dqmEndJob(DQMStore::IBooker& iBooker, DQMS } } + // book the summary output histograms + iBooker.setCurrentFolder(fmt::format("{}Harvesting/LorentzAngleMaps", dqmDir_)); + + // Define a lambda function to extract the second element and add it to the accumulator + auto sumValues = [](int accumulator, const std::pair& element) { + return accumulator + element.second; + }; + + // Use std::accumulate to sum the values + int totalLayers = std::accumulate(iHists_.nlayers_.begin(), iHists_.nlayers_.end(), 0, sumValues); + + // Lambda expression to set bin labels for a TH2F histogram + auto setHistoLabels = [](TH2F* histogram, const std::map& nlayers) { + // Set common options + histogram->SetOption("colz1"); // don't fill empty bins + histogram->SetStats(false); + histogram->GetYaxis()->SetLabelSize(0.05); + histogram->GetXaxis()->SetLabelSize(0.05); + + // Set bin labels for the X-axis + histogram->GetXaxis()->SetBinLabel(1, "r-#phi"); + histogram->GetXaxis()->SetBinLabel(2, "stereo"); + + // Set bin labels for the Y-axis + int binCounter = 1; + for (const auto& subdet : {"TIB", "TOB"}) { + for (int layer = 1; layer <= nlayers.at(subdet); ++layer) { + std::string label = Form("%s L%d", subdet, layer); + histogram->GetYaxis()->SetBinLabel(binCounter++, label.c_str()); + } + } + histogram->GetXaxis()->LabelsOption("h"); + }; + + std::string d_name = "h2_byLayerSiStripLA"; + std::string d_text = "SiStrip tan#theta_{LA}/B;module type (r-#phi/stereo);layer number;tan#theta_{LA}/B [1/T]"; + iHists_.h2_byLayerLA_ = + iBooker.book2D(d_name.c_str(), d_text.c_str(), 2, -0.5, 1.5, totalLayers, -0.5, totalLayers - 0.5); + + setHistoLabels(iHists_.h2_byLayerLA_->getTH2F(), iHists_.nlayers_); + + d_name = "h2_byLayerSiStripLADiff"; + d_text = "SiStrip #Delta#mu_{H}/#mu_{H};module type (r-#phi/stereo);ladder number;#Delta#mu_{H}/#mu_{H} [%%]"; + iHists_.h2_byLayerDiff_ = + iBooker.book2D(d_name.c_str(), d_text.c_str(), 2, -0.5, 1.5, totalLayers, -0.5, totalLayers - 0.5); + + setHistoLabels(iHists_.h2_byLayerDiff_->getTH2F(), iHists_.nlayers_); + // prepare the profiles for (const auto& ME : iHists_.h2_) { if (!ME.second) @@ -291,29 +339,84 @@ void SiStripLorentzAnglePCLHarvester::dqmEndJob(DQMStore::IBooker& iBooker, DQMS // now prepare the output LA std::shared_ptr OutLorentzAngle = std::make_shared(); + bool isPayloadChanged{false}; + std::vector> treatedIndices; for (const auto& loc : iHists_.moduleLocationType_) { if (debug_) { edm::LogInfo(moduleDescription().moduleName()) << "modId: " << loc.first << " " << loc.second; } - if (!(loc.second).empty()) { + if (!(loc.second).empty() && theMagField_ != 0.f) { OutLorentzAngle->putLorentzAngle(loc.first, std::abs(LAMap_[loc.second].first / theMagField_)); } else { OutLorentzAngle->putLorentzAngle(loc.first, iHists_.la_db_[loc.first]); } - } - edm::Service mydbservice; - if (mydbservice.isAvailable()) { - try { - mydbservice->writeOneIOV(*OutLorentzAngle, mydbservice->currentTime(), recordName_); - } catch (const cond::Exception& er) { - edm::LogError("SiStripLorentzAngleDB") << er.what(); - } catch (const std::exception& er) { - edm::LogError("SiStripLorentzAngleDB") << "caught std::exception " << er.what(); + // if the location is not assigned (e.g. TID or TEC) continue + if ((loc.second).empty()) { + continue; + } + + const auto& index2D = siStripLACalibration::locationTypeIndex(loc.second); + LogDebug("SiStripLorentzAnglePCLHarvester") + << loc.first << " : " << loc.second << " index: " << index2D.first << "-" << index2D.second << std::endl; + + // check if the location exists, otherwise throw! + if (index2D != std::make_pair(-1, -1)) { + // Check if index2D is in treatedIndices + // Do not fill the control plots more than necessary (i.e. 1 entry per "partition") + auto it = std::find(treatedIndices.begin(), treatedIndices.end(), index2D); + if (it == treatedIndices.end()) { + // control plots + LogTrace("SiStripLorentzAnglePCLHarvester") << "accepted " << loc.first << " : " << loc.second << " bin (" + << index2D.first << "," << index2D.second << ")"; + + const auto& outputLA = OutLorentzAngle->getLorentzAngle(loc.first); + const auto& inputLA = currentLorentzAngle_->getLorentzAngle(loc.first); + + LogTrace("SiStripLorentzAnglePCLHarvester") << "inputLA: " << inputLA << " outputLA: " << outputLA; + + iHists_.h2_byLayerLA_->setBinContent(index2D.first, index2D.second, outputLA); + + float deltaMuHoverMuH = (inputLA != 0.f) ? (inputLA - outputLA) / inputLA : 0.f; + iHists_.h2_byLayerDiff_->setBinContent(index2D.first, index2D.second, deltaMuHoverMuH * 100.f); + treatedIndices.emplace_back(index2D); + + // Check if the delta is different from zero + // if none of the locations has a non-zero diff + // will not write out the payload. + if (deltaMuHoverMuH != 0.f) { + isPayloadChanged = true; + LogDebug("SiStripLorentzAnglePCLHarvester") + << "accepted " << loc.first << " : " << loc.second << " bin (" << index2D.first << "," << index2D.second + << ") " << deltaMuHoverMuH; + } + + } // if the index has not been treated already + } else { + throw cms::Exception("SiStripLorentzAnglePCLHarvester") + << "Trying to fill an inexistent module location from " << loc.second << "!"; + } // + } // ends loop on location types + + if (isPayloadChanged) { + // fill the DB object record + edm::Service mydbservice; + if (mydbservice.isAvailable()) { + try { + mydbservice->writeOneIOV(*OutLorentzAngle, mydbservice->currentTime(), recordName_); + } catch (const cond::Exception& er) { + edm::LogError("SiStripLorentzAngleDB") << er.what(); + } catch (const std::exception& er) { + edm::LogError("SiStripLorentzAngleDB") << "caught std::exception " << er.what(); + } + } else { + edm::LogError("SiStripLorentzAngleDB") << "Service is unavailable!"; } } else { - edm::LogError("SiStripLorentzAngleDB") << "Service is unavailable"; + edm::LogPrint("SiStripLorentzAngleDB") + << "****** WARNING ******\n* " << __PRETTY_FUNCTION__ + << "\n* There is no new valid measurement to append!\n* Will NOT update the DB!\n*********************"; } }