###############################################################################
# (c) Copyright 2000-2022 CERN for the benefit of the LHCb Collaboration #
# #
# This software is distributed under the terms of the GNU General Public #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". #
# #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
###############################################################################
__author__ = "Gloria Corti, Dominik Muller, and Michal Mazurek"
__email__ = "lhcb-simulation@cern.ch"
from Gaudi.Configuration import Configurable, log
from GaudiConf.SimConf import SimConf
from GaudiKernel import SystemOfUnits
from Gauss.Generation import GaussGeneration
from Gauss.Geometry import GaussGeometry
from Gauss.Simulation import GaussSimulation
from Gaussino.Configuration import Gaussino
# Configurables (do NOT use 'from Configurables' here)
from Gaussino.Utilities import GaussinoConfigurable
from LHCbAlgs.Configuration import LHCbApp
[docs]class Gauss(GaussinoConfigurable):
__used_configurables__ = [
LHCbApp,
SimConf,
GaussGeneration,
GaussSimulation,
GaussGeometry,
Gaussino,
]
__slots__ = {
"Histograms": "DEFAULT",
"EvtMax": -1,
"Phases": ["Generator", "Simulation"],
"EnableHive": True,
"ThreadPoolSize": 1,
"EventSlots": 1,
"FirstTimingEvent": 1,
"DatasetName": "Gauss",
"OutputType": "SIM",
"ReDecay": False,
"Debug": False,
"SpilloverPaths": [],
"EnablePack": True,
"DataType": "",
"WriteFSR": False,
"MergeGenFSR": False,
"FirstEventNumber": 1,
"RunNumber": 1,
}
# options to be directly propagated to Gaussino
GAUSSINO_OPTIONS = [
"Histograms",
"EvtMax",
"Phases",
"EnableHive",
"ThreadPoolSize",
"EventSlots",
"FirstTimingEvent",
"DatasetName",
"OutputType",
"ReDecay",
"Debug",
"FirstEventNumber",
"RunNumber",
]
# options to be directly propagated to LHCbApp
LHCBAPP_OPTIONS = [
# TODO: investigate this!
# I think this should be passed only to Gaussino
"EvtMax",
"DataType",
]
SIMCONF_OPTIONS = [
"SpilloverPaths",
"EnablePack",
"Phases",
"DataType",
]
Run1DataTypes = ["2009", "2010", "2011", "2012", "2013"]
Run2DataTypes = ["2015", "2016", "2017", "2018"]
Run3DataTypes = ["2022", "2023", "2024", "Run3"]
Run4DataTypes = ["Run4"]
Run5DataTypes = ["Run5"]
DataTypes = [
*Run1DataTypes,
*Run2DataTypes,
*Run3DataTypes,
*Run4DataTypes,
*Run5DataTypes,
]
KNOWN_OUTPUTS = ["NONE", "GEN", "XGEN", "RGEN", "SIM", "XSIM"]
def __init__(self, name=Configurable.DefaultName, _enabled=True, **kwargs):
# -> the following makes sure that one does not instantiate Gaussino before
# Gauss, otherwise the later in the code fix will be ill-formed
if "Gaussino" in Configurable.allConfigurables:
msg = "Gauss configurable must be instantiated before Gaussino"
log.error(msg)
raise RuntimeError(msg)
# -> this makes the Gaussino configurable LHCbApp-dependent
# -> explanation: in some cases different configurables have to be instantiated
# with the same name (e.g. HiveWhiteBoard and EventDataSvc);
# -> this makes sure that IOHelper via LHCbApp will not set the defaults before
# Gaussino.__apply_configuration__ takes place
Gaussino.__used_configurables__.append(LHCbApp)
# -> end of the fix
super(Gauss, self).__init__(name=name, _enabled=_enabled, **kwargs)
# Apply the configuration
[docs] def __apply_configuration__(self):
self._check_options_compatibility()
self._propagate_gaussino()
self._propagate_lhcbapp()
packing = self._set_packing()
self._propagate_sim_conf(packing)
self._propagate_simulation()
self._set_evtgen()
self._define_output(prerequisites=[packing])
for conf in self.__used_configurables__:
conf()
[docs] def _check_options_compatibility(self):
if not self.getProp("DataType"):
msg = "Must have a DataType."
log.error(msg)
raise ValueError(msg)
if self.getProp("DataType") not in self.DataTypes:
msg = (
f"Unknown DataType '{self.getProp('DataType')}'. "
f"Must be one of: '{self.DataTypes}'"
)
log.error(msg)
raise ValueError(msg)
for conf, props in Configurable.allConfigurables.items():
if conf.startswith("Gaussino") and props._enabled:
msg = (
"When using Gauss, you must set "
"Gaussino's properties through "
"the corresponding configurable "
"in Gauss. Setting Gaussino's options "
"directly has been disabled."
)
log.error(msg)
raise RuntimeError(msg)
[docs] def _propagate_gaussino(self):
self.propagateProperties(self.GAUSSINO_OPTIONS, Gaussino())
Gaussino().ConvertEDM = True
# FIXME: temporary! we have to wait for an official way of getting ParticleTable.txt
# in the meantime, we use the internal ParticleTable.txt in Gaussino
# see: https://gitlab.cern.ch/lhcb/LHCb/-/merge_requests/3510#note_5530125
#
# Gaussino().ParticleTable = 'git:///param/ParticleTable.txt'
[docs] def _propagate_lhcbapp(self):
self.propagateProperties(self.LHCBAPP_OPTIONS, LHCbApp())
LHCbApp(
Simulation=True,
# do not turn hive mode with LHCbApp
# this is now done in Gaussino() in _setup_hive()
EnableHive=False,
)
[docs] def _set_packing(self):
from Configurables import GaudiSequencer
return GaudiSequencer("PackingSeq", Sequential=True, IgnoreFilterPassed=True)
[docs] def _propagate_sim_conf(self, packing):
# Propagate properties to SimConf
SimConf().setProp("Writer", "GaussTape")
self.propagateProperties(self.SIMCONF_OPTIONS, SimConf())
# Empty the list of detectors, it is later populated when configuring
# the subdetectors
SimConf().Detectors = []
# if we have post-sim filters, we only want to write if the filter is
# passed
# if self.getProp("PostSimFilters"):
# OutputStream("GaussTape").RequireAlgs.append("PostSimFilterSeq")
# Don't want SIM data unpacking enabled in DoD service
SimConf().EnableUnpack = False
SimConf().SaveHepMC = False
phases = self.getProp("Phases")
if "GenToMCTree" in phases or "Simulation" in phases:
for so in self.defineCrossingList():
SimConf().PackingSequencers[so] = packing
[docs] def defineCrossingList(self):
crossingList = [""]
spillOverList = self.getProp("SpilloverPaths")
while "" in spillOverList:
spillOverList.remove("")
crossingList += spillOverList
return crossingList
[docs] def _define_output(self, prerequisites):
"""
Set up output stream according to phase processed,
the spill-over slots and the type of output
"""
output = self.getProp("OutputType").upper()
if output == "NONE":
log.warning("No event data output produced")
return
simWriter = SimConf().writer()
# define default file extensions depending on the phase that has been
# run
fileDefaultExtension = ".gen"
fileAllowedExtension = [fileDefaultExtension]
if "GenToMCTree" in self.getProp("Phases"):
fileDefaultExtension = ".xgen"
fileAllowedExtension = [fileDefaultExtension, ".rgen"]
elif "Simulation" in self.getProp("Phases"):
fileDefaultExtension = ".sim"
fileAllowedExtension = [fileDefaultExtension, ".xsim"]
# choose the file extension from the one selected compatibly with the
# phase run
if output not in self.KNOWN_OUTPUTS:
log.warning(
"OutputType not supported. "
f"Use default for chosen phases: {fileDefaultExtension}"
)
fileExtension = "." + output.lower()
if fileExtension not in fileAllowedExtension:
fileExtension = fileDefaultExtension
log.warning(
"OutputType not supported "
f"for this phase. Use default: {fileExtension}"
)
# set saving or not of HepMC depending on chosen file extension
if SimConf().isPropertySet("SaveHepMC"):
log.warning("SimConf().SaveHepMC will " "be ignored. Value set by Gauss()")
saveHepMC = False
if fileExtension in [".gen", ".xgen", ".xsim"]:
saveHepMC = True
SimConf().setProp("SaveHepMC", saveHepMC)
outputFile = ""
from GaudiConf import IOHelper
if simWriter.isPropertySet("Output"):
outputFile = IOHelper().undressFile(simWriter.getProp("Output"))
else:
outputFile = Gaussino()._get_output_name() + fileExtension
# Merge genFSRs
if self.getProp("WriteFSR"):
seqGenFSR = GaudiSequencer("GenFSRSeq")
ApplicationMgr().TopAlg += [seqGenFSR]
if self.getProp("MergeGenFSR"):
seqGenFSR.Members += ["GenFSRMerge"]
IOHelper().outStream(outputFile, simWriter, self.getProp("WriteFSR"))
from Configurables import FileCatalog
if not FileCatalog().isPropertySet("Catalogs"):
FileCatalog().Catalogs = ["xmlcatalog_file:NewCatalog.xml"]
edm_algos = Gaussino.edm_algorithms(self.getProp("ReDecay"))
members = edm_algos + prerequisites + [SimConf().writer()]
from Configurables import GaudiSequencer
output_seq = GaudiSequencer(
"OutputSeq",
Members=members,
Sequential=True,
)
from Configurables import ApplicationMgr
ApplicationMgr().TopAlg.append(output_seq)
[docs] def _propagate_simulation(self):
if "Simulation" not in self.getProp("Phases"):
GaussSimulation.only_generation_phase = True
GaussGeometry.only_generation_phase = True
return
run1or2 = self.getProp("DataType") in self.Run1DataTypes + self.Run2DataTypes
GaussGeometry.run1or2 = run1or2
GaussGeometry.run4or5 = (
self.getProp("DataType") in self.Run4DataTypes + self.Run5DataTypes
)
GaussGeometry.datatype = self.getProp("DataType")
GaussSimulation.run1or2 = run1or2
[docs] def _set_evtgen(self):
from Configurables import EvtGenDecay
EvtGenDecay().DecayFile = "$DECFILESROOT/dkfiles/DECAY.DEC"