CMS 3D CMS Logo

generateGeometry.py
Go to the documentation of this file.
1 from __future__ import print_function
2 from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, RawTextHelpFormatter, RawDescriptionHelpFormatter
3 import sys, os, operator
4 from pprint import pprint
5 import filecmp
6 
7 # convenience definition
8 # (from ConfigArgParse)
10  ArgumentDefaultsHelpFormatter,
11  RawTextHelpFormatter,
12  RawDescriptionHelpFormatter):
13  """HelpFormatter that adds default values AND doesn't do line-wrapping"""
14 pass
15 
17  def __init__(self, scriptName, detectorVersionDefault, detectorPrefix, detectorYear, maxSections, allDicts, detectorVersionDict, deprecatedDets = None, deprecatedSubdets = None, detectorVersionType = int):
18  self.scriptName = scriptName
19  self.detectorVersionDefault = detectorVersionDefault
20  self.detectorPrefix = detectorPrefix
21  self.detectorYear = detectorYear
22  self.maxSections = maxSections
23  self.allDicts = allDicts
24  self.detectorVersionDict = detectorVersionDict
25  self.deprecatedDets = deprecatedDets
26  self.deprecatedSubdets = deprecatedSubdets
27  self.detectorVersionType = detectorVersionType
29  self.dd4hepDetectorVersion = 91 #If detectorVersion > 91, add warning to add also DD4hep in Configuration/StandardSequences/python/GeometryConf.py
30 
31  def generateGeom(self, detectorTuple, args):
32  detectorVersion = self.detectorPrefix+str(args.detectorVersionManual)
33  # reverse dict search if overall D# specified
34  if args.v_detector!=self.detectorVersionNull:
35  detectorVersion = self.detectorPrefix+str(args.v_detector)
36  if detectorVersion in self.detectorVersionDict.values():
37  detectorTuple = list(self.detectorVersionDict.keys())[list(self.detectorVersionDict.values()).index(detectorVersion)]
38  else:
39  print("Unknown detector "+detectorVersion)
40  sys.exit(1)
41  elif detectorTuple in self.detectorVersionDict.keys():
42  detectorVersion = self.detectorVersionDict[detectorTuple]
43  else:
44  if not args.doTest: print("Detector "+str(detectorTuple)+" not found in dictionary, using "+("default" if args.detectorVersionManual==self.detectorVersionDefault else "provided")+" version number "+str(detectorVersion))
45 
46  # check for deprecation
47  if self.deprecatedDets is not None and detectorVersion in self.deprecatedDets:
48  print("Error: "+detectorVersion+" is deprecated and cannot be used.")
49  sys.exit(1)
50  if self.deprecatedSubdets is not None:
51  for subdet in detectorTuple:
52  if subdet in self.deprecatedSubdets:
53  print("Error: "+subdet+" is deprecated and cannot be used.")
54  sys.exit(1)
55 
56  # create output files
57  xmlName = "cmsExtendedGeometry"+self.detectorYear+detectorVersion+"XML_cfi.py"
58  xmlDD4hepName = "cmsExtendedGeometry"+self.detectorYear+detectorVersion+".xml"
59  simName = "GeometryExtended"+self.detectorYear+detectorVersion+"_cff.py"
60  simDD4hepName = "GeometryDD4hepExtended"+self.detectorYear+detectorVersion+"_cff.py"
61  recoName = "GeometryExtended"+self.detectorYear+detectorVersion+"Reco_cff.py"
62  recoDD4hepName = "GeometryDD4hepExtended"+self.detectorYear+detectorVersion+"Reco_cff.py"
63 
64  # check directories
65  CMSSWBASE = os.getenv("CMSSW_BASE")
66  CMSSWRELBASE = os.getenv("CMSSW_RELEASE_BASE")
67  if CMSSWBASE is None: CMSSWBASE = ""
68  xmlDir = os.path.join(CMSSWBASE,"src","Geometry","CMSCommonData","python")
69  xmlDD4hepDir = os.path.join(CMSSWBASE,"src","Geometry","CMSCommonData","data","dd4hep")
70  simrecoDir = os.path.join(CMSSWBASE,"src","Configuration","Geometry","python")
71  simrecoDD4hepDir = os.path.join(CMSSWBASE,"src","Configuration","Geometry","python")
72  if args.doTest:
73  if not os.path.isdir(xmlDir):
74  xmlDir = os.path.join(CMSSWRELBASE,"src","Geometry","CMSCommonData","python")
75  xmlDD4hepDir = os.path.join(CMSSWRELBASE,"src","Geometry","CMSCommonData","data","dd4hep")
76  else:
77  mvCommands = ""
78  if not os.path.isdir(xmlDir):
79  mvCommands += "mv "+xmlName+" "+xmlDir+"/\n"
80  else:
81  xmlName = os.path.join(xmlDir,xmlName)
82  if not os.path.isdir(xmlDD4hepDir):
83  mvCommands += "mv "+xmlDD4hepName+" "+xmlDD4hepDir+"/\n"
84  else:
85  xmlDD4hepName = os.path.join(xmlDD4hepDir,xmlDD4hepName)
86  if not os.path.isdir(simrecoDir):
87  mvCommands += "mv "+simName+" "+simrecoDir+"/\n"
88  mvCommands += "mv "+recoName+" "+simrecoDir+"/\n"
89  else:
90  simName = os.path.join(simrecoDir,simName)
91  recoName = os.path.join(simrecoDir,recoName)
92  if not os.path.isdir(simrecoDD4hepDir):
93  mvCommands += "mv "+simDD4hepName+" "+simrecoDD4hepDir+"/\n"
94  mvCommands += "mv "+recoDD4hepName+" "+simrecoDD4hepDir+"/\n"
95  else:
96  simDD4hepName = os.path.join(simrecoDD4hepDir,simDD4hepName)
97  recoDD4hepName = os.path.join(simrecoDD4hepDir,recoDD4hepName)
98  if len(mvCommands)>0:
99  print("Warning: some geometry packages not checked out.\nOnce they are available, please execute the following commands manually:\n"+mvCommands)
100 
101  # open files
102  xmlFile = open(xmlName,'w')
103  xmlDD4hepFile = open(xmlDD4hepName,'w')
104  simFile = open(simName,'w')
105  simDD4hepFile = open(simDD4hepName,'w')
106  recoFile = open(recoName,'w')
107  recoDD4hepFile = open(recoDD4hepName,'w')
108 
109  # common preamble
110  preamble = "import FWCore.ParameterSet.Config as cms"+"\n"+"\n"
111  preamble += "# This config was generated automatically using "+self.scriptName+"\n"
112  preamble += "# If you notice a mistake, please update the generating script, not just this config"+"\n"+"\n"
113 
114  # create XML config
115  xmlFile.write(preamble)
116  # extra preamble
117  xmlFile.write("XMLIdealGeometryESSource = cms.ESSource(\"XMLIdealGeometryESSource\","+"\n")
118  xmlFile.write(" geomXMLFiles = cms.vstring("+"\n")
119  for section in range(1,self.maxSections+1):
120  # midamble
121  if section==2:
122  xmlFile.write(" )+"+"\n"+" cms.vstring("+"\n")
123  for iDict,aDict in enumerate(self.allDicts):
124  if section in aDict[detectorTuple[iDict]].keys():
125  xmlFile.write('\n'.join([ " '"+aLine+"'," for aLine in aDict[detectorTuple[iDict]][section] ])+"\n")
126  # postamble
127  xmlFile.write(" ),"+"\n"+" rootNodeName = cms.string('cms:OCMS')"+"\n"+")"+"\n")
128  xmlFile.close()
129 
130  # create DD4hep XML config
131  xmlDD4hepFile.write("<?xml version=\"1.0\"?>\n"+
132  "<DDDefinition>\n"+
133  " <open_geometry/>\n"+
134  " <close_geometry/>\n"+
135  "\n"+
136  " <IncludeSection>\n")
137  for section in range(1,self.maxSections+1):
138  # midamble
139  for iDict,aDict in enumerate(self.allDicts):
140  if section in aDict[detectorTuple[iDict]].keys():
141  xmlDD4hepFile.write('\n'.join([ " <Include ref='"+aLine+"'/>" for aLine in aDict[detectorTuple[iDict]][section] ])+"\n")
142  # postamble
143  xmlDD4hepFile.write(" </IncludeSection>\n"+
144  "</DDDefinition>"+"\n")
145  xmlDD4hepFile.close()
146 
147  # create sim config
148  simFile.write(preamble)
149  # always need XML
150  simFile.write("from Geometry.CMSCommonData."+os.path.basename(xmlName).replace(".py","")+" import *"+"\n")
151  for iDict,aDict in enumerate(self.allDicts):
152  if "sim" in aDict[detectorTuple[iDict]].keys():
153  simFile.write('\n'.join([ aLine for aLine in aDict[detectorTuple[iDict]]["sim"] ])+"\n")
154  simFile.close()
155 
156  # create simDD4hep config
157  simDD4hepFile.write(preamble)
158  # always need XML
159  simDD4hepFile.write("from Configuration.Geometry.GeometryDD4hep_cff"+" import *"+"\n")
160  simDD4hepFile.write("DDDetectorESProducer.confGeomXMLFiles = cms.FileInPath(\"Geometry/CMSCommonData/data/dd4hep/"+os.path.basename(xmlDD4hepName)+"\")\n\n")
161  for iDict,aDict in enumerate(self.allDicts):
162  if "sim" in aDict[detectorTuple[iDict]].keys():
163  simDD4hepFile.write('\n'.join([ aLine for aLine in aDict[detectorTuple[iDict]]["sim"] ])+"\n")
164  simDD4hepFile.close()
165 
166  # create reco config
167  recoFile.write(preamble)
168  # always need sim
169  recoFile.write("from Configuration.Geometry."+os.path.basename(simName).replace(".py","")+" import *"+"\n\n")
170  for iDict,aDict in enumerate(self.allDicts):
171  if "reco" in aDict[detectorTuple[iDict]].keys():
172  recoFile.write("# "+aDict["name"]+"\n")
173  recoFile.write('\n'.join([ aLine for aLine in aDict[detectorTuple[iDict]]["reco"] ])+"\n\n")
174  recoFile.close()
175 
176  # create recoDD4hep config
177  recoDD4hepFile.write(preamble)
178  # always need sim
179  recoDD4hepFile.write("from Configuration.Geometry."+os.path.basename(simDD4hepName).replace(".py","")+" import *"+"\n\n")
180  for iDict,aDict in enumerate(self.allDicts):
181  if "reco" in aDict[detectorTuple[iDict]].keys():
182  recoDD4hepFile.write("# "+aDict["name"]+"\n")
183  recoDD4hepFile.write('\n'.join([ aLine for aLine in aDict[detectorTuple[iDict]]["reco"] ])+"\n\n")
184  recoDD4hepFile.close()
185 
186  from Configuration.StandardSequences.GeometryConf import GeometryConf
187  if not args.doTest: # todo: include these in unit test somehow
188  # specify Era customizations
189  # must be checked manually in:
190  # Configuration/StandardSequences/python/Eras.py
191  # Configuration/Eras/python/
192  # Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py (workflow definitions)
193  eraLine = ""
194  eraLineItems = []
195  for iDict,aDict in enumerate(self.allDicts):
196  if "era" in aDict[detectorTuple[iDict]].keys():
197  eraLineItems.append(aDict[detectorTuple[iDict]]["era"])
198  eraLine += ", ".join([ eraLineItem for eraLineItem in eraLineItems ])
199  print("The Era for this detector should contain:")
200  print(eraLine)
201 
202  # specify GeometryConf
203  if not 'Extended'+self.detectorYear+detectorVersion in GeometryConf.keys():
204  print("Please add this line in Configuration/StandardSequences/python/GeometryConf.py:")
205  print(" 'Extended"+self.detectorYear+detectorVersion+"' : 'Extended"+self.detectorYear+detectorVersion+",Extended"+self.detectorYear+detectorVersion+"Reco',")
206  if self.detectorYear == "2026" and int(args.v_detector) > self.dd4hepDetectorVersion:
207  print(" 'DD4hepExtended"+self.detectorYear+detectorVersion+"' : 'DD4hepExtended"+self.detectorYear+detectorVersion+",DD4hepExtended"+self.detectorYear+detectorVersion+"Reco',")
208 
209  errorList = []
210 
211  if args.doTest:
212  # tests for Configuration/Geometry
213  simFile = os.path.join(simrecoDir,simName)
214  if not os.path.isfile(simFile):
215  errorList.append(simName+" missing")
216  elif not filecmp.cmp(simName,simFile):
217  errorList.append(simName+" differs")
218  simDD4hepFile = os.path.join(simrecoDD4hepDir,simDD4hepName)
219  if not os.path.isfile(simDD4hepFile):
220  errorList.append(simDD4hepName+" missing")
221  elif not filecmp.cmp(simDD4hepName,simDD4hepFile):
222  errorList.append(simDD4hepName+" differs")
223  recoFile = os.path.join(simrecoDir,recoName)
224  if not os.path.isfile(recoFile):
225  errorList.append(recoName+" missing")
226  elif not filecmp.cmp(recoName,recoFile):
227  errorList.append(recoName+" differs")
228  recoDD4hepFile = os.path.join(simrecoDD4hepDir,recoDD4hepName)
229  if not os.path.isfile(recoDD4hepFile):
230  errorList.append(recoDD4hepName+" missing")
231  elif not filecmp.cmp(recoDD4hepName,recoDD4hepFile):
232  errorList.append(recoDD4hepName+" differs")
233  # test for Configuration/StandardSequences
234  if not 'Extended'+self.detectorYear+detectorVersion in GeometryConf.keys():
235  errorList.append('Extended'+self.detectorYear+detectorVersion+" missing from GeometryConf")
236  # test for Geometry/CMSCommonData
237  xmlFile = os.path.join(xmlDir,xmlName)
238  if not os.path.isfile(xmlFile):
239  errorList.append(xmlName+" missing")
240  elif not filecmp.cmp(xmlName,xmlFile):
241  errorList.append(xmlName+" differs")
242  # test for dd4hep xml
243  xmlDD4hepFile = os.path.join(xmlDD4hepDir,xmlDD4hepName)
244  if not os.path.exists(xmlDD4hepFile):
245  errorList.append(xmlDD4hepName+" differs")
246  elif not filecmp.cmp(xmlDD4hepName,xmlDD4hepFile):
247  errorList.append(xmlDD4hepName+" differs")
248  return errorList
249 
250  def run(self):
251  # define options
252  parser = ArgumentParser(formatter_class=ArgumentDefaultsRawHelpFormatter)
253  for aDict in self.allDicts:
254  parser.add_argument("-"+aDict["abbrev"], "--"+aDict["name"], dest="v_"+aDict["name"], default=aDict["default"], type=int, help="version for "+aDict["name"])
255  parser.add_argument("-V", "--version", dest="detectorVersionManual", default=self.detectorVersionDefault, type=int, help="manual detector version number")
256  parser.add_argument("-D", "--detector", dest="v_detector", default=self.detectorVersionNull, type=self.detectorVersionType, help="version for whole detector, ignored if 0, overrides subdet versions otherwise")
257  parser.add_argument("-l", "--list", dest="doList", default=False, action="store_true", help="list known detector versions and exit")
258  parser.add_argument("-t", "--test", dest="doTest", default=False, action="store_true", help="enable unit test mode")
259  args = parser.parse_args()
260 
261  # check options
262  if args.doList and not args.doTest:
263  pprint(sorted(self.detectorVersionDict.items(),key=operator.itemgetter(1)))
264  sys.exit(0)
265  elif args.doTest:
266  # list of errors
267  errorList = []
268  # run all known possibilities
269  for detectorTuple in self.detectorVersionDict:
270  errorTmp = self.generateGeom(detectorTuple,args)
271  errorList.extend(errorTmp)
272  if len(errorList)>0:
273  print('\n'.join([anError for anError in errorList]))
274  sys.exit(1)
275  else:
276  sys.exit(0)
277  else:
278  detectorTuple = tuple([aDict["abbrev"]+str(getattr(args,"v_"+aDict["name"])) for aDict in self.allDicts])
279  self.generateGeom(detectorTuple,args)
280  sys.exit(0)
281 
def replace(string, replacements)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:47
static std::string join(char **cmd)
Definition: RemoteFile.cc:19
def __init__(self, scriptName, detectorVersionDefault, detectorPrefix, detectorYear, maxSections, allDicts, detectorVersionDict, deprecatedDets=None, deprecatedSubdets=None, detectorVersionType=int)
#define str(s)
def generateGeom(self, detectorTuple, args)