ATLAS Offline Software
Loading...
Searching...
No Matches
DumpGeoConfig.py
Go to the documentation of this file.
1# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3#----------------------------------------------------------------
4# Author: Riccardo Maria BIANCHI <riccardo.maria.bianchi@cern.ch>
5# Initial version: Feb 2024
6#
7# Main updates:
8# - 2025, Feb -- Riccardo Maria BIANCHI <riccardo.maria.bianchi@cern.ch>
9# Added dedicated DumpGeo flags as GeoModel.DumpGeo;
10# also, support the use of DumpGeo transforms and other
11# Athena jobs -- that is, not standalone. This is useful
12# when we want to dump the geometry that comes out as the
13# output of an Athena job.
14#----------------------------------------------------------------
15import os, sys
16
17# Set the CA environment
18from AthenaConfiguration.ComponentAccumulator import (
19 ComponentAccumulator,
20 ConfigurationError,
21)
22from AthenaConfiguration.ComponentFactory import CompFactory
23
24# Set the Athena Logger
25from AthenaCommon.Logging import logging
26_logger = logging.getLogger('DumpGeo')
27
28def configureGeometry(flags, cfg):
29
30 # Beam pipe
31 if flags.Detector.GeometryBpipe:
32 from BeamPipeGeoModel.BeamPipeGMConfig import BeamPipeGeometryCfg
33 cfg.merge(BeamPipeGeometryCfg(flags))
34
35 # Inner Detectors
36 if flags.Detector.GeometryPixel:
37 from PixelGeoModel.PixelGeoModelConfig import PixelReadoutGeometryCfg
38 cfg.merge(PixelReadoutGeometryCfg(flags))
39 # TODO: do we need to set this separately?
40 # if flags.Detector.GeometryBCM:
41
42 if flags.Detector.GeometrySCT:
43 from SCT_GeoModel.SCT_GeoModelConfig import SCT_ReadoutGeometryCfg
44 cfg.merge(SCT_ReadoutGeometryCfg(flags))
45
46 if flags.Detector.GeometryTRT:
47 from TRT_GeoModel.TRT_GeoModelConfig import TRT_ReadoutGeometryCfg
48 cfg.merge(TRT_ReadoutGeometryCfg(flags))
49
50 # InDetServMat
51 # Trigger the build of the InDetServMat geometry
52 # if any ID subsystems have been enabled
53 if flags.Detector.GeometryID:
54 from InDetServMatGeoModel.InDetServMatGeoModelConfig import (
55 InDetServiceMaterialCfg)
56 cfg.merge(InDetServiceMaterialCfg(flags))
57
58 # Calorimeters
59 if flags.Detector.GeometryLAr:
60 from LArGeoAlgsNV.LArGMConfig import LArGMCfg
61 cfg.merge(LArGMCfg(flags))
62
63 if flags.Detector.GeometryTile:
64 from TileGeoModel.TileGMConfig import TileGMCfg
65 #flags.Tile.forceFullGeometry = True
66 cfg.merge(TileGMCfg(flags))
67 # We must set the "FULL" geometry explicitly, otherwise the "RECO" version will be used by default,
68 # which is almost 'empty' (just the first level of child volumes is created for the "RECO" geo).
69 cfg.getService("GeoModelSvc").DetectorTools["TileDetectorTool"].GeometryConfig="FULL"
70 # TODO: do we need to set this separately?
71 # if flags.Detector.GeometryMBTS:
72
73 # Muon spectrometer
74 if flags.Detector.GeometryMuon:
75 from MuonConfig.MuonGeometryConfig import MuonGeoModelCfg
76 cfg.merge(MuonGeoModelCfg(flags))
77
78 # HGTD (defined only for Run4 geometry tags)
79 if flags.Detector.GeometryHGTD:
80 #set up geometry
81 if flags.HGTD.Geometry.useGeoModelXml:
82 from HGTD_GeoModelXml.HGTD_GeoModelConfig import HGTD_SimulationGeometryCfg
83 else:
84 from HGTD_GeoModel.HGTD_GeoModelConfig import HGTD_SimulationGeometryCfg
85 cfg.merge(HGTD_SimulationGeometryCfg(flags))
86
87 # ITk (defined only for Run4 geometry tags)
88 if flags.Detector.GeometryITkPixel:
89 from PixelGeoModelXml.ITkPixelGeoModelConfig import ITkPixelReadoutGeometryCfg
90 cfg.merge(ITkPixelReadoutGeometryCfg(flags))
91 if flags.Detector.GeometryITkStrip:
92 from StripGeoModelXml.ITkStripGeoModelConfig import ITkStripReadoutGeometryCfg
93 cfg.merge(ITkStripReadoutGeometryCfg(flags))
94 # TODO: do we need to set those separately?
95 # if flags.Detector.GeometryBCMPrime:
96 # if flags.Detector.GeometryPLR:
97
98 # Cavern (disabled by default)
99 if flags.Detector.GeometryCavern:
100 from AtlasGeoModel.CavernGMConfig import CavernGeometryCfg
101 cfg.merge(CavernGeometryCfg(flags))
102
103 # Forward detectors (disabled by default)
104 if flags.Detector.GeometryLucid or flags.Detector.GeometryALFA or flags.Detector.GeometryAFP or flags.Detector.GeometryFwdRegion :
105 from AtlasGeoModel.ForDetGeoModelConfig import ForDetGeometryCfg
106 cfg.merge(ForDetGeometryCfg(flags))
107 if flags.Detector.GeometryZDC:
108 from ZDC_GeoM.ZdcGeoModelConfig import ZDC_DetToolCfg
109 cfg.merge(ZDC_DetToolCfg(flags))
110
111 # Temporary 'hack':
112 # Replace EllipticTube with Box,
113 # to bypass a crash due to lack of support
114 # for EllipticTube in GeoModelIO
115 # See: https://its.cern.ch/jira/browse/ATLASSIM-7263
116 if "ForwardRegionGeoModelTool" in cfg.getService("GeoModelSvc").DetectorTools:
117 cfg.getService("GeoModelSvc").DetectorTools["ForwardRegionGeoModelTool"].vp1Compatibility=True
118
119
121 if "AtlasVersion" in os.environ:
122 return os.environ["AtlasVersion"]
123 if "AtlasBaseVersion" in os.environ:
124 return os.environ["AtlasBaseVersion"]
125 return "Unknown"
126
127
129 """Return the configured DumpGeo SQLite output file name."""
130 if flags.GeoModel.DumpGeo.OutputFileName:
131 return flags.GeoModel.DumpGeo.OutputFileName
132
133 output_file = f"geometry-{flags.GeoModel.AtlasVersion}"
134 filter_det_managers = flags.GeoModel.DumpGeo.FilterDetManagers
135 if filter_det_managers:
136 output_file += "-" + "-".join(filter_det_managers)
137
138 return output_file + ".db"
139
140
141def resolveDumpGeoGeometryTag(det_descr, configured_tag, fallback_tag):
142 """Resolve the geometry tag using the DumpGeo command-line precedence."""
143 if det_descr:
144 return det_descr
145 if configured_tag:
146 return configured_tag
147 return fallback_tag
148
149
150def dumpGeoHasInputFiles(input_files):
151 """Return whether standalone DumpGeo was given real input files."""
152 return bool(input_files) and input_files != [
153 "_ATHENA_GENERIC_INPUTFILE_NAME_"
154 ]
155
156
158 """Configure deterministic defaults for an input-less standalone job."""
159 if dumpGeoHasInputFiles(flags.Input.Files):
160 return False
161
162 from Campaigns.Utils import Campaign
163 from AthenaConfiguration.TestDefaults import defaultConditionsTags
164
165 flags.Input.Files = []
166
167 # MainServicesCfg and detector configuration require these normally
168 # metadata-derived flags to be initialized for an input-less job.
169 flags.Input.ProjectName = "mc23_13p6TeV"
170 flags.Input.RunNumbers = [330000]
171 flags.Input.TimeStamps = [1]
172 flags.Input.TypedCollections = []
173 flags.IOVDb.GlobalTag = defaultConditionsTags.RUN3_MC
174 flags.Input.isMC = True
175 flags.Input.MCCampaign = Campaign.Unknown
176 return True
177
178
179def validateDumpGeoOutputFile(output_file, force_overwrite):
180 """Reject an existing output file unless overwrite is enabled."""
181 if os.path.exists(output_file) and not force_overwrite:
182 raise ConfigurationError(
183 f"DumpGeo output file '{output_file}' already exists. "
184 "Move or remove it, or enable "
185 "'GeoModel.DumpGeo.ForceOverwrite' "
186 "(or use the '-f' option from the command line)."
187 )
188
189
190def logZDCFailureReminder(zdc_enabled, run_succeeded):
191 """Remind standalone users about ZDC diagnostics after a failed run."""
192 if zdc_enabled and not run_succeeded:
193 _logger.error(
194 "DumpGeo failed while ZDC geometry was enabled. Check the "
195 "preceding ZDC_DetTool messages: the selected geometry tag "
196 "may not contain ZDC geometry information."
197 )
198
199
200def DumpGeoCfg(flags, name="DumpGeoAlg", **kwargs):
201 if _logger.isEnabledFor(logging.DEBUG):
202 _logger.debug(
203 "Dumping the 'GeoModel.DumpGeo' configuration flags:"
204 )
205 flags.dump("GeoModel.DumpGeo")
206
207 # Debug messages
208 _logger.debug("kwargs: %s", kwargs)
209
210 # set additional DumpGeo Alg's properties
211 _logger.verbose("Using ATLAS/Athena version: %s", getATLASVersion())
212 _logger.verbose("Using GeoModel ATLAS version: %s", flags.GeoModel.AtlasVersion)
213 kwargs.setdefault("AtlasRelease", getATLASVersion())
214 kwargs.setdefault("AtlasVersion", flags.GeoModel.AtlasVersion)
215
216 # Set the user's choice to see the content of the Treetops
217 if flags.GeoModel.DumpGeo.ShowTreetopContent:
218 kwargs.setdefault("ShowTreetopContent", True)
219
220 # Configure DetectorManager filtering independently of the output file
221 # name. In particular, a user-defined file name must not disable the
222 # filter passed to the C++ algorithm.
223 filterDetManagers = flags.GeoModel.DumpGeo.FilterDetManagers
224 if filterDetManagers:
225 _logger.info(
226 "+++ Filtering on these GeoModel 'Detector Managers': '%s'",
227 filterDetManagers,
228 )
229 kwargs.setdefault("UserFilterDetManager", filterDetManagers)
230
231 # Set the name of the output '.db' file.
232 configuredOutFileName = dumpGeoOutputFileName(flags)
233 if not flags.GeoModel.DumpGeo.OutputFileName:
234 _logger.info(
235 "+++ Dumping this Detector Description geometry TAG: '%s'",
236 flags.GeoModel.AtlasVersion,
237 )
238
239 # Set the output file name variable in the C++ code
240 kwargs.setdefault("OutSQLiteFileName", configuredOutFileName)
241
242 # The final algorithm property is authoritative. A caller can override the
243 # flag-derived filename through kwargs, so validation and deletion must use
244 # the same path that the C++ algorithm will write.
245 outFileName = kwargs["OutSQLiteFileName"]
246 kwargs.setdefault(
247 "ForceOverwrite",
248 flags.GeoModel.DumpGeo.ForceOverwrite,
249 )
250 forceOverwrite = kwargs["ForceOverwrite"]
251
252 # Reject an existing file unless overwrite is enabled. Destructive removal
253 # is deliberately deferred to DumpGeo::initialize(), immediately before
254 # the C++ algorithm opens the output database.
256 outFileName,
257 forceOverwrite,
258 )
259
260 # Schedule the DumpGeo Athena Algorithm
261 result = ComponentAccumulator()
262 the_alg = CompFactory.DumpGeo(name=name, **kwargs)
263 result.addEventAlgo(the_alg, primary=True)
264 return result
265
266
267if __name__=="__main__":
268 # Run with e.g. python -m DumpGeo.DumpGeoConfig --detDescr=<ATLAS-geometry-tag> --filterDetManagers=[<list of tree tops>]
269
270 from AthenaConfiguration.TestDefaults import defaultGeometryTags
271
272 # ++++ Firstly we setup flags ++++
273 # +++ Set the Athena Flags
274 from AthenaConfiguration.AllConfigFlags import initConfigFlags
275 flags = initConfigFlags()
276
277 flags.Exec.MaxEvents = 0
278 # ^ We do not need any events to get the GeoModel tree from the GeoModelSvc.
279 # So, we don't need to run on any events,
280 # and we don't need to trigger any execute() Athena methods either.
281 # So, we set 'EvtMax' to 0 and Athena will skip the 'execute' phase;
282 # only the 'finalize' step will be run after the 'init'.
283 # -- Note:
284 # Also, if we run on events (even on 1 event) and we dump the Pixel
285 # as part of the DetectorManager filter, then we get a crash because
286 # the PixelDetectorManager complains during the 'execute' phase,
287 # because we 'stole' a handle on its TreeTop,
288 # which contains a FullPhysVol and cannot be shared.
289
290 flags.Concurrency.NumThreads = 0
291 # ^ DumpGeo will not work with the scheduler, since its condition/data dependencies are not known in advance
292 # More in details: the scheduler needs to know BEFORE the event, what the dependencies of each Alg are.
293 # So for DumpGeo, no dependencies are declared, which means the conditions data is not there.
294 # So when I load tracks, the geometry is missing and it crashes.
295 # Turning off the scheduler (with NumThreads=0) fixes this.
296
297 # +++ Set custom CLI parameters for DumpGeo when ran as a standalone program
298 # (that is, from the command line,
299 # and not as part of an Athena Transform or job)
300 parser = flags.getArgumentParser(description="Dump the detector geometry to a GeoModel-based SQLite '.db' file.")
301 parser.prog = 'dump-geo'
302 # here we extend the parser with CLI options specific to DumpGeo
303 parser.add_argument(
304 "--detDescr",
305 default=None,
306 help=(
307 "Override the ATLAS geometry tag. This is a convenience alias "
308 "for 'GeoModel.AtlasVersion=TAG'. If omitted, the generic flag "
309 "or input-file metadata is used."
310 ),
311 metavar="TAG",
312 )
313 parser.add_argument("--outFilename", default="",
314 help="Here you can set a custom name for the output '.db' file. It will replace the name that is built with the geometry tag and the list of filtered Detector Managers, if any.", metavar="FILENAME")
315 # parser.add_argument("--filterTreeTops", help="Only output the GeoModel Tree Tops specified in the FILTER list; input is a comma-separated list")
316 parser.add_argument("--filterDetManagers", help="Only output the GeoModel Detector Managers specified in the FILTER list; input is a comma-separated list")
317 parser.add_argument("-f", "--forceOverwrite",
318 help="Force to overwrite an existing SQLite output file with the same name, if any", action = 'store_true')
319 parser.add_argument("--showTreetopContent",
320 help="Show the content of the Treetops --- (by default, only the list of Treetops is shown)", action = 'store_true')
321 parser.add_argument("--debugCA", help="Debug the CA configuration: print flags, tools, ... --- mainly, for DumpGeo developers. '1' prints a subset of the CA flags, '2' prints all of them.")
322
323 args = flags.fillFromArgs(parser=parser)
324
325 # +++ Get CLI parameters and set the corresponding configuration flags
326 # Get the user's custom file name, if set;
327 # this will replace the filename computed
328 # from the geometry tag and the filtered volumes
329 if args.outFilename:
330 flags.GeoModel.DumpGeo.OutputFileName = args.outFilename
331 if args.filterDetManagers:
332 flags.GeoModel.DumpGeo.FilterDetManagers = [
333 manager.strip()
334 for manager in args.filterDetManagers.split(",")
335 if manager.strip()
336 ]
337 if args.showTreetopContent:
338 flags.GeoModel.DumpGeo.ShowTreetopContent = True
339 if args.forceOverwrite:
340 flags.GeoModel.DumpGeo.ForceOverwrite = True
341
342 # Athena uses a placeholder as the default Input.Files value. Treat that
343 # placeholder, as well as an explicitly empty list, as a genuine
344 # input-less job. In particular, do not replace it with a test EVNT file:
345 # standalone geometry dumping must not depend on CVMFS or on unrelated
346 # event-file metadata.
347 dumpgeo_empty_input = configureDumpGeoInputFlags(flags)
348
349 # A custom filename is already final and can be checked without resolving
350 # the geometry tag, which may otherwise require a metadata lookup.
351 if flags.GeoModel.DumpGeo.OutputFileName:
353 flags.GeoModel.DumpGeo.OutputFileName,
354 flags.GeoModel.DumpGeo.ForceOverwrite,
355 )
356
357 # Resolve the geometry tag with this precedence: an explicit --detDescr,
358 # the generic GeoModel.AtlasVersion flag (including its metadata-derived
359 # value), then the standalone Run-3 fallback. Avoid evaluating the generic
360 # flag when --detDescr was supplied, since doing so may trigger an
361 # unnecessary metadata lookup.
362 configured_geometry_tag = None
363 if not args.detDescr:
364 configured_geometry_tag = flags.GeoModel.AtlasVersion
366 args.detDescr,
367 configured_geometry_tag,
368 defaultGeometryTags.RUN3,
369 )
370 if args.detDescr:
371 _logger.verbose(
372 "+ About to set this detector description tag: '%s'",
373 args.detDescr,
374 )
375 flags.GeoModel.AtlasVersion = geometry_tag
376 _logger.verbose("+ Using detector description tag: '%s'", geometry_tag)
377
378 from MuonConfig.MuonConfigUtils import configureCondTag
379 configureCondTag(flags)
380
381 # Fail as soon as the final geometry tag is known and before detector or
382 # geometry configuration. Resolving a metadata-derived tag necessarily
383 # performs the metadata lookup first. This check deliberately does not
384 # delete an existing file when force overwrite is enabled; deletion is
385 # deferred to the C++ algorithm's initialize() method.
388 flags.GeoModel.DumpGeo.ForceOverwrite,
389 )
390
391 # +++ Set the empty input
392 _logger.verbose("+ About to set flags related to the input")
393
394 # Empty input is not normal for Athena, so we will need to check
395 # this repeatedly below (the same as with VP1)
396 dumpgeo_empty_input = False
397
398 # This covers the use case where we launch DumpGeo
399 # without input files; e.g., to check the detector description
400 from AthenaConfiguration.AutoConfigFlags import GetFileMD
401
402 input_metadata = GetFileMD(flags.Input.Files)
403 input_geometry_tag = input_metadata.get("GeoAtlas", None)
404
405 # Treat both None and an empty string as a missing geometry tag.
406 dumpgeo_empty_input = (
407 len(flags.Input.Files) == 0 or not input_geometry_tag
408 )
409
410 if dumpgeo_empty_input:
411 from Campaigns.Utils import Campaign
412 from AthenaConfiguration.TestDefaults import (
413 defaultConditionsTags,
414 defaultGeometryTags
415 )
416
417 # NB Must set e.g. ConfigFlags.Input.Runparse_args() Number and
418 # ConfigFlags.Input.TimeStamp before calling the
419 # MainServicesCfg to avoid it attempting auto-configuration
420 # from an input file, which is empty in this use case.
421 # If you don't have it, it (and/or other Cfg routines) complains and crashes.
422 # See also:
423 # https://acode-browser1.usatlas.bnl.gov/lxr/source/athena/InnerDetector/InDetConditions/SCT_ConditionsAlgorithms/python/SCT_DCSConditionsTestAlgConfig.py#0023
424 flags.Input.ProjectName = "mc23_13p6TeV"
425 flags.Input.RunNumbers = [330000]
426 flags.Input.TimeStamps = [1]
427 flags.Input.TypedCollections = []
428
429 # set default CondDB and Geometry version
430 flags.IOVDb.GlobalTag = defaultConditionsTags.RUN3_MC
431 flags.Input.isMC = True
432 flags.Input.MCCampaign = Campaign.Unknown
433
434 _logger.verbose("+ ... Done")
435 _logger.verbose("+ empty input: '%s'", dumpgeo_empty_input)
436
437
438 # +++ Set the detector geometry
439 _logger.verbose("+ About to set the detector flags")
440 # So we can now set up the geometry flags from the input
441 from AthenaConfiguration.DetectorConfigFlags import setupDetectorFlags
442 setupDetectorFlags(
443 flags,
444 None,
445 use_metadata=not dumpgeo_empty_input,
446 toggle_geometry=True,
447 keep_beampipe=True
448 )
449 _logger.verbose("+ ... Done")
450
451 # finalize setting flags: lock them.
452 flags.lock()
453
454 # ++++ Now we setup the actual configuration ++++
455 _logger.verbose("+ Setup main services")
456 from AthenaConfiguration.MainServicesConfig import MainServicesCfg
457 cfg = MainServicesCfg(flags)
458 _logger.verbose("+ ...Done")
459
460 _logger.verbose("+ About to setup geometry")
461 configureGeometry(flags,cfg)
462 _logger.verbose("+ ...Done")
463
464 # debug messages
465 if args.debugCA:
466 debugCAlevel = int(args.debugCA)
467 if debugCAlevel >= 1:
468 _logger.verbose("Debug --- printing flags...")
469 print("\nflags:", flags)
470 for fl in flags:
471 print("fl:", fl)
472 print("\nflags.Tile:", flags.Tile)
473 for fl in flags.Tile:
474 print("fl.Tile:", fl)
475 print(dir(cfg))
476 print("cfg._privateTools: ", cfg._privateTools)
477 print("cfg._publicTools: ", cfg._publicTools)
478 if debugCAlevel >= 2:
479 flags.dump()
480 flags._loadDynaFlags('GeoModel')
481 flags._loadDynaFlags('Detector')
482 flags.dump('Detector.(Geometry|Enable)', True)
483 if debugCAlevel >= 1:
484 _logger.verbose("We're in a debugCA session, flags have been printed out, now exiting...")
485 sys.exit()
486
487 # +++ Configure DumpGeo and run
488 cfg.merge(DumpGeoCfg(flags))
489 status = cfg.run()
490
492 flags.Detector.GeometryZDC,
493 status.isSuccess(),
494 )
495
496 sys.exit(not status.isSuccess())
void print(char *figname, TCanvas *c1)
configureDumpGeoInputFlags(flags)
DumpGeoCfg(flags, name="DumpGeoAlg", **kwargs)
dumpGeoOutputFileName(flags)
resolveDumpGeoGeometryTag(det_descr, configured_tag, fallback_tag)
dumpGeoHasInputFiles(input_files)
configureGeometry(flags, cfg)
logZDCFailureReminder(zdc_enabled, run_succeeded)
validateDumpGeoOutputFile(output_file, force_overwrite)