-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #45975 from amecca/improve-PixelBarycentre
Porting the Pixel Barycentre tool in the All-in-One framework
- Loading branch information
Showing
13 changed files
with
503 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Pixel Barycentre Validation | ||
Currently only the `single` type of job is implemented in the All-in-One Tool, but the execution of the plotting script `plotBaryCentre_VS_BeamSpot.py` could be added in the future as a `trend` job. | ||
|
||
## Extraction from TrackerAlignmentRcd - PixelBarycentreAnalyzer_cfg.py | ||
This config runs `PixelBaryCentreAnalyzer` on an empty source, after configuring the GlobalTag and additional conditions for a given alignment. | ||
The following parameters are expected/accepted in the json/yaml configuration file: | ||
``` | ||
validations: | ||
PixBary: | ||
single: | ||
<job_name>: | ||
<options> | ||
``` | ||
|
||
The following options are understood: | ||
|
||
Variable | Default value | Explanation/Options | ||
-------- | ------------- | -------------------- | ||
firstRun | 290550 | The first run to process (inclusive) | ||
lastRun | 325175 | The last run to process (inclusive) | ||
lumisPerRun | 1 | The number of LumiSections tested for a change in the TrackerAlignmentRcd in each run | ||
alignments | None | List of alignments for which this validation is run |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,8 +7,10 @@ | |
* Python script plotBaryCentre_VS_BeamSpot.py under script dir is used to plot barycentres from alignment constants used in Prompt-Reco, End-of-Year Rereco and so-called Run-2 (Ultra)Legacy Rereco. Options of the plotting script can be found from the helper in the script. | ||
* | ||
* $Date: 2021/01/05 $ | ||
* $Revision: 1.0 $ | ||
* $Last Modified: 2024/09/23 $ | ||
* $Revision: 1.1 $ | ||
* \author Tongguang Cheng - Beihang University <[email protected]> | ||
* \author Alberto Mecca - Torino University <[email protected]> | ||
* | ||
*/ | ||
|
||
|
@@ -246,32 +248,32 @@ void PixelBaryCentreAnalyzer::analyze(const edm::Event& iEvent, const edm::Event | |
|
||
phase_ = -1; | ||
|
||
const TrackerGeometry* tkGeo = &iSetup.getData(trackerGeometryToken_); | ||
const TrackerTopology* tkTopo = &iSetup.getData(trackerTopologyToken_); | ||
const TrackerGeometry& tkGeom = iSetup.getData(trackerGeometryToken_); | ||
const TrackerTopology& tkTopo = iSetup.getData(trackerTopologyToken_); | ||
|
||
if (tkGeo->isThere(GeomDetEnumerators::PixelBarrel) && tkGeo->isThere(GeomDetEnumerators::PixelEndcap)) { | ||
if (tkGeom.isThere(GeomDetEnumerators::PixelBarrel) && tkGeom.isThere(GeomDetEnumerators::PixelEndcap)) { | ||
phase_ = 0; | ||
} else if (tkGeo->isThere(GeomDetEnumerators::P1PXB) && tkGeo->isThere(GeomDetEnumerators::P1PXEC)) { | ||
} else if (tkGeom.isThere(GeomDetEnumerators::P1PXB) && tkGeom.isThere(GeomDetEnumerators::P1PXEC)) { | ||
phase_ = 1; | ||
} | ||
|
||
// pixel quality | ||
const SiPixelQuality* badPixelInfo = &iSetup.getData(siPixelQualityToken_); | ||
const SiPixelQuality& badPixelInfo = iSetup.getData(siPixelQualityToken_); | ||
|
||
// Tracker global position | ||
const AlignTransform glbCoord = align::DetectorGlobalPosition(iSetup.getData(gprToken_), DetId(DetId::Tracker)); | ||
|
||
// Convert AlignTransform::Translation to GlobalVector using the appropriate constructor | ||
GlobalVector globalTkPosition(glbCoord.translation().x(), glbCoord.translation().y(), glbCoord.translation().z()); | ||
const Alignments& globalAlignments = iSetup.getData(gprToken_); | ||
const AlignTransform& globalCoordinates = align::DetectorGlobalPosition(globalAlignments, DetId(DetId::Tracker)); | ||
GlobalVector globalTkPosition( | ||
globalCoordinates.translation().x(), globalCoordinates.translation().y(), globalCoordinates.translation().z()); | ||
|
||
// loop over bclabels | ||
for (const auto& label : bcLabels_) { | ||
// init tree content | ||
PixelBaryCentreAnalyzer::initBC(); | ||
|
||
// Get TkAlign from EventSetup: | ||
const Alignments* alignments = &iSetup.getData(tkAlignTokens_[label]); | ||
std::vector<AlignTransform> tkAlignments = alignments->m_align; | ||
const Alignments& alignments = iSetup.getData(tkAlignTokens_[label]); | ||
std::vector<AlignTransform> tkAlignments = alignments.m_align; | ||
|
||
// PIX | ||
GlobalVector barycentre_PIX(0.0, 0.0, 0.0); | ||
|
@@ -295,7 +297,7 @@ void PixelBaryCentreAnalyzer::analyze(const edm::Event& iEvent, const edm::Event | |
//DetId | ||
const DetId& detId = DetId(ali.rawId()); | ||
// remove bad module | ||
if (usePixelQuality_ && badPixelInfo->IsModuleBad(detId)) | ||
if (usePixelQuality_ && badPixelInfo.IsModuleBad(detId)) | ||
continue; | ||
|
||
// alignment for a given module | ||
|
@@ -308,8 +310,8 @@ void PixelBaryCentreAnalyzer::analyze(const edm::Event& iEvent, const edm::Event | |
barycentre_BPIX += ali_translation; | ||
barycentre_PIX += ali_translation; | ||
|
||
int layer = tkTopo->pxbLayer(detId); | ||
int ladder = tkTopo->pxbLadder(detId); | ||
int layer = tkTopo.pxbLayer(detId); | ||
int ladder = tkTopo.pxbLadder(detId); | ||
nmodules_bpix[layer][ladder] += 1; | ||
barycentre_bpix[layer][ladder] += ali_translation; | ||
|
||
|
@@ -321,16 +323,16 @@ void PixelBaryCentreAnalyzer::analyze(const edm::Event& iEvent, const edm::Event | |
barycentre_FPIX += ali_translation; | ||
barycentre_PIX += ali_translation; | ||
|
||
int disk = tkTopo->pxfDisk(detId); | ||
int quadrant = PixelEndcapName(detId, tkTopo, phase_).halfCylinder(); | ||
int disk = tkTopo.pxfDisk(detId); | ||
int quadrant = PixelEndcapName(detId, &tkTopo, phase_).halfCylinder(); | ||
if (quadrant < 3) | ||
disk *= -1; | ||
|
||
int ring = -9999; | ||
if (phase_ == 0) { | ||
ring = 1 + (tkTopo->pxfPanel(detId) + tkTopo->pxfModule(detId.rawId()) > 3); | ||
ring = 1 + (tkTopo.pxfPanel(detId) + tkTopo.pxfModule(detId.rawId()) > 3); | ||
} else if (phase_ == 1) { | ||
ring = PixelEndcapName(detId, tkTopo, phase_).ringName(); | ||
ring = PixelEndcapName(detId, &tkTopo, phase_).ringName(); | ||
} | ||
|
||
nmodules_fpix[disk][ring] += 1; | ||
|
64 changes: 64 additions & 0 deletions
64
Alignment/OfflineValidation/python/TkAlAllInOneTool/PixBary.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import os | ||
import copy | ||
|
||
_validationName = "PixBary" | ||
|
||
def PixBary(config, validationDir, verbose=False): | ||
##List with all jobs | ||
jobs = [] | ||
|
||
##Dictionary of lists of all IOVs (can be different per each single job) | ||
IOVs = {} | ||
|
||
##Start with single jobs | ||
jobType = "single" | ||
|
||
##Check that a job is defined | ||
if not jobType in config["validations"][_validationName]: | ||
raise LookupError("No '%s' key word in config for %s" %(jobType, _validationName)) | ||
|
||
##Loop over all merge jobs/IOVs which are requested | ||
for jobName, jobConfig in config["validations"][_validationName][jobType].items(): | ||
IOV_list = get_IOVs(jobConfig) # The PixelBarycentre automatically detects IOV changes in the payloads. This list is used to specify the run range(s) to analyze | ||
if(verbose): | ||
print('job: %s IOV_list: %s', jobName, IOV_list) | ||
IOVs[jobName] = IOV_list | ||
|
||
##Loop over IOVs (ranges of runs, in this case) | ||
for runRange in IOV_list: | ||
IOV = '-'.join(str(i) for i in runRange) | ||
|
||
for alignment, alignmentConfig in config["alignments"].items(): | ||
##Work directory for each IOV | ||
workDir = os.path.join(validationDir, _validationName, jobType, jobName, alignment, IOV) | ||
|
||
##Write local config | ||
local = {} | ||
local["output"] = os.path.join(config["LFS"], config["name"], _validationName, jobType, alignment, jobName, IOV) | ||
local["alignment"] = copy.deepcopy(alignmentConfig) | ||
local["alignment"]["label"] = alignment | ||
local["validation"] = copy.deepcopy(jobConfig) | ||
local["validation"].pop("alignments") | ||
local["validation"]["IOV"] = IOV | ||
if "dataset" in local["validation"]: | ||
local["validation"]["dataset"] = local["validation"]["dataset"].format(IOV) | ||
if "goodlumi" in local["validation"]: | ||
local["validation"]["goodlumi"] = local["validation"]["goodlumi"].format(IOV) | ||
|
||
##Write job info | ||
job = { | ||
"name": "{}_{}_{}_{}_{}".format(_validationName, alignment, jobType, jobName, IOV), | ||
"dir": workDir, | ||
"exe": "cmsRun", | ||
"cms-config": "{}/src/Alignment/OfflineValidation/python/TkAlAllInOneTool/PixelBaryCentreAnalyzer_cfg.py".format(os.environ["CMSSW_BASE"]), | ||
"run-mode": "Condor", | ||
"dependencies": [], | ||
"config": local, | ||
} | ||
|
||
jobs.append(job) | ||
|
||
return jobs | ||
|
||
def get_IOVs(jobConfig): | ||
return [[jobConfig['firstRun'], jobConfig['lastRun']]] |
211 changes: 211 additions & 0 deletions
211
Alignment/OfflineValidation/python/TkAlAllInOneTool/PixelBaryCentreAnalyzer_cfg.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
import FWCore.ParameterSet.Config as cms | ||
import os | ||
import json | ||
|
||
process = cms.Process("READ") | ||
|
||
# import of standard configurations | ||
process.load('Configuration.StandardSequences.Services_cff') | ||
process.load('Configuration.EventContent.EventContent_cff') | ||
process.load('Configuration.StandardSequences.GeometryRecoDB_cff') | ||
process.load('Configuration.StandardSequences.MagneticField_AutoFromDBCurrent_cff') | ||
process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') | ||
|
||
import FWCore.ParameterSet.VarParsing as VarParsing | ||
from Configuration.AlCa.GlobalTag import GlobalTag | ||
|
||
options = VarParsing.VarParsing() | ||
options.register('lumisPerRun', | ||
1, | ||
VarParsing.VarParsing.multiplicity.singleton, | ||
VarParsing.VarParsing.varType.int, | ||
"the number of lumis to be processed per-run.") | ||
options.register('firstRun', | ||
290550, | ||
VarParsing.VarParsing.multiplicity.singleton, | ||
VarParsing.VarParsing.varType.int, | ||
"the first run number be processed") | ||
options.register('lastRun', | ||
325175, | ||
VarParsing.VarParsing.multiplicity.singleton, | ||
VarParsing.VarParsing.varType.int, | ||
"the run number to stop at") | ||
options.register('config', | ||
default = None, | ||
mult = VarParsing.VarParsing.multiplicity.singleton, | ||
mytype = VarParsing.VarParsing.varType.string, | ||
info = 'JSON config with information about the GT, Alignments, etc.') | ||
options.register('unitTest', | ||
False, # default value | ||
VarParsing.VarParsing.multiplicity.singleton, # singleton or list | ||
VarParsing.VarParsing.varType.bool, # string, int, or float | ||
"is it a unit test?") | ||
|
||
defaultFirstRun = options.firstRun | ||
defaultLastRun = options.lastRun | ||
defaultLumisPerRun = options.lumisPerRun | ||
|
||
options.parseArguments() | ||
|
||
if(options.config is None): | ||
configuration = { | ||
"alignments": { | ||
"prompt": { | ||
"globaltag": "140X_dataRun3_Prompt_v4", | ||
"conditions": {"TrackerAlignmentRcd": {"tag":"TrackerAlignment_PCL_byRun_v2_express"}} | ||
}, | ||
"EOY": { | ||
"conditions": {"TrackerAlignmentRcd": {"tag":"TrackerAlignment_v24_offline"}} | ||
}, | ||
"rereco": { | ||
"conditions": {"TrackerAlignmentRcd": {"tag":"TrackerAlignment_v29_offline"}} | ||
} | ||
}, | ||
"validation": {} | ||
} | ||
else: | ||
# Load configuration from file | ||
with open(options.config) as f: | ||
configuration = json.load(f) | ||
|
||
# The priority for the options is: | ||
# 1. Value specified on command line | ||
# 2. Value in the config | ||
# 3. Default value in the parser | ||
if(options.firstRun != defaultFirstRun): | ||
firstRun = options.firstRun | ||
else: | ||
firstRun = configuration["validation"].get('firstRun', defaultFirstRun) | ||
|
||
if(options.lastRun != defaultLastRun): | ||
lastRun = options.lastRun | ||
else: | ||
lastRun = configuration["validation"].get('lastRun', defaultLastRun) | ||
|
||
if(options.lumisPerRun != defaultLumisPerRun): | ||
lumisPerRun = options.lumisPerRun | ||
else: | ||
lumisPerRun = configuration["validation"].get('lumisPerRun', defaultLumisPerRun) | ||
|
||
process.load("FWCore.MessageService.MessageLogger_cfi") | ||
|
||
# Test that the configuration is complete | ||
if(lastRun < firstRun): | ||
raise ValueError("The last run is smaller than the first") | ||
|
||
process.MessageLogger.cerr.FwkReport.reportEvery = lumisPerRun*1000 # do not clog output with I/O | ||
|
||
if options.unitTest: | ||
numberOfRuns = 10 | ||
else: | ||
numberOfRuns = lastRun - firstRun + 1 | ||
|
||
print("INFO: Runs: {:d} - {:d} --> number of runs: {:d}".format(firstRun, lastRun, numberOfRuns)) | ||
|
||
process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(options.lumisPerRun*numberOfRuns) ) | ||
|
||
#################################################################### | ||
# Empty source | ||
#################################################################### | ||
#import FWCore.PythonUtilities.LumiList as LumiList | ||
#DCSJson='/afs/cern.ch/cms/CAF/CMSCOMM/COMM_DQM/certification/Collisions16/13TeV/DCSOnly/json_DCSONLY.txt' | ||
|
||
process.source = cms.Source("EmptySource", | ||
firstRun = cms.untracked.uint32(firstRun), | ||
firstLuminosityBlock = cms.untracked.uint32(1), # probe one LS after the other | ||
numberEventsInLuminosityBlock = cms.untracked.uint32(1), # probe one event per LS | ||
numberEventsInRun = cms.untracked.uint32(lumisPerRun), # a number of events > the number of LS possible in a real run (5000 s ~ 32 h) | ||
) | ||
|
||
#################################################################### | ||
# Load and configure analyzer | ||
#################################################################### | ||
bcLabels_ = cms.untracked.vstring("") | ||
bsLabels_ = cms.untracked.vstring("") | ||
|
||
alignments = configuration.get('alignments', None) # NOTE: aligments is plural | ||
if alignments is None: | ||
align = configuration['alignment'] # NOTE: alignment is singular | ||
label = configuration['alignment'].get('label', align['title'].split()[0]) | ||
alignments = {label: align} | ||
|
||
for label, align in alignments.items(): | ||
if(align.get('globaltag')): | ||
if(len(process.GlobalTag.globaltag.value()) > 0): | ||
if(process.GlobalTag.globaltag.value() != align['globaltag']): | ||
print('ERROR: another GT has already been specified: "{}". Ignoring GT "{}" from alignment "{}"'.format( | ||
process.GlobalTag.globaltag.value(), align['globaltag'], label)) | ||
else: | ||
# Assign this GlobalTag to the process | ||
process.GlobalTag = GlobalTag(process.GlobalTag, align['globaltag']) | ||
print('INFO: GlobalTag:', process.GlobalTag.globaltag.value()) | ||
|
||
conditions = align.get('conditions') | ||
if(conditions is None): | ||
print('INFO: No conditions specified for alignment "{}": skipping'.format(label)) | ||
continue | ||
|
||
bcLabels_.append(label) | ||
print(f'TrackerAlignment: {label=} {align=}') | ||
|
||
for record, condition in conditions.items(): | ||
condition.setdefault('connect', 'frontier://FrontierProd/CMS_CONDITIONS') | ||
if (record == 'TrackerAlignmentRcd'): | ||
condition.setdefault('tag', 'Alignments') | ||
elif(record == 'TrackerSurfaceDeformationRcd'): | ||
condition.setdefault('tag', 'Deformations') | ||
elif(record == 'TrackerAlignmentErrorsExtendedRcd'): # Errors should not affect the barycentre | ||
condition.setdefault('tag', 'AlignmentErrors') | ||
|
||
process.GlobalTag.toGet.append( | ||
cms.PSet( | ||
record = cms.string(record), | ||
label = cms.untracked.string(label), | ||
tag = cms.string(condition['tag']), | ||
connect = cms.string(condition['connect']) | ||
) | ||
) | ||
|
||
|
||
for label, beamspot in configuration['validation'].get("beamspots", {}).items() : | ||
bsLabels_.append(label) | ||
print(f'BeamSpot : {label=} {beamspot=}') | ||
|
||
process.GlobalTag.toGet.append( | ||
cms.PSet( | ||
record = cms.string("BeamSpotObjectsRcd"), | ||
label = cms.untracked.string(label), | ||
tag = cms.string(beamspot["tag"]), | ||
connect = cms.string(beamspot.get("connect", "frontier://FrontierProd/CMS_CONDITIONS")) | ||
) | ||
) | ||
|
||
|
||
from Alignment.OfflineValidation.pixelBaryCentreAnalyzer_cfi import pixelBaryCentreAnalyzer as _pixelBaryCentreAnalyzer | ||
|
||
process.PixelBaryCentreAnalyzer = _pixelBaryCentreAnalyzer.clone( | ||
usePixelQuality = False, | ||
tkAlignLabels = bcLabels_, | ||
beamSpotLabels = bsLabels_ | ||
) | ||
|
||
process.PixelBaryCentreAnalyzerWithPixelQuality = _pixelBaryCentreAnalyzer.clone( | ||
usePixelQuality = True, | ||
tkAlignLabels = bcLabels_, | ||
beamSpotLabels = bsLabels_ | ||
) | ||
|
||
#################################################################### | ||
# Output file | ||
#################################################################### | ||
outfile = os.path.join(configuration.get("output", os.getcwd()), 'PixelBaryCentre.root') | ||
|
||
process.TFileService = cms.Service("TFileService", | ||
fileName=cms.string(outfile) | ||
) | ||
print('INFO: output in', outfile) | ||
|
||
# Put module in path: | ||
process.p = cms.Path(process.PixelBaryCentreAnalyzer | ||
#*process.PixelBaryCentreAnalyzerWithPixelQuality | ||
) |
Oops, something went wrong.