Commit cb079b36 authored by Alex Pearce's avatar Alex Pearce Committed by Alex Pearce
Browse files

Allow Tesla to save a filter copy of the MC event.

Tesla can then mimic the behaviour of a Stripping microDST writer, by
saving a filtering copy of /Event/MC/{Particles,Vertices} as
/Event/Turbo/MC/{Particles,Vertices}.
parent 2b8796e0
import os
from Gaudi.Configuration import *
from LHCbKernel.Configuration import *
from Configurables import LHCbApp
......@@ -11,7 +13,7 @@ from TurboStreamProd import prodDict
from copy import copy
class Tesla(LHCbConfigurableUser):
__used_configurables__ = [ LHCbApp, LumiAlgsConf, RawEventJuggler, DecodeRawEvent, RawEventFormatConf, DstConf, RecombineRawEvent, PackParticlesAndVertices, TrackAssociator, ChargedPP2MC, TrackSys, TurboConf]
__used_configurables__ = [ LHCbApp, LumiAlgsConf, RawEventJuggler, DecodeRawEvent, RawEventFormatConf, DstConf, RecombineRawEvent, PackParticlesAndVertices, TrackAssociator, ChargedPP2MC, CopyProtoParticle2MCRelations, CopySignalMCParticles, TrackSys, TurboConf]
__slots__ = {
"EvtMax" : -1 # Maximum number of events to process
......@@ -55,6 +57,7 @@ class Tesla(LHCbConfigurableUser):
, 'ValidateStreams' : False # Run validation to compare streams and TriggerLines
, 'EnableLineChecker' : True # Enable the comparison of lines in the DecReports and the input to TeslaReportsAlgo
, 'IgnoredLines' : [ ] # Regexes for lines excluded from the comparison of DecReports and input to TeslaReportsAlgo
, 'FilterMC' : False # Save a subset of the input MC particles and vertices under `Tesla.base, mimicking a microDST writer`
}
_propertyDocDct ={
"EvtMax" : "Maximum number of events to process, default all"
......@@ -97,6 +100,7 @@ class Tesla(LHCbConfigurableUser):
, 'ValidateStreams' : 'Run validation to compare streams and TriggerLines'
, 'EnableLineChecker' : 'Enable the comparison of lines in the DecReports and the input to TeslaReportsAlgo'
, 'IgnoredLines' : 'Regexes for lines excluded from the comparison of DecReports and input to TeslaReportsAlgo'
, 'FilterMC' : "Save a subset of the input MC particles and vertices under `Tesla.base`, mimicking a microDST writer"
}
......@@ -156,7 +160,11 @@ class Tesla(LHCbConfigurableUser):
assoccluster.Clusters+=clusters
from Configurables import NeutralPP2MC
protoTabLoc= self.base + "Relations/Turbo/NeutralPP2MC"
# When filtering MC, the relations table cloners will copy the tables
# to /Event/Turbo for us. Otherwise we create them there directly
protoTabLoc = "Relations/Turbo/NeutralPP2MC"
if not self.getProp("FilterMC"):
protoTabLoc = os.path.join(self.base, protoTabLoc)
assocneutral = NeutralPP2MC("TurboNeutralPP2MC")
assocneutral.InputData += protos
assocneutral.OutputLevel = self.getProp('OutputLevel')
......@@ -171,6 +179,54 @@ class Tesla(LHCbConfigurableUser):
DataOnDemandSvc().AlgMap["MC/Particles"] = "UnpackMCParticle"
DataOnDemandSvc().AlgMap["MC/Vertices"] = "UnpackMCVertex"
def _filterMCParticlesSequence(self, relations_locations):
"""Copy signal and associated MC particles to microDST-like locations.
In the Stripping, the microDST machinery only saves a subset of the
input MC particles and vertices. This subset contains two possibly
overlapping contributions:
1. The MCParticle objects in the signal decay tree; and
2. The MCParticle objects which can be associated to the reconstructed
objects selected by at least one stripping line.
To mimic this behave in Tesla, we run almost the same set of microDST
algorithms, using the relations tables Tesla makes to find the MC
particles that have been associated to the reconstruction.
"""
if not self.getProp('FilterMC'):
return
from Configurables import (
CopyProtoParticle2MCRelations,
CopySignalMCParticles
)
output_prefix = self.base.replace('/', '')
# Algorithm to clone the existing relations tables and the MC particles
# and vertices these tables point to from their original location to
# the same location prefixed by /Event/Turbo
copy_pp2mcp = CopyProtoParticle2MCRelations()
copy_pp2mcp.InputLocations = relations_locations
copy_pp2mcp.OutputPrefix = output_prefix
# Don't use the assumed copy of the input ProtoParticle objects, as
# Tesla doesn't need to copy them (they're already under /Event/Turbo)
copy_pp2mcp.UseOriginalFrom = True
# Algorithm to clone all MC particles and vertices that are associated
# to the simulated signal process (using LHCb::MCParticle::fromSignal)
copy_signal_mcp = CopySignalMCParticles()
copy_signal_mcp.OutputPrefix = output_prefix
# Don't copy the associated reconstruction, as Tesla already saves it
copy_signal_mcp.SaveAssociatedRecoInfo = False
algorithms = [copy_pp2mcp, copy_signal_mcp]
seq = GaudiSequencer('TurboMCFiltering', Members=algorithms)
return seq
def _configureForOnline(self,stream):
#
DecodeRawEvent().DataOnDemand=False
......@@ -318,7 +374,12 @@ class Tesla(LHCbConfigurableUser):
assocpp=ChargedPP2MC("TurboProtoAssocPP")
assocpp.OutputLevel = self.getProp('OutputLevel')
assocpp.VetoEmpty=True
tesROOT="/Event/"+self.base
# When filtering MC, the relations table cloners will copy the
# tables to /Event/Turbo for us. Otherwise we create them there
# directly
tesROOT = "/Event/"
if not self.getProp("FilterMC"):
tesROOT = os.path.join(tesROOT, self.base)
assocpp.RootInTES=tesROOT
# Start with an empty input list, so we don't accidentally create
# relations for non-Turbo/non-PersistReco objects
......@@ -398,6 +459,15 @@ class Tesla(LHCbConfigurableUser):
# Add final sequences
TeslaReportAlgoSeq.Members+=[ChargedProtoSeq,NeutralProtoSeq]
# Sequence to copy the relations tables, and the subset of MC
# particles used by those tables, into /Event/Turbo
if self.getProp("FilterMC"):
relationsLocations = [os.path.join('Relations', path)
for path in assocpp.InputData]
relationsLocations.append(protoneutral)
filterMCSeq = self._filterMCParticlesSequence(relationsLocations)
TeslaReportAlgoSeq.Members += [filterMCSeq]
if self.getProp('Pack'):
packer = PackParticlesAndVertices( name = "TurboPacker",
InputStream = "/Event"+"/"+self.base.rstrip('/'),
......@@ -422,6 +492,25 @@ class Tesla(LHCbConfigurableUser):
OutputName = self.base+"pRec/neutral/Clusters" )
TeslaReportAlgoSeq.Members +=[hypopacker,clusterpacker]
# Pack the filtered MC particles and vertices
if self.getProp('Simulation') and self.getProp('FilterMC'):
from Configurables import PackMCParticle, PackMCVertex
mcp_packer = PackMCParticle(
'TurboPackMCParticle',
AlwaysCreateOutput=True,
DeleteInput=False,
InputName=self.base + 'MC/Particles',
OutputName=self.base + 'pSim/MCParticles'
)
mcv_packer = PackMCVertex(
'TurboPackMCVertex',
AlwaysCreateOutput=True,
DeleteInput=False,
InputName=self.base + 'MC/Vertices',
OutputName=self.base + 'pSim/MCVertices'
)
TeslaReportAlgoSeq.Members += [mcp_packer, mcv_packer]
packer.OutputLevel = min(self.getProp('OutputLevel'),self.getProp('PackerOutputLevel'))
TeslaOutputStreamsSequence = GaudiSequencer('TeslaOutputStreamsSequence')
......@@ -585,6 +674,8 @@ class Tesla(LHCbConfigurableUser):
,self.base+"pRec/neutral/Hypos#99"
,self.base+"pRec/neutral/Clusters#99"
,self.base+"Rec/Summary#99"
,self.base+"pSim/MCParticles#99"
,self.base+"pSim/MCVertices#99"
]
IOHelper(persistency,persistency).outStream(fname,writer,writeFSR=self.getProp('WriteFSR'))
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment