CMS 3D CMS Logo

validation.py
Go to the documentation of this file.
1 import os
2 import re
3 import sys
4 import shutil
5 import subprocess
6 
7 import ROOT
8 ROOT.gROOT.SetBatch(True)
9 ROOT.PyConfig.IgnoreCommandLineOptions = True
10 
11 import plotting
12 import html
13 
14 # Mapping from releases to GlobalTags
15 _globalTags = {
16  "CMSSW_6_2_0": {"default": "PRE_ST62_V8"},
17  "CMSSW_6_2_0_SLHC15": {"UPG2019withGEM": "DES19_62_V8", "UPG2023SHNoTaper": "DES23_62_V1"},
18  "CMSSW_6_2_0_SLHC17": {"UPG2019withGEM": "DES19_62_V8", "UPG2023SHNoTaper": "DES23_62_V1"},
19  "CMSSW_6_2_0_SLHC20": {"UPG2019withGEM": "DES19_62_V8", "UPG2023SHNoTaper": "DES23_62_V1_UPG2023SHNoTaper"},
20  "CMSSW_6_2_0_SLHC22": {"UPG2023SHNoTaper": "PH2_1K_FB_V6_UPG23SHNoTaper",
21  # map 81X GReco and tilted to SHNoTaper
22  "2023GReco": "PH2_1K_FB_V6_UPG23SHNoTaper", "2023GRecoPU35": "", "2023GRecoPU140": "", "2023GRecoPU200": "",
23  "2023tilted": "PH2_1K_FB_V6_UPG23SHNoTaper", "2023tiltedPU35": "", "2023tiltedPU140": "", "2023tiltedPU200": ""},
24  "CMSSW_6_2_0_SLHC26": {"LHCCRefPU140": "DES23_62_V1_LHCCRefPU140", "LHCCRefPU200": "DES23_62_V1_LHCCRefPU200",
25  # map 81X GReco and tilted to LHCCRef
26  "2023GReco": "", "2023GRecoPU35": "", "2023GRecoPU140": "DES23_62_V1_LHCCRefPU140", "2023GRecoPU200": "DES23_62_V1_LHCCRefPU200",
27  "2023tilted": "", "2023tiltedPU35": "", "2023tiltedPU140": "DES23_62_V1_LHCCRefPU140", "2023tiltedPU200": "DES23_62_V1_LHCCRefPU200"},
28  "CMSSW_6_2_0_SLHC27_phase1": {"default": "DES17_62_V8_UPG17"},
29  "CMSSW_7_0_0": {"default": "POSTLS170_V3", "fullsim_50ns": "POSTLS170_V4"},
30  "CMSSW_7_0_0_AlcaCSA14": {"default": "POSTLS170_V5_AlcaCSA14", "fullsim_50ns": "POSTLS170_V6_AlcaCSA14"},
31  "CMSSW_7_0_7_pmx": {"default": "PLS170_V7AN1", "fullsim_50ns": "PLS170_V6AN1"},
32  "CMSSW_7_0_9_patch3": {"default": "PLS170_V7AN2", "fullsim_50ns": "PLS170_V6AN2"},
33  "CMSSW_7_0_9_patch3_Premix": {"default": "PLS170_V7AN2", "fullsim_50ns": "PLS170_V6AN2"},
34  "CMSSW_7_1_0": {"default": "POSTLS171_V15", "fullsim_50ns": "POSTLS171_V16"},
35  "CMSSW_7_1_9": {"default": "POSTLS171_V17", "fullsim_50ns": "POSTLS171_V18"},
36  "CMSSW_7_1_9_patch2": {"default": "POSTLS171_V17", "fullsim_50ns": "POSTLS171_V18"},
37  "CMSSW_7_1_10_patch2": {"default": "MCRUN2_71_V1", "fullsim_50ns": "MCRUN2_71_V0"},
38  "CMSSW_7_2_0_pre5": {"default": "POSTLS172_V3", "fullsim_50ns": "POSTLS172_V4"},
39  "CMSSW_7_2_0_pre7": {"default": "PRE_LS172_V11", "fullsim_50ns": "PRE_LS172_V12"},
40  "CMSSW_7_2_0_pre8": {"default": "PRE_LS172_V15", "fullsim_50ns": "PRE_LS172_V16"},
41  "CMSSW_7_2_0": {"default": "PRE_LS172_V15", "fullsim_50ns": "PRE_LS172_V16"},
42  "CMSSW_7_2_0_PHYS14": {"default": "PHYS14_25_V1_Phys14"},
43  "CMSSW_7_2_2_patch1": {"default": "MCRUN2_72_V1", "fullsim_50ns": "MCRUN2_72_V0"},
44  "CMSSW_7_2_2_patch1_Fall14DR": {"default": "MCRUN2_72_V3_71XGENSIM"},
45 # "CMSSW_7_3_0_pre1": {"default": "PRE_LS172_V15", "fullsim_25ns": "PRE_LS172_V15_OldPU", "fullsim_50ns": "PRE_LS172_V16_OldPU"},
46  "CMSSW_7_3_0_pre1": {"default": "PRE_LS172_V15", "fullsim_50ns": "PRE_LS172_V16"},
47 # "CMSSW_7_3_0_pre2": {"default": "MCRUN2_73_V1_OldPU", "fullsim_50ns": "MCRUN2_73_V0_OldPU"},
48  "CMSSW_7_3_0_pre2": {"default": "MCRUN2_73_V1", "fullsim_50ns": "MCRUN2_73_V0"},
49  "CMSSW_7_3_0_pre3": {"default": "MCRUN2_73_V5", "fullsim_50ns": "MCRUN2_73_V4"},
50  "CMSSW_7_3_0": {"default": "MCRUN2_73_V7", "fullsim_50ns": "MCRUN2_73_V6"},
51  "CMSSW_7_3_0_71XGENSIM": {"default": "MCRUN2_73_V7_71XGENSIM"},
52  "CMSSW_7_3_0_71XGENSIM_FIXGT": {"default": "MCRUN2_73_V9_71XGENSIM_FIXGT"},
53  "CMSSW_7_3_1_patch1": {"default": "MCRUN2_73_V9", "fastsim": "MCRUN2_73_V7"},
54  "CMSSW_7_3_1_patch1_GenSim_7113": {"default": "MCRUN2_73_V9_GenSim_7113"},
55  "CMSSW_7_3_3": {"default": "MCRUN2_73_V11", "fullsim_50ns": "MCRUN2_73_V10", "fastsim": "MCRUN2_73_V13"},
56  "CMSSW_7_4_0_pre1": {"default": "MCRUN2_73_V5", "fullsim_50ns": "MCRUN2_73_V4"},
57  "CMSSW_7_4_0_pre2": {"default": "MCRUN2_73_V7", "fullsim_50ns": "MCRUN2_73_V6"},
58  "CMSSW_7_4_0_pre2_73XGENSIM": {"default": "MCRUN2_73_V7_73XGENSIM_Pythia6", "fullsim_50ns": "MCRUN2_73_V6_73XGENSIM_Pythia6"},
59  "CMSSW_7_4_0_pre5": {"default": "MCRUN2_73_V7", "fullsim_50ns": "MCRUN2_73_V6"},
60  "CMSSW_7_4_0_pre5_BS": {"default": "MCRUN2_73_V9_postLS1beamspot", "fullsim_50ns": "MCRUN2_73_V8_postLS1beamspot"},
61  "CMSSW_7_4_0_pre6": {"default": "MCRUN2_74_V1", "fullsim_50ns": "MCRUN2_74_V0"},
62  "CMSSW_7_4_0_pre8": {"default": "MCRUN2_74_V7", "fullsim_25ns": "MCRUN2_74_V5_AsympMinGT", "fullsim_50ns": "MCRUN2_74_V4_StartupMinGT"},
63  "CMSSW_7_4_0_pre8_minimal": {"default": "MCRUN2_74_V5_MinGT", "fullsim_25ns": "MCRUN2_74_V5_AsympMinGT", "fullsim_50ns": "MCRUN2_74_V4_StartupMinGT"},
64  "CMSSW_7_4_0_pre8_25ns_asymptotic": {"default": "MCRUN2_74_V7"},
65  "CMSSW_7_4_0_pre8_50ns_startup": {"default": "MCRUN2_74_V6"},
66  "CMSSW_7_4_0_pre8_50ns_asympref": {"default": "MCRUN2_74_V5A_AsympMinGT"}, # for reference of 50ns asymptotic
67  "CMSSW_7_4_0_pre8_50ns_asymptotic": {"default": "MCRUN2_74_V7A_AsympGT"},
68  "CMSSW_7_4_0_pre8_ROOT6": {"default": "MCRUN2_74_V7"},
69  "CMSSW_7_4_0_pre8_pmx": {"default": "MCRUN2_74_V7", "fullsim_50ns": "MCRUN2_74_V6"},
70  "CMSSW_7_4_0_pre8_pmx_v2": {"default": "MCRUN2_74_V7_gs_pre7", "fullsim_50ns": "MCRUN2_74_V6_gs_pre7"},
71  "CMSSW_7_4_0_pre8_pmx_v3": {"default": "MCRUN2_74_V7_bis", "fullsim_50ns": "MCRUN2_74_V6_bis"},
72  "CMSSW_7_4_0_pre9": {"default": "MCRUN2_74_V7", "fullsim_50ns": "MCRUN2_74_V6"},
73  "CMSSW_7_4_0_pre9_ROOT6": {"default": "MCRUN2_74_V7", "fullsim_50ns": "MCRUN2_74_V6"},
74  "CMSSW_7_4_0_pre9_extended": {"default": "MCRUN2_74_V7_extended"},
75  "CMSSW_7_4_0": {"default": "MCRUN2_74_V7_gensim_740pre7", "fullsim_50ns": "MCRUN2_74_V6_gensim_740pre7", "fastsim": "MCRUN2_74_V7"},
76  "CMSSW_7_4_0_71XGENSIM": {"default": "MCRUN2_74_V7_GENSIM_7_1_15", "fullsim_50ns": "MCRUN2_74_V6_GENSIM_7_1_15"},
77  "CMSSW_7_4_0_71XGENSIM_PU": {"default": "MCRUN2_74_V7_gs7115_puProd", "fullsim_50ns": "MCRUN2_74_V6_gs7115_puProd"},
78  "CMSSW_7_4_0_71XGENSIM_PXworst": {"default": "MCRUN2_74_V7C_pxWorst_gs7115", "fullsim_50ns": "MCRUN2_74_V6A_pxWorst_gs7115"},
79  "CMSSW_7_4_0_71XGENSIM_PXbest": {"default": "MCRUN2_74_V7D_pxBest_gs7115", "fullsim_50ns": "MCRUN2_74_V6B_pxBest_gs7115"},
80  "CMSSW_7_4_0_pmx": {"default": "MCRUN2_74_V7", "fullsim_50ns": "MCRUN2_74_V6"},
81  "CMSSW_7_4_1": {"default": "MCRUN2_74_V9_gensim_740pre7", "fullsim_50ns": "MCRUN2_74_V8_gensim_740pre7", "fastsim": "MCRUN2_74_V9"},
82  "CMSSW_7_4_1_71XGENSIM": {"default": "MCRUN2_74_V9_gensim71X", "fullsim_50ns": "MCRUN2_74_V8_gensim71X"},
83  "CMSSW_7_4_1_extended": {"default": "MCRUN2_74_V9_extended"},
84  "CMSSW_7_4_3": {"default": "MCRUN2_74_V9", "fullsim_50ns": "MCRUN2_74_V8", "fastsim": "MCRUN2_74_V9", "fastsim_25ns": "MCRUN2_74_V9_fixMem"},
85  "CMSSW_7_4_3_extended": {"default": "MCRUN2_74_V9_ext","fastsim": "MCRUN2_74_V9_fixMem"},
86  "CMSSW_7_4_3_pmx": {"default": "MCRUN2_74_V9_ext", "fullsim_50ns": "MCRUN2_74_V8", "fastsim": "MCRUN2_74_V9_fixMem"},
87  "CMSSW_7_4_3_patch1_unsch": {"default": "MCRUN2_74_V9_unsch", "fullsim_50ns": "MCRUN2_74_V8_unsch"},
88  "CMSSW_7_4_4": {"default": "MCRUN2_74_V9_38Tbis", "fullsim_50ns": "MCRUN2_74_V8_38Tbis"},
89  "CMSSW_7_4_4_0T": {"default": "MCRUN2_740TV1_0Tv2", "fullsim_50ns": "MCRUN2_740TV0_0TV2", "fullsim_25ns": "MCRUN2_740TV1_0TV2"},
90  "CMSSW_7_4_6_patch6": {"default": "MCRUN2_74_V9_scheduled", "fullsim_50ns": "MCRUN2_74_V8_scheduled"},
91  "CMSSW_7_4_6_patch6_unsch": {"default": "MCRUN2_74_V9", "fullsim_50ns": "MCRUN2_74_V8"},
92  "CMSSW_7_4_6_patch6_noCCC": {"default": "MCRUN2_74_V9_unsch_noCCC", "fullsim_50ns": "MCRUN2_74_V8_unsch_noCCC"},
93  "CMSSW_7_4_6_patch6_noCCC_v3": {"default": "MCRUN2_74_V9_unsch_noCCC_v3", "fullsim_50ns": "MCRUN2_74_V8_unsch_noCCC_v3"},
94  "CMSSW_7_4_6_patch6_BS": {"default": "74X_mcRun2_asymptotic_realisticBS_v0_2015Jul24", "fullsim_50ns": "74X_mcRun2_startup_realisticBS_v0_2015Jul24PU", "fullsim_25ns": "74X_mcRun2_asymptotic_realisticBS_v0_2015Jul24PU"},
95  "CMSSW_7_4_8_patch1_MT": {"default": "MCRUN2_74_V11_mulTrh", "fullsim_50ns": "MCRUN2_74_V10_mulTrh",},
96  "CMSSW_7_4_12": {"default": "74X_mcRun2_asymptotic_v2", "fullsim_25ns": "74X_mcRun2_asymptotic_v2_v2", "fullsim_50ns": "74X_mcRun2_startup_v2_v2"},
97  "CMSSW_7_5_0_pre1": {"default": "MCRUN2_74_V7", "fullsim_50ns": "MCRUN2_74_V6"},
98  "CMSSW_7_5_0_pre2": {"default": "MCRUN2_74_V7", "fullsim_50ns": "MCRUN2_74_V6"},
99  "CMSSW_7_5_0_pre3": {"default": "MCRUN2_74_V7", "fullsim_50ns": "MCRUN2_74_V6"},
100  "CMSSW_7_5_0_pre4": {"default": "MCRUN2_75_V1", "fullsim_50ns": "MCRUN2_75_V0"},
101  "CMSSW_7_5_0_pre5": {"default": "MCRUN2_75_V5", "fullsim_50ns": "MCRUN2_75_V4"},
102  "CMSSW_7_5_0_pre6": {"default": "75X_mcRun2_asymptotic_v1", "fullsim_50ns": "75X_mcRun2_startup_v1"},
103  "CMSSW_7_5_0": {"default": "75X_mcRun2_asymptotic_v1", "fullsim_50ns": "75X_mcRun2_startup_v1"},
104  "CMSSW_7_5_0_71XGENSIM": {"default": "75X_mcRun2_asymptotic_v1_gs7115", "fullsim_50ns": "75X_mcRun2_startup_v1_gs7115"},
105  "CMSSW_7_5_1": {"default": "75X_mcRun2_asymptotic_v3", "fullsim_50ns": "75X_mcRun2_startup_v3"},
106  "CMSSW_7_5_1_71XGENSIM": {"default": "75X_mcRun2_asymptotic_v3_gs7118", "fullsim_50ns": "75X_mcRun2_startup_v3_gs7118"},
107  "CMSSW_7_5_2": {"default": "75X_mcRun2_asymptotic_v5", "fullsim_50ns": "75X_mcRun2_startup_v4"},
108  "CMSSW_7_6_0_pre1": {"default": "75X_mcRun2_asymptotic_v1", "fullsim_50ns": "75X_mcRun2_startup_v1"},
109  "CMSSW_7_6_0_pre2": {"default": "75X_mcRun2_asymptotic_v2", "fullsim_50ns": "75X_mcRun2_startup_v2"},
110  "CMSSW_7_6_0_pre3": {"default": "75X_mcRun2_asymptotic_v2", "fullsim_50ns": "75X_mcRun2_startup_v2"},
111  "CMSSW_7_6_0_pre4": {"default": "76X_mcRun2_asymptotic_v1", "fullsim_50ns": "76X_mcRun2_startup_v1"},
112  "CMSSW_7_6_0_pre5": {"default": "76X_mcRun2_asymptotic_v1", "fullsim_50ns": "76X_mcRun2_startup_v1"},
113  "CMSSW_7_6_0_pre6": {"default": "76X_mcRun2_asymptotic_v4", "fullsim_50ns": "76X_mcRun2_startup_v4"},
114  "CMSSW_7_6_0_pre7": {"default": "76X_mcRun2_asymptotic_v5", "fullsim_50ns": "76X_mcRun2_startup_v5", "fastsim": "76X_mcRun2_asymptotic_v5_resub"},
115  "CMSSW_7_6_0": {"default": "76X_mcRun2_asymptotic_v11", "fullsim_50ns": "76X_mcRun2_startup_v11"},
116  "CMSSW_7_6_0_71XGENSIM": {"default": "76X_mcRun2_asymptotic_v11_gs7120p2rlBS", "fullsim_50ns": "76X_mcRun2_startup_v11_gs7120p2rlBS"},
117  "CMSSW_7_6_2": {"default": "76X_mcRun2_asymptotic_v12", "fullsim_50ns": "76X_mcRun2_startup_v11"},
118  "CMSSW_7_6_3_patch2_0T": {"default": "76X_mcRun2_0T_v1_0Tv1GT"},
119  "CMSSW_8_0_0_pre1": {"default": "76X_mcRun2_asymptotic_v11", "fullsim_50ns": "76X_mcRun2_startup_v11"},
120  "CMSSW_8_0_0_pre2": {"default": "76X_mcRun2_asymptotic_v12", "fullsim_50ns": "76X_mcRun2_startup_v11"},
121  "CMSSW_8_0_0_pre2_phase1": {"default": "76X_upgrade2017_design_v7"},
122  "CMSSW_8_0_0_pre2_phase1_rereco": {"default": "76X_upgrade2017_design_v7_rereco"},
123  "CMSSW_8_0_0_pre3_phase1": {"default": "76X_upgrade2017_design_v8"},
124  "CMSSW_8_0_0_pre3_phase1_pythia8": {"default": "76X_upgrade2017_design_v8_pythia8"},
125  "CMSSW_8_0_0_pre4": {"default": "76X_mcRun2_asymptotic_v13", "fullsim_50ns": "76X_mcRun2_startup_v12"},
126  "CMSSW_8_0_0_pre4_phase1": {"default": "76X_upgrade2017_design_v8_UPG17"},
127  "CMSSW_8_0_0_pre4_phase1_13TeV": {"default": "76X_upgrade2017_design_v8_UPG17"},
128  "CMSSW_8_0_0_pre4_ecal15fb": {"default": "80X_mcRun2_asymptotic_2016EcalTune_15fb_v0_ecal15fbm1"},
129  "CMSSW_8_0_0_pre4_ecal30fb": {"default": "80X_mcRun2_asymptotic_2016EcalTune_30fb_v0_ecal30fbm1"},
130  "CMSSW_8_0_0_pre5": {"default": "80X_mcRun2_asymptotic_v1", "fullsim_50ns": "80X_mcRun2_startup_v1"},
131  "CMSSW_8_0_0_pre5_phase1": {"default": "80X_upgrade2017_design_v1_UPG17"},
132  "CMSSW_8_0_0_pre6": {"default": "80X_mcRun2_asymptotic_v4"},
133  "CMSSW_8_0_0_pre6_phase1": {"default": "80X_upgrade2017_design_v3_UPG17"},
134  "CMSSW_8_0_0_pre6_MT": {"default": "80X_mcRun2_asymptotic_v4_multiCoreResub"},
135  "CMSSW_8_0_0": {"default": "80X_mcRun2_asymptotic_v4"},
136  "CMSSW_8_0_0_patch1_phase1": {"default": "80X_upgrade2017_design_v4_UPG17"},
137  "CMSSW_8_0_0_patch1_phase1_rereco": {"default": "80X_upgrade2017_design_v4_UPG17_rereco"},
138  "CMSSW_8_0_0_patch2": {"default": "80X_mcRun2_asymptotic_v5_refGT"},
139  "CMSSW_8_0_0_patch2_pixDynIneff": {"default": "80X_mcRun2_asymptotic_v5_2016PixDynIneff_targetGT"},
140 # "CMSSW_8_0_0_patch2": {"default": "80X_mcRun2_asymptotic_v5_refGT"},
141 # "CMSSW_8_0_0_patch2_pixDynIneff": {"default": "80X_mcRun2_asymptotic_v5_2016PixDynIneff_targetGT"},
142  "CMSSW_8_0_0_patch2": {"default": "80X_mcRun2_asymptotic_v5_refGT_resub"},
143  "CMSSW_8_0_0_patch2_pixDynIneff": {"default": "80X_mcRun2_asymptotic_v5_2016PixDynIneff_targetGT_resub"},
144  "CMSSW_8_0_1": {"default": "80X_mcRun2_asymptotic_v6"},
145  "CMSSW_8_0_1_71XGENSIM": {"default": "80X_mcRun2_asymptotic_v6_gs7120p2"},
146  "CMSSW_8_0_1_gcc530": {"default": "80X_mcRun2_asymptotic_v6_gcc530"},
147  "CMSSW_8_0_3_71XGENSIM": {"default": "80X_mcRun2_asymptotic_2016_v3_gs7120p2NewGTv3"},
148  "CMSSW_8_0_3_71XGENSIM_hcal": {"default": "80X_mcRun2_asymptotic_2016_v3_gs71xNewGtHcalCust"},
149  "CMSSW_8_0_3_71XGENSIM_tec": {"default": "80X_mcRun2_asymptotic_SiStripBad_TEC_CL62_for2016_v1_mc_gs7120p2TrkCoolLoop"},
150  "CMSSW_8_0_5": {"default": "80X_mcRun2_asymptotic_v12_gs7120p2", "fastsim": "80X_mcRun2_asymptotic_v12"},
151  "CMSSW_8_0_5_pmx": {"default": "80X_mcRun2_asymptotic_v12_gs7120p2_resub", "fastsim": "80X_mcRun2_asymptotic_v12"},
152  "CMSSW_8_0_10": {"default": "80X_mcRun2_asymptotic_v14"},
153  "CMSSW_8_0_10_patch1_BS": {"default": "80X_mcRun2_asymptotic_RealisticBS_25ns_13TeV2016_v1_mc_realisticBS2016"},
154  "CMSSW_8_0_11": {"default": "80X_mcRun2_asymptotic_v14"},
155  "CMSSW_8_0_15": {"default": "80X_mcRun2_asymptotic_v16_gs7120p2", "fastsim": "80X_mcRun2_asymptotic_v16"},
156  "CMSSW_8_0_16": {"default": "80X_mcRun2_asymptotic_v16_gs7120p2", "fastsim": "80X_mcRun2_asymptotic_v16"},
157  "CMSSW_8_0_16_Tranche4GT": {"default": "80X_mcRun2_asymptotic_2016_TrancheIV_v0_gs7120p2_Tranch4GT", "fastsim": "80X_mcRun2_asymptotic_2016_TrancheIV_v0_Tranch4GT"},
158  "CMSSW_8_1_0_pre1": {"default": "80X_mcRun2_asymptotic_v6"},
159  "CMSSW_8_1_0_pre1_phase1": {"default": "80X_upgrade2017_design_v4_UPG17", "fullsim_25ns": "80X_upgrade2017_design_v4_UPG17PU35"},
160  "CMSSW_8_1_0_pre2": {"default": "80X_mcRun2_asymptotic_v10_gs810pre2", "fastsim": "80X_mcRun2_asymptotic_v10"},
161  "CMSSW_8_1_0_pre2_phase1": {"default": "80X_upgrade2017_design_v9_UPG17designGT", "fullsim_25ns": "80X_upgrade2017_design_v9_UPG17PU35designGT"},
162  "CMSSW_8_1_0_pre2_phase1_realGT": {"default": "80X_upgrade2017_realistic_v1_UPG17realGT", "fullsim_25ns": "80X_upgrade2017_realistic_v1_UPG17PU35realGT"},
163  "CMSSW_8_1_0_pre3": {"default": "80X_mcRun2_asymptotic_v12"},
164  "CMSSW_8_1_0_pre3_phase1": {"default": "80X_upgrade2017_realistic_v3_UPG17", "fullsim_25ns": "80X_upgrade2017_realistic_v3_UPG17PU35"},
165  "CMSSW_8_1_0_pre4": {"default": "80X_mcRun2_asymptotic_v13"},
166  "CMSSW_8_1_0_pre4_phase1": {"default": "80X_upgrade2017_realistic_v4_UPG17", "fullsim_25ns": "80X_upgrade2017_realistic_v4_UPG17PU35"},
167  "CMSSW_8_1_0_pre5": {"default": "80X_mcRun2_asymptotic_v13"},
168  "CMSSW_8_1_0_pre5_phase1": {"default": "80X_upgrade2017_realistic_v4_resubUPG17", "fullsim_25ns": "80X_upgrade2017_realistic_v4_resubUPG17PU35"},
169  "CMSSW_8_1_0_pre6": {"default": "80X_mcRun2_asymptotic_v14"},
170  "CMSSW_8_1_0_pre6_phase1": {"default": "81X_upgrade2017_realistic_v0_UPG17", "fullsim_25ns": "81X_upgrade2017_realistic_v0_UPG17PU35"},
171  "CMSSW_8_1_0_pre7": {"default": "81X_mcRun2_asymptotic_v0"},
172  "CMSSW_8_1_0_pre7_phase1": {"default": "81X_upgrade2017_realistic_v2_UPG17", "fullsim_25ns": "81X_upgrade2017_realistic_v2_UPG17PU35"},
173  "CMSSW_8_1_0_pre7_phase1_newGT": {"default": "81X_upgrade2017_realistic_v3_UPG17newGT", "fullsim_25ns": "81X_upgrade2017_realistic_v3_UPG17PU35newGTresub"},
174  "CMSSW_8_1_0_pre7_phase2": {"2023GReco": "81X_mcRun2_asymptotic_v0_2023GReco", "2023GRecoPU35": "", "2023GRecoPU140": "81X_mcRun2_asymptotic_v0_2023GRecoPU140resubmit2", "2023GRecoPU200": "81X_mcRun2_asymptotic_v0_2023GRecoPU200resubmit2",
175  "2023tilted": "81X_mcRun2_asymptotic_v0_2023tilted", "2023tiltedPU35": "", "2023tiltedPU140": "81X_mcRun2_asymptotic_v0_2023tiltedPU140resubmit2", "2023tiltedPU200": "81X_mcRun2_asymptotic_v0_2023tiltedPU200resubmit2"},
176  "CMSSW_8_1_0_pre8": {"default": "81X_mcRun2_asymptotic_v1"},
177  "CMSSW_8_1_0_pre8_phase1": {"default": "81X_upgrade2017_realistic_v3_UPG17", "fullsim_25ns": "81X_upgrade2017_realistic_v3_UPG17PU35"},
178  "CMSSW_8_1_0_pre8_phase1_newGT": {"default": "81X_upgrade2017_realistic_v4_UPG17newGT", "fullsim_25ns": "81X_upgrade2017_realistic_v4_UPG17PU35newGT"},
179  "CMSSW_8_1_0_pre8_phase1_newGT2": {"default": "81X_upgrade2017_realistic_v5_UPG17newGTset2", "fullsim_25ns": "81X_upgrade2017_realistic_v5_UPG17PU35newGTset2"},
180  "CMSSW_8_1_0_pre8_phase2": {"2023GReco": "81X_mcRun2_asymptotic_v1_resub2023GReco", "2023GRecoPU35": "81X_mcRun2_asymptotic_v1_resub2023GRecoPU35", "2023GRecoPU140": "81X_mcRun2_asymptotic_v1_resub2023GRecoPU140", "2023GRecoPU200": "81X_mcRun2_asymptotic_v1_resub2023GRecoPU200",
181  "2023tilted": "81X_mcRun2_asymptotic_v1_2023tilted", "2023tiltedPU35": "81X_mcRun2_asymptotic_v1_2023tiltedPU", "2023tiltedPU140": "81X_mcRun2_asymptotic_v1_2023tiltedPU140", "2023tiltedPU200": "81X_mcRun2_asymptotic_v1_2023tiltedPU200"},
182  "CMSSW_8_1_0_pre9": {"default": "81X_mcRun2_asymptotic_v2"},
183  "CMSSW_8_1_0_pre9_Geant4102": {"default": "81X_mcRun2_asymptotic_v2"},
184  "CMSSW_8_1_0_pre9_phase1": {"default": "81X_upgrade2017_realistic_v5_UPG17", "fullsim_25ns": "81X_upgrade2017_realistic_v5_UPG17PU35"},
185  "CMSSW_8_1_0_pre9_phase1_newGT": {"default": "81X_upgrade2017_realistic_v6_UPG17newGT", "fullsim_25ns": "81X_upgrade2017_realistic_v6_UPG17PU35newGT"},
186 }
187 
188 _releasePostfixes = ["_AlcaCSA14", "_PHYS14", "_TEST", "_71XGENSIM_pmx", "_gcc530_pmx", "_pmx_v2", "_pmx_v3", "_pmx", "_Fall14DR", "_71XGENSIM_FIXGT", "_71XGENSIM_PU", "_71XGENSIM_PXbest", "_71XGENSIM_PXworst", "_71XGENSIM_hcal", "_71XGENSIM_tec", "_71XGENSIM", "_73XGENSIM", "_BS", "_GenSim_7113", "_extended",
189  "_25ns_asymptotic", "_50ns_startup", "_50ns_asympref", "_50ns_asymptotic", "_minimal", "_0T", "_unsch", "_noCCC_v3", "_noCCC", "_MT", "_phase1_rereco", "_phase1_pythia8", "_phase1_13TeV", "_phase1_realGT", "_phase1_newGT2", "_phase1_newGT", "_phase1", "_phase2", "_ecal15fb", "_ecal30fb", "_pixDynIneff", "_gcc530", "_Tranche4GT"]
190 def _stripRelease(release):
191  for pf in _releasePostfixes:
192  if pf in release:
193  return release.replace(pf, "")
194  return release
195 
196 
197 def _getGlobalTag(sample, release):
198  """Get a GlobalTag.
199 
200  Arguments:
201  sample -- Sample object
202  release -- CMSSW release string
203  """
204  if not release in _globalTags:
205  print "Release %s not found from globaltag map in validation.py" % release
206  sys.exit(1)
207  gtmap = _globalTags[release]
208  if sample.hasOverrideGlobalTag():
209  ogt = sample.overrideGlobalTag()
210  if release in ogt:
211  gtmap = _globalTags[ogt[release]]
212  if sample.fullsim():
213  if sample.hasScenario():
214  return gtmap[sample.scenario()]
215  if sample.pileupEnabled():
216  puType = sample.pileupType()
217  if "50ns" in puType:
218  return gtmap.get("fullsim_50ns", gtmap["default"])
219  if "25ns" in puType:
220  return gtmap.get("fullsim_25ns", gtmap["default"])
221  if sample.fastsim():
222  fsgt = gtmap.get("fastsim", gtmap["default"])
223  if sample.pileupEnabled():
224  puType = sample.pileupType()
225  if "25ns" in puType:
226  return gtmap.get("fastsim_25ns", fsgt)
227  return fsgt
228  return gtmap["default"]
229 
230 # Mapping from release series to RelVal download URLs
231 _relvalUrls = {
232  "6_2_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_6_2_x/",
233  "7_0_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_7_0_x/",
234  "7_1_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_7_1_x/",
235  "7_2_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_7_2_x/",
236  "7_3_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_7_3_x/",
237  "7_4_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_7_4_x/",
238  "7_5_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_7_5_x/",
239  "7_6_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_7_6_x/",
240  "8_0_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_8_0_x/",
241  "8_1_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_8_1_x/",
242 }
243 
244 _doElectronSamples = [
245  "RelValTTbar",
246  "RelValSingleElectronPt35",
247  "RelValSingleElectronPt10",
248 ]
249 _doConversionSamples = [
250  "RelValTTbar",
251  "RelValH125GGgluonfusion",
252 ]
253 
254 def _getRelValUrl(release):
255  """Get RelVal download URL for a given release."""
256  version_re = re.compile("CMSSW_(?P<X>\d+)_(?P<Y>\d+)")
257  m = version_re.search(release)
258  if not m:
259  raise Exception("Regex %s does not match to release version %s" % (version_re.pattern, release))
260  version = "%s_%s_X" % (m.group("X"), m.group("Y"))
261  if not version in _relvalUrls:
262  print "No RelVal URL for version %s, please update _relvalUrls" % version
263  sys.exit(1)
264  return _relvalUrls[version]
265 
266 def _processPlotsForSample(plotterFolder, sample):
267  if plotterFolder.onlyForPileup() and not sample.pileupEnabled():
268  return False
269  if plotterFolder.onlyForElectron() and not sample.doElectron():
270  return False
271  if plotterFolder.onlyForConversion() and not sample.doConversion():
272  return False
273  return True
274 
275 class Sample:
276  """Represents a RelVal sample."""
277  def __init__(self, sample, append=None, midfix=None, putype=None, punum=0,
278  fastsim=False, fastsimCorrespondingFullsimPileup=None,
279  doElectron=None, doConversion=None,
280  version="v1", dqmVersion="0001", scenario=None, overrideGlobalTag=None, appendGlobalTag=""):
281  """Constructor.
282 
283  Arguments:
284  sample -- String for name of the sample
285 
286  Keyword arguments
287  append -- String for a variable name within the DWM file names, to be directly appended to sample name (e.g. "HS"; default None)
288  midfix -- String for a variable name within the DQM file names, to be appended after underscore to "sample name+append" (e.g. "13", "UP15"; default None)
289  putype -- String for pileup type (e.g. "25ns"/"50ns" for FullSim, "AVE20" for FastSim; default None)
290  punum -- String for amount of pileup (default None)
291  fastsim -- Bool indicating the FastSim status (default False)
292  fastsimCorrespondingFullSimPileup -- String indicating what is the FullSim pileup sample corresponding this FastSim sample. Must be set if fastsim=True and putype!=None (default None)
293  doElectron -- Bool specifying if electron-specific plots should be produced (default depends on sample)
294  doConversion -- Bool specifying if conversion-specific plots should be produced (default depends on sample)
295  version -- String for dataset/DQM file version (default "v1")
296  scenario -- Geometry scenario for upgrade samples (default None)
297  overrideGlobalTag -- GlobalTag obtained from release information (in the form of {"release": "actualRelease"}; default None)
298  appendGlobalTag -- String to append to GlobalTag (intended for one-time hacks; default "")
299  """
300  self._sample = sample
301  self._append = append
302  self._midfix = midfix
303  self._putype = putype
304  self._punum = punum
305  self._fastsim = fastsim
306  self._fastsimCorrespondingFullsimPileup = fastsimCorrespondingFullsimPileup
307  self._version = version
308  self._dqmVersion = dqmVersion
309  self._scenario = scenario
310  self._overrideGlobalTag = overrideGlobalTag
311  self._appendGlobalTag = appendGlobalTag
312 
313  if doElectron is not None:
314  self._doElectron = doElectron
315  else:
316  self._doElectron = (sample in _doElectronSamples)
317  if doConversion is not None:
318  self._doConversion = doConversion
319  else:
320  self._doConversion = (sample in _doConversionSamples)
321 
322  if self._fastsim and self.hasPileup() and self._fastsimCorrespondingFullsimPileup is None:
324 
325  def digest(self):
326  """Return a tuple uniquely identifying the sample, to be used e.g. as a key to dict"""
327  return (self.name(), self.pileupNumber(), self.pileupType(), self.scenario(), self.fastsim())
328 
329  def sample(self):
330  """Get the sample name"""
331  return self._sample
332 
333  def name(self):
334  """Get the sample name"""
335  return self._sample
336 
337  def label(self):
338  return self._sample
339 
340  def hasPileup(self):
341  """Return True if sample has pileup (for HTML generation)"""
342  return self._putype is not None
343 
344  def pileupEnabled(self):
345  """Return True if pileup plots are enabled (for plot generation)"""
346  return self.hasPileup()
347 
348  def pileup(self):
349  """Return "PU"/"noPU" corresponding the pileup status"""
350  if self.hasPileup():
351  return "PU"
352  else:
353  return "noPU"
354 
355  def pileupType(self, release=None):
356  """Return the pileup type"""
357  if isinstance(self._putype, dict):
358  return self._putype.get(release, self._putype["default"])
359  else:
360  return self._putype
361 
362  def pileupNumber(self):
363  return self._punum
364 
365  def doElectron(self):
366  return self._doElectron
367 
368  def doConversion(self):
369  return self._doConversion
370 
371  def version(self, release=None):
372  if isinstance(self._version, dict):
373  return self._version.get(release, self._version["default"])
374  else:
375  return self._version
376 
377  def hasScenario(self):
378  return self._scenario is not None
379 
380  def scenario(self):
381  return self._scenario
382 
384  return self._overrideGlobalTag is not None
385 
386  def overrideGlobalTag(self):
387  return self._overrideGlobalTag
388 
389  def fastsim(self):
390  """Return True for FastSim sample"""
391  return self._fastsim
392 
393  def fullsim(self):
394  """Return True for FullSim sample"""
395  return not self._fastsim
396 
399 
400  def dirname(self, newRepository, newRelease, newSelection):
401  """Return the output directory name
402 
403  Arguments:
404  newRepository -- String for base directory for output files
405  newRelease -- String for CMSSW release
406  newSelection -- String for histogram selection
407  """
408  pileup = ""
409  if self.hasPileup() and not self._fastsim:
410  pileup = "_"+self._putype
411  return "{newRepository}/{newRelease}/{newSelection}{pileup}/{sample}".format(
412  newRepository=newRepository, newRelease=newRelease, newSelection=newSelection,
413  pileup=pileup, sample=sample)
414 
415  def filename(self, newRelease):
416  """Return the DQM file name
417 
418  Arguments:
419  newRelease -- String for CMSSW release
420  """
421  pileup = ""
422  fastsim = ""
423  midfix = ""
424  sample = self._sample
425  if self._append is not None:
426  midfix += self._append
427  if self._midfix is not None:
428  midfix += "_"+self._midfix
429  if self.hasPileup():
430  if self._fastsim:
431  #sample = sample.replace("RelVal", "RelValFS_")
432  # old style
433  #pileup = "PU_"
434  #midfix += "_"+self.pileupType(newRelease)
435  # new style
436  pileup = "PU"+self.pileupType(newRelease)+"_"
437  else:
438  pileup = "PU"+self.pileupType(newRelease)+"_"
439  if self._fastsim:
440  fastsim = "_FastSim"
441 
442  globalTag = _getGlobalTag(self, newRelease)
443 
444  fname = 'DQM_V{dqmVersion}_R000000001__{sample}{midfix}__{newrelease}-{pileup}{globaltag}{appendGlobalTag}{fastsim}-{version}__DQMIO.root'.format(
445  sample=sample, midfix=midfix, newrelease=_stripRelease(newRelease),
446  pileup=pileup, globaltag=globalTag, appendGlobalTag=self._appendGlobalTag, fastsim=fastsim,
447  version=self.version(newRelease), dqmVersion=self._dqmVersion
448  )
449 
450  return fname
451 
452  def datasetpattern(self, newRelease):
453  """Return the dataset pattern
454 
455  Arguments:
456  newRelease -- String for CMSSW release
457  """
458  pileup = ""
459  fastsim = ""
460  digi = ""
461  if self.hasPileup():
462  pileup = "-PU_"
463  if self._fastsim:
464  fastsim = "_FastSim-"
465  digi = "DIGI-"
466  else:
467  fastsim = "*"
468  globalTag = _getGlobalTag(self, newRelease)
469  return "{sample}/{newrelease}-{pileup}{globaltag}{fastsim}{version}/GEN-SIM-{digi}RECO".format(
470  sample=self._sample, newrelease=newRelease,
471  pileup=pileup, globaltag=globalTag, fastsim=fastsim, digi=digi,
472  version=self.version(newRelease)
473  )
474 
476  """Base class for Tracking/Vertex validation."""
477  def __init__(self, fullsimSamples, fastsimSamples, refRelease, refRepository, newRelease, newRepository, newFileModifier=None, selectionName=""):
478  """Constructor.
479 
480  Arguments:
481  fullsimSamples -- List of Sample objects for FullSim samples (may be empty)
482  fastsimSamples -- List of Sample objects for FastSim samples (may be empty)
483  refRelease -- String for reference CMSSW release (can be None for no reference release)
484  newRepository -- String for directory whete to put new files
485  newRelease -- CMSSW release to be validated
486  refRepository -- String for directory where reference root files are
487  newFileModifier -- If given, a function to modify the names of the new files (function takes a string and returns a string)
488  selectionName -- If given, use this string as the selection name (appended to GlobalTag for directory names)
489  """
490  try:
491  self._newRelease = os.environ["CMSSW_VERSION"]
492  except KeyError:
493  print >>sys.stderr, 'Error: CMSSW environment variables are not available.'
494  print >>sys.stderr, ' Please run cmsenv'
495  sys.exit()
496 
497  self._fullsimSamples = fullsimSamples
498  self._fastsimSamples = fastsimSamples
499  self._refRelease = refRelease
500  self._refRepository = refRepository
501  self._newRelease = newRelease
502  self._newBaseDir = os.path.join(newRepository, self._newRelease)
503  self._newFileModifier = newFileModifier
504  self._selectionName = selectionName
505 
506  def _getDirectoryName(self, *args, **kwargs):
507  return None
508 
509  def _getSelectionName(self, *args, **kwargs):
510  return self._selectionName
511 
512  def download(self):
513  """Download DQM files. Requires grid certificate and asks your password for it."""
514  filenames = [s.filename(self._newRelease) for s in self._fullsimSamples+self._fastsimSamples]
515  if self._newFileModifier is not None:
516  filenames = map(self._newFileModifier, filenames)
517  filenames = filter(lambda f: not os.path.exists(f), filenames)
518  if len(filenames) == 0:
519  print "All files already downloaded"
520  return
521 
522  relvalUrl = _getRelValUrl(self._newRelease)
523  urls = [relvalUrl+f for f in filenames]
524  certfile = os.path.join(os.environ["HOME"], ".globus", "usercert.pem")
525  if not os.path.exists(certfile):
526  print "Certificate file {certfile} does not exist, unable to download RelVal files from {url}".format(certfile=certfile, url=relvalUrl)
527  sys.exit(1)
528  keyfile = os.path.join(os.environ["HOME"], ".globus", "userkey.pem")
529  if not os.path.exists(certfile):
530  print "Private key file {keyfile} does not exist, unable to download RelVal files from {url}".format(keyfile=keyfile, url=relvalUrl)
531  sys.exit(1)
532 
533  # curl --cert-type PEM --cert $HOME/.globus/usercert.pem --key $HOME/.globus/userkye.pem -k -O <url> -O <url>
534  cmd = ["curl", "--cert-type", "PEM", "--cert", certfile, "--key", keyfile, "-k"]
535  for u in urls:
536  cmd.extend(["-O", u])
537  print "Downloading %d files from RelVal URL %s:" % (len(filenames), relvalUrl)
538  print " "+"\n ".join(filenames)
539  print "Please provide your private key pass phrase when curl asks it"
540  ret = subprocess.call(cmd)
541  if ret != 0:
542  print "Downloading failed with exit code %d" % ret
543  sys.exit(1)
544 
545  # verify
546  allFine = True
547  for f in filenames:
548  p = subprocess.Popen(["file", f], stdout=subprocess.PIPE)
549  stdout = p.communicate()[0]
550  if p.returncode != 0:
551  print "file command failed with exit code %d" % p.returncode
552  sys.exit(1)
553  if not "ROOT" in stdout:
554  print "File {f} is not ROOT, please check the correct version, GlobalTag etc. from {url}".format(f=f, url=relvalUrl)
555  allFine = False
556  if os.path.exists(f):
557  os.remove(f)
558  if not allFine:
559  sys.exit(1)
560 
561  def createHtmlReport(self):
562  return html.HtmlReport(self._newRelease, self._newBaseDir)
563 
564  def doPlots(self, plotter, plotterDrawArgs={}, limitSubFoldersOnlyTo=None, htmlReport=html.HtmlReportDummy(), doFastVsFull=True, doPhase2PU=False):
565  """Create validation plots.
566 
567  Arguments:
568  plotter -- plotting.Plotter object that does the plotting
569 
570  Keyword arguments:
571  plotterDrawArgs -- Dictionary for additional arguments to Plotter.draw() (default: {})
572  limitSubFoldersOnlyTo -- If not None, should be a dictionary from string to an object. The string is the name of a PlotFolder, and the object is PlotFolder-type specific to limit the subfolders to be processed. In general case the object is a list of strings, but e.g. for track iteration plots it is a function taking the algo and quality as parameters.
573  htmlReport -- Object returned by createHtmlReport(), in case HTML report generation is desired
574  doFastVsFull -- Do FastSim vs. FullSim comparison? (default: True)
575  doPhase2PU -- Do Phase2 PU 200 vs. 140 comparison (default: False)
576  """
577  self._plotter = plotter
578  self._plotterDrawArgs = plotterDrawArgs
579 
580  # New vs. Ref
581  for sample in self._fullsimSamples+self._fastsimSamples:
582  # Check that the new DQM file exists
583  harvestedFile = sample.filename(self._newRelease)
584  if not os.path.exists(harvestedFile):
585  print "Harvested file %s does not exist!" % harvestedFile
586  sys.exit(1)
587 
588  plotterInstance = plotter.readDirs(harvestedFile)
589  htmlReport.beginSample(sample)
590  for plotterFolder, dqmSubFolder in plotterInstance.iterFolders(limitSubFoldersOnlyTo=limitSubFoldersOnlyTo):
591  if not _processPlotsForSample(plotterFolder, sample):
592  continue
593  plotFiles = self._doPlots(sample, harvestedFile, plotterFolder, dqmSubFolder, htmlReport)
594  htmlReport.addPlots(plotterFolder, dqmSubFolder, plotFiles)
595 
596  # Fast vs. Full
597  if doFastVsFull:
598  self._doFastsimFastVsFullPlots(limitSubFoldersOnlyTo, htmlReport)
599 
600  # Phase2 PU200 vs. PU 140
601  if doPhase2PU:
602  self._doPhase2PileupPlots(limitSubFoldersOnlyTo, htmlReport)
603 
604  def _doFastsimFastVsFullPlots(self, limitSubFoldersOnlyTo, htmlReport):
605  for fast in self._fastsimSamples:
606  correspondingFull = None
607  for full in self._fullsimSamples:
608  if fast.name() != full.name():
609  continue
610  if fast.pileupEnabled():
611  if not full.pileupEnabled():
612  continue
613  if fast.fastsimCorrespondingFullsimPileup() != full.pileupType():
614  continue
615  else:
616  if full.pileupEnabled():
617  continue
618 
619  if correspondingFull is None:
620  correspondingFull = full
621  else:
622  raise Exception("Got multiple compatible FullSim samples for FastSim sample %s %s" % (fast.name(), fast.pileup()))
623  if correspondingFull is None:
624  print "WARNING: Did not find compatible FullSim sample for FastSim sample %s %s, omitting FastSim vs. FullSim comparison" % (fast.name(), fast.pileup())
625  continue
626 
627  # If we reach here, the harvestedFile must exist
628  harvestedFile = fast.filename(self._newRelease)
629  plotterInstance = self._plotter.readDirs(harvestedFile)
630  htmlReport.beginSample(fast, fastVsFull=True)
631  for plotterFolder, dqmSubFolder in plotterInstance.iterFolders(limitSubFoldersOnlyTo=limitSubFoldersOnlyTo):
632  if not _processPlotsForSample(plotterFolder, fast):
633  continue
634  plotFiles = self._doPlotsFastFull(fast, correspondingFull, plotterFolder, dqmSubFolder, htmlReport)
635  htmlReport.addPlots(plotterFolder, dqmSubFolder, plotFiles)
636 
637  def _doPhase2PileupPlots(self, limitSubFoldersOnlyTo, htmlReport):
638  def _stripScenario(name):
639  puindex = name.find("PU")
640  if puindex < 0:
641  return name
642  return name[:puindex]
643 
644  pu140samples = {}
645  for sample in self._fullsimSamples:
646  if sample.pileupNumber() == 140:
647  key = (sample.name(), _stripScenario(sample.scenario()))
648  if key in pu140samples:
649  raise Exception("Duplicate entry for sample %s in scenario %s" % (sample.name(), sample.scenar()))
650  pu140samples[key] = sample
651 
652  for sample in self._fullsimSamples:
653  if sample.pileupNumber() != 200:
654  continue
655  key = (sample.name(), _stripScenario(sample.scenario()))
656  if not key in pu140samples:
657  continue
658 
659  sample_pu140 = pu140samples[key]
660 
661  # If we reach here, the harvestedFile must exist
662  harvestedFile = sample.filename(self._newRelease)
663  plotterInstance = self._plotter.readDirs(harvestedFile)
664  htmlReport.beginSample(sample, pileupComparison="vs. PU140")
665  for plotterFolder, dqmSubFolder in plotterInstance.iterFolders(limitSubFoldersOnlyTo=limitSubFoldersOnlyTo):
666  if not _processPlotsForSample(plotterFolder, sample):
667  continue
668  plotFiles = self._doPlotsPileup(sample_pu140, sample, plotterFolder, dqmSubFolder, htmlReport)
669  htmlReport.addPlots(plotterFolder, dqmSubFolder, plotFiles)
670 
671 
672  def _getRefFileAndSelection(self, sample, plotterFolder, dqmSubFolder, selectionNameBase, valname):
673  if self._refRelease is None:
674  return (None, "")
675 
676  refGlobalTag = _getGlobalTag(sample, self._refRelease)
677  def _createRefSelection(selectionName):
678  sel = refGlobalTag+selectionNameBase+selectionName
679  if sample.pileupEnabled():
680  refPu = sample.pileupType(self._refRelease)
681  if refPu != "":
682  sel += "_"+refPu
683  return sel
684  refSelection = _createRefSelection(plotterFolder.getSelectionName(dqmSubFolder))
685 
686  # Construct reference directory name, and open reference file it it exists
687  refValFile = None
688  triedRefValFiles = []
689  tmp = [self._refRepository, self._refRelease]
690  if sample.fastsim():
691  tmp.extend(["fastsim", self._refRelease])
692  for selName in plotterFolder.getSelectionNameIterator(dqmSubFolder):
693  refSel = _createRefSelection(selName)
694  refdir = os.path.join(*(tmp+[refSel, sample.name()]))
695 
696  # Open reference file if it exists
697  refValFilePath = os.path.join(refdir, valname)
698  if os.path.exists(refValFilePath):
699  refSelection = refSel
700  refValFile = ROOT.TFile.Open(refValFilePath)
701  break
702  else:
703  triedRefValFiles.append(refValFilePath)
704  if refValFile is None:
705  if len(triedRefValFiles) == 1:
706  if plotting.verbose:
707  print "Reference file %s not found" % triedRefValFiles[0]
708  else:
709  if plotting.verbose:
710  print "None of the possible reference files %s not found" % ",".join(triedRefValFiles)
711 
712  return (refValFile, refSelection)
713 
714  def _doPlots(self, sample, harvestedFile, plotterFolder, dqmSubFolder, htmlReport):
715  """Do the real plotting work for a given sample and DQM subfolder"""
716  # Get GlobalTags
717  newGlobalTag = _getGlobalTag(sample, self._newRelease)
718 
719  # Construct selection string
720  selectionNameBase = "_"+sample.pileup()
721  newSelection = newGlobalTag+selectionNameBase+plotterFolder.getSelectionName(dqmSubFolder)
722  if sample.pileupEnabled():
723  newPu = sample.pileupType(self._newRelease)
724  if newPu != "":
725  newSelection += "_"+newPu
726 
727  valname = "val.{sample}.root".format(sample=sample.name())
728 
729  # Construct reference file and selection string
730  (refValFile, refSelection) = self._getRefFileAndSelection(sample, plotterFolder, dqmSubFolder, selectionNameBase, valname)
731 
732  # Construct new directory name
733  tmp = []
734  if sample.fastsim():
735  tmp.extend(["fastsim", self._newRelease])
736  tmp.extend([newSelection, sample.name()])
737  newsubdir = os.path.join(*tmp)
738  newdir = os.path.join(self._newBaseDir, newsubdir)
739 
740  # Copy the relevant histograms to a new validation root file
741  # TODO: treat the case where dqmSubFolder is empty
742  newValFile = _copySubDir(harvestedFile, valname, plotterFolder.getPossibleDQMFolders(), dqmSubFolder.subfolder if dqmSubFolder is not None else None)
743  fileList = []
744 
745  # Do the plots
746  if plotting.verbose:
747  print "Comparing ref and new {sim} {sample} {translatedFolder}".format(
748  sim="FullSim" if not sample.fastsim() else "FastSim",
749  sample=sample.name(), translatedFolder=str(dqmSubFolder.translated) if dqmSubFolder is not None else "")
750  rootFiles = [refValFile, newValFile]
751  legendLabels = [
752  "%s, %s %s" % (sample.name(), _stripRelease(self._refRelease), refSelection) if self._refRelease is not None else "dummy",
753  "%s, %s %s" % (sample.name(), _stripRelease(self._newRelease), newSelection)
754  ]
755  plotterFolder.create(rootFiles, legendLabels, dqmSubFolder, isPileupSample=sample.pileupEnabled())
756  fileList.extend(plotterFolder.draw(**self._plotterDrawArgs))
757  # Copy val file only if there were plots
758  if len(fileList) > 0:
759  fileList.append(valname)
760 
761  # For tables we just try them all, and see which ones succeed
762  for tableCreator in plotterFolder.getTableCreators():
763  htmlReport.addTable(tableCreator.create(rootFiles, legendLabels, dqmSubFolder))
764 
765  newValFile.Close()
766  if refValFile is not None:
767  refValFile.Close()
768 
769  if len(fileList) == 0:
770  return []
771 
772  dups = _findDuplicates(fileList)
773  if len(dups) > 0:
774  print "Plotter produced multiple files with names", ", ".join(dups)
775  print "Typically this is a naming problem in the plotter configuration"
776  sys.exit(1)
777 
778  # Move plots to new directory
779  print "Moving plots and %s to %s" % (valname, newdir)
780  if not os.path.exists(newdir):
781  os.makedirs(newdir)
782  for f in fileList:
783  shutil.move(f, os.path.join(newdir, f))
784  return map(lambda n: os.path.join(newsubdir, n), fileList)
785 
786  def _doPlotsFastFull(self, fastSample, fullSample, plotterFolder, dqmSubFolder, htmlReport):
787  """Do the real plotting work for FastSim vs. FullSim for a given algorithm, quality flag, and sample."""
788  # Get GlobalTags
789  fastGlobalTag = _getGlobalTag(fastSample, self._newRelease)
790  fullGlobalTag = _getGlobalTag(fullSample, self._newRelease)
791 
792  # Construct selection string
793  tmp = plotterFolder.getSelectionName(dqmSubFolder)
794  fastSelection = fastGlobalTag+"_"+fastSample.pileup()+tmp
795  fullSelection = fullGlobalTag+"_"+fullSample.pileup()+tmp
796  if fullSample.pileupEnabled():
797  fullSelection += "_"+fullSample.pileupType(self._newRelease)
798  fastSelection += "_"+fastSample.pileupType(self._newRelease)
799 
800  # Construct directories for FastSim, FullSim, and for the results
801  fastdir = os.path.join(self._newBaseDir, "fastsim", self._newRelease, fastSelection, fastSample.name())
802  fulldir = os.path.join(self._newBaseDir, fullSelection, fullSample.name())
803  newsubdir = os.path.join("fastfull", self._newRelease, fastSelection, fastSample.name())
804  newdir = os.path.join(self._newBaseDir, newsubdir)
805 
806  # Open input root files
807  valname = "val.{sample}.root".format(sample=fastSample.name())
808  fastValFilePath = os.path.join(fastdir, valname)
809  if not os.path.exists(fastValFilePath) and plotting.verbose:
810  print "FastSim file %s not found" % fastValFilePath
811  fullValFilePath = os.path.join(fulldir, valname)
812  if not os.path.exists(fullValFilePath) and plotting.verbose:
813  print "FullSim file %s not found" % fullValFilePath
814 
815  fastValFile = ROOT.TFile.Open(fastValFilePath)
816  fullValFile = ROOT.TFile.Open(fullValFilePath)
817 
818  # Do plots
819  if plotting.verbose:
820  print "Comparing FullSim and FastSim {sample} {translatedFolder}".format(
821  sample=fastSample.name(), translatedFolder=str(dqmSubFolder.translated) if dqmSubFolder is not None else "")
822  rootFiles = [fullValFile, fastValFile]
823  legendLabels = [
824  "FullSim %s, %s %s" % (fullSample.name(), _stripRelease(self._newRelease), fullSelection),
825  "FastSim %s, %s %s" % (fastSample.name(), _stripRelease(self._newRelease), fastSelection),
826  ]
827  plotterFolder.create(rootFiles, legendLabels, dqmSubFolder, isPileupSample=fastSample.pileupEnabled(), requireAllHistograms=True)
828  fileList = plotterFolder.draw(**self._plotterDrawArgs)
829 
830  # For tables we just try them all, and see which ones succeed
831  for tableCreator in plotterFolder.getTableCreators():
832  htmlReport.addTable(tableCreator.create(rootFiles, legendLabels, dqmSubFolder))
833 
834  fullValFile.Close()
835  fastValFile.Close()
836 
837  if len(fileList) == 0:
838  return []
839 
840  dups = _findDuplicates(fileList)
841  if len(dups) > 0:
842  print "Plotter produced multiple files with names", ", ".join(dups)
843  print "Typically this is a naming problem in the plotter configuration"
844  sys.exit(1)
845 
846  # Move plots to new directory
847  print "Moving plots to %s" % (newdir)
848  if not os.path.exists(newdir):
849  os.makedirs(newdir)
850  for f in fileList:
851  shutil.move(f, os.path.join(newdir, f))
852  return map(lambda n: os.path.join(newsubdir, n), fileList)
853 
854  def _doPlotsPileup(self, pu140Sample, pu200Sample, plotterFolder, dqmSubFolder, htmlReport):
855  """Do the real plotting work for two pileup scenarios for a given algorithm, quality flag, and sample."""
856  # Get GlobalTags
857  pu140GlobalTag = _getGlobalTag(pu140Sample, self._newRelease)
858  pu200GlobalTag = _getGlobalTag(pu200Sample, self._newRelease)
859 
860  # Construct selection string
861  tmp = plotterFolder.getSelectionName(dqmSubFolder)
862  pu140Selection = pu140GlobalTag+"_"+pu140Sample.pileup()+tmp+"_"+pu140Sample.pileupType(self._newRelease)
863  pu200Selection = pu200GlobalTag+"_"+pu200Sample.pileup()+tmp+"_"+pu200Sample.pileupType(self._newRelease)
864 
865  # Construct directories for
866  pu140dir = os.path.join(self._newBaseDir, pu140Selection, pu140Sample.name())
867  pu200dir = os.path.join(self._newBaseDir, pu200Selection, pu200Sample.name())
868  newsubdir = os.path.join("pileup", self._newRelease, pu200Selection, pu200Sample.name())
869  newdir = os.path.join(self._newBaseDir, newsubdir)
870 
871  # Open input root files
872  valname = "val.{sample}.root".format(sample=pu140Sample.name())
873  pu140ValFilePath = os.path.join(pu140dir, valname)
874  if not os.path.exists(pu140ValFilePath):
875  if plotting.verbose:
876  print "PU140 file %s not found" % pu140ValFilePath
877  return []
878  pu200ValFilePath = os.path.join(pu200dir, valname)
879  if not os.path.exists(pu200ValFilePath):
880  if plotting.verbose:
881  print "PU200 file %s not found" % pu200ValFilePath
882  return []
883 
884  pu140ValFile = ROOT.TFile.Open(pu140ValFilePath)
885  pu200ValFile = ROOT.TFile.Open(pu200ValFilePath)
886 
887  # Do plots
888  if plotting.verbose:
889  print "Comparing PU140 and PU200 {sample} {translatedFolder}".format(
890  sample=pu200Sample.name(), translatedFolder=str(dqmSubFolder.translated) if dqmSubFolder is not None else "")
891  rootFiles = [pu140ValFile, pu200ValFile]
892  legendLabels = [
893  "%s, %s %s" % (pu140Sample.name(), _stripRelease(self._newRelease), pu140Selection),
894  "%s, %s %s" % (pu200Sample.name(), _stripRelease(self._newRelease), pu200Selection),
895  ]
896  plotterFolder.create(rootFiles, legendLabels, dqmSubFolder, isPileupSample=pu140Sample.pileupEnabled(), requireAllHistograms=True)
897  fileList = plotterFolder.draw(**self._plotterDrawArgs)
898 
899  # For tables we just try them all, and see which ones succeed
900  for tableCreator in plotterFolder.getTableCreators():
901  htmlReport.addTable(tableCreator.create(rootFiles, legendLabels, dqmSubFolder))
902 
903  pu200ValFile.Close()
904  pu140ValFile.Close()
905 
906  if len(fileList) == 0:
907  return []
908 
909  dups = _findDuplicates(fileList)
910  if len(dups) > 0:
911  print "Plotter produced multiple files with names", ", ".join(dups)
912  print "Typically this is a naming problem in the plotter configuration"
913  sys.exit(1)
914 
915  # Move plots to new directory
916  print "Moving plots to %s" % (newdir)
917  if not os.path.exists(newdir):
918  os.makedirs(newdir)
919  for f in fileList:
920  shutil.move(f, os.path.join(newdir, f))
921  return map(lambda n: os.path.join(newsubdir, n), fileList)
922 
923 
924 def _copySubDir(oldfile, newfile, basenames, dirname):
925  """Copy a subdirectory from oldfile to newfile.
926 
927  Arguments:
928  oldfile -- String for source TFile
929  newfile -- String for destination TFile
930  basenames -- List of strings for base directories, first existing one is picked
931  dirname -- String for directory name under the base directory
932  """
933  oldf = ROOT.TFile.Open(oldfile)
934 
935  dirold = None
936  for basename in basenames:
937  dirold = oldf.GetDirectory(basename)
938  if dirold:
939  break
940  if not dirold:
941  raise Exception("Did not find any of %s directories from file %s" % (",".join(basenames), oldfile))
942  if dirname:
943  d = dirold.Get(dirname)
944  if not d:
945  raise Exception("Did not find directory %s under %s" % (dirname, dirold.GetPath()))
946  dirold = d
947 
948  newf = ROOT.TFile.Open(newfile, "RECREATE")
949  dirnew = newf
950  for d in basenames[0].split("/"):
951  dirnew = dirnew.mkdir(d)
952  if dirname:
953  dirnew = dirnew.mkdir(dirname)
954  _copyDir(dirold, dirnew)
955 
956  oldf.Close()
957  return newf
958 
959 def _copyDir(src, dst):
960  """Copy non-TTree objects from src TDirectory to dst TDirectory."""
961  keys = src.GetListOfKeys()
962  for key in keys:
963  classname = key.GetClassName()
964  cl = ROOT.TClass.GetClass(classname)
965  if not cl:
966  continue
967  if not (cl.InheritsFrom("TTree") and cl.InheritsFrom("TDirectory")):
968  dst.cd()
969  obj = key.ReadObj()
970  obj.Write()
971  obj.Delete()
972 
974  found = set()
975  found2 = set()
976  for x in lst:
977  if x in found:
978  found2.add(x)
979  else:
980  found.add(x)
981  return list(found2)
982 
984  def __init__(self, label, name, fileLegends, pileup=True, customPileupLabel=""):
985  self._label = label
986  self._name = name
987  self._fileLegends = fileLegends
988  self._pileup = pileup
989  self._customPileupLabel = customPileupLabel
990 
991  def digest(self):
992  # Label should be unique among the plotting run, so it serves also as the digest
993  return self._label
994 
995  def label(self):
996  return self._label
997 
998  def name(self):
999  return self._name
1000 
1001  def files(self):
1002  return [t[0] for t in self._fileLegends]
1003 
1004  def legendLabels(self):
1005  return [t[1] for t in self._fileLegends]
1006 
1007  def fastsim(self):
1008  # No need to emulate the release validation fastsim behaviour here
1009  return False
1010 
1011  def pileupEnabled(self):
1012  return self._pileup
1013 
1015  return self._customPileupLabel
1016 
1017  def doElectron(self):
1018  return True
1019 
1020  def doConversion(self):
1021  return True
1022 
1024  def __init__(self, samples, newdir):
1025  self._samples = samples
1026  self._newdir = newdir
1027  if not os.path.exists(newdir):
1028  os.makedirs(newdir)
1029 
1031 
1032  def createHtmlReport(self, validationName=""):
1033  if hasattr(self._htmlReport, "write"):
1034  raise Exception("HTML report object already created. There is probably some logic error in the calling code.")
1035  self._htmlReport = html.HtmlReport(validationName, self._newdir)
1036  return self._htmlReport
1037 
1038  def doPlots(self, plotters, plotterDrawArgs={}, **kwargs):
1039  self._plotterDrawArgs = plotterDrawArgs
1040 
1041  for sample in self._samples:
1042  self._subdirprefix = sample.label()
1043  self._labels = sample.legendLabels()
1044  self._htmlReport.beginSample(sample)
1045 
1046  self._openFiles = []
1047  for f in sample.files():
1048  if os.path.exists(f):
1049  self._openFiles.append(ROOT.TFile.Open(f))
1050  else:
1051  print "File %s not found (from sample %s), ignoring it" % (f, sample.name())
1052  self._openFiles.append(None)
1053 
1054  for plotter in plotters:
1055  self._doPlotsForPlotter(plotter, sample, **kwargs)
1056 
1057  for tf in self._openFiles:
1058  if tf is not None:
1059  tf.Close()
1060  self._openFiles = []
1061 
1062  def _doPlotsForPlotter(self, plotter, sample, limitSubFoldersOnlyTo=None):
1063  plotterInstance = plotter.readDirs(*self._openFiles)
1064  for plotterFolder, dqmSubFolder in plotterInstance.iterFolders(limitSubFoldersOnlyTo=limitSubFoldersOnlyTo):
1065  if sample is not None and not _processPlotsForSample(plotterFolder, sample):
1066  continue
1067  plotFiles = self._doPlots(plotterFolder, dqmSubFolder)
1068  if len(plotFiles) > 0:
1069  self._htmlReport.addPlots(plotterFolder, dqmSubFolder, plotFiles)
1070 
1071  def _doPlots(self, plotterFolder, dqmSubFolder):
1072  plotterFolder.create(self._openFiles, self._labels, dqmSubFolder)
1073  fileList = plotterFolder.draw(**self._plotterDrawArgs)
1074 
1075  for tableCreator in plotterFolder.getTableCreators():
1076  self._htmlReport.addTable(tableCreator.create(self._openFiles, self._labels, dqmSubFolder))
1077 
1078  newsubdir = self._subdirprefix+plotterFolder.getSelectionName(dqmSubFolder)
1079  newdir = os.path.join(self._newdir, newsubdir)
1080 
1081  if len(fileList) == 0:
1082  return fileList
1083 
1084  dups = _findDuplicates(fileList)
1085  if len(dups) > 0:
1086  print "Plotter produced multiple files with names", ", ".join(dups)
1087  print "Typically this is a naming problem in the plotter configuration"
1088  sys.exit(1)
1089 
1090  print "Moving plots to %s" % newdir
1091  if not os.path.exists(newdir):
1092  os.makedirs(newdir)
1093  for f in fileList:
1094  shutil.move(f, os.path.join(newdir, f))
1095  return map(lambda n: os.path.join(newsubdir, n), fileList)
def name(self)
Definition: validation.py:333
def __init__(self, sample, append=None, midfix=None, putype=None, punum=0, fastsim=False, fastsimCorrespondingFullsimPileup=None, doElectron=None, doConversion=None, version="v1", dqmVersion="0001", scenario=None, overrideGlobalTag=None, appendGlobalTag="")
Definition: validation.py:280
def sample(self)
Definition: validation.py:329
_fastsimCorrespondingFullsimPileup
Definition: validation.py:306
def _getGlobalTag(sample, release)
Definition: validation.py:197
def _doPlotsPileup(self, pu140Sample, pu200Sample, plotterFolder, dqmSubFolder, htmlReport)
Definition: validation.py:854
def createHtmlReport(self, validationName="")
Definition: validation.py:1032
def _getSelectionName(self, args, kwargs)
Definition: validation.py:509
def hasPileup(self)
Definition: validation.py:340
def dirname(self, newRepository, newRelease, newSelection)
Definition: validation.py:400
def fullsim(self)
Definition: validation.py:393
def filename(self, newRelease)
Definition: validation.py:415
def _getDirectoryName(self, args, kwargs)
Definition: validation.py:506
def __init__(self, label, name, fileLegends, pileup=True, customPileupLabel="")
Definition: validation.py:984
def datasetpattern(self, newRelease)
Definition: validation.py:452
def label(self)
Definition: validation.py:337
def _doPlots(self, plotterFolder, dqmSubFolder)
Definition: validation.py:1071
def hasScenario(self)
Definition: validation.py:377
def doConversion(self)
Definition: validation.py:368
def pileupType(self, release=None)
Definition: validation.py:355
def pileupNumber(self)
Definition: validation.py:362
def _doFastsimFastVsFullPlots(self, limitSubFoldersOnlyTo, htmlReport)
Definition: validation.py:604
def _getRelValUrl(release)
Definition: validation.py:254
def _stripRelease(release)
Definition: validation.py:190
def _processPlotsForSample(plotterFolder, sample)
Definition: validation.py:266
def hasOverrideGlobalTag(self)
Definition: validation.py:383
def _doPlotsFastFull(self, fastSample, fullSample, plotterFolder, dqmSubFolder, htmlReport)
Definition: validation.py:786
def doElectron(self)
Definition: validation.py:365
def digest(self)
Definition: validation.py:325
def version(self, release=None)
Definition: validation.py:371
def doPlots(self, plotters, plotterDrawArgs={}, kwargs)
Definition: validation.py:1038
def __init__(self, fullsimSamples, fastsimSamples, refRelease, refRepository, newRelease, newRepository, newFileModifier=None, selectionName="")
Definition: validation.py:477
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
def _copyDir(src, dst)
Definition: validation.py:959
def pileupEnabled(self)
Definition: validation.py:344
def _findDuplicates(lst)
Definition: validation.py:973
def _copySubDir(oldfile, newfile, basenames, dirname)
Definition: validation.py:924
def _doPhase2PileupPlots(self, limitSubFoldersOnlyTo, htmlReport)
Definition: validation.py:637
def scenario(self)
Definition: validation.py:380
def doPlots(self, plotter, plotterDrawArgs={}, limitSubFoldersOnlyTo=None, htmlReport=html.HtmlReportDummy(), doFastVsFull=True, doPhase2PU=False)
Definition: validation.py:564
def pileup(self)
Definition: validation.py:348
def fastsimCorrespondingFullsimPileup(self)
Definition: validation.py:397
def fastsim(self)
Definition: validation.py:389
def createHtmlReport(self)
Definition: validation.py:561
def _doPlotsForPlotter(self, plotter, sample, limitSubFoldersOnlyTo=None)
Definition: validation.py:1062
def __init__(self, samples, newdir)
Definition: validation.py:1024
double split
Definition: MVATrainer.cc:139
def _getRefFileAndSelection(self, sample, plotterFolder, dqmSubFolder, selectionNameBase, valname)
Definition: validation.py:672
def _doPlots(self, sample, harvestedFile, plotterFolder, dqmSubFolder, htmlReport)
Definition: validation.py:714
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger list("!*","!HLTx*"if it matches 2 triggers or more) will accept the event if all the matching triggers are FAIL.It will reject the event if any of the triggers are PASS or EXCEPTION(this matches the behavior of"!*"before the partial wildcard feature was incorporated).Triggers which are in the READY state are completely ignored.(READY should never be returned since the trigger paths have been run
def overrideGlobalTag(self)
Definition: validation.py:386