Back to home page

EIC code displayed by LXR

 
 

    


Warning, /eic-smear/eicpy/tppmc2smear is written in an unsupported language. File is not indexed.

0001 #!/usr/bin/env python
0002 
0003 '''
0004 Bridging script between TPPMC output and EIC smearing code.
0005 
0006 You need both TPPMC and eic-smear installed, and the libraries to
0007 be accessible via (DY)LD_LIBRARY_PATH.
0008 ROOT should be installed with Python support (which it is by default).
0009 
0010 First, it generates a ROOT tree in the EIC event format, specifically
0011 events of the class erhic::hadronic::EventPythia, from the TPPMC events.
0012 Only TPPMC hadrons are propagated to the EIC tree file, as the partons
0013 are not involved in smearing.
0014 Then, smearing is performed on the EIC tree.
0015 Users can define their own smearing performance either by
0016 1) modifying the subroutine build_detector() in tppmc2smear.py
0017 2) providing an external ROOT script. The external script should provide
0018    a function with the following name and signature:
0019       void define_smearing(Smear::Detector&);
0020    The function should define the Smear::Detector that guides smearing
0021    according to their needs.
0022 By default the intermediate EIC event tree will be saved, with the name
0023 unsmeared.<name>.root for a smeared file named <name>.root.
0024 
0025 Run tppmc2smear.py --help for an explanation of all command line options.
0026 
0027 Examples:
0028 
0029 1) Create EIC/smeared trees:
0030     tppmc2smear.py tppmc.root myfile.root
0031 Generates myfile.root and unsmeared.myfile.root
0032 
0033 2) Use smearing defined in an external script:
0034     tppmc2smear.py tppmc.root myfile.root --script detector.C
0035 
0036 3) Delete intermediate unsmeared EIC file
0037     tppmc2smear.py tppmc.root myfile.root --clean
0038 '''
0039 
0040 import argparse
0041 import math
0042 import os
0043 import subprocess
0044 import sys
0045 
0046 import ROOT
0047 
0048 # Don't pass command line arguments to ROOT so it
0049 # doesn't intercept use of --help: we want the help
0050 # to be printed for this script, not ROOT.
0051 # root.cern.ch/phpBB3/viewtopic.php?f=14&t=13582
0052 ROOT.PyConfig.IgnoreCommandLineOptions = True
0053 
0054 # Speed things up a bit
0055 ROOT.SetSignalPolicy(ROOT.kSignalFast)
0056 
0057 def open_tppmc_file(filename):
0058     '''
0059     Open the named ROOT file.
0060     Return a tuple of the file and the tree in the file.
0061     '''
0062     try:
0063         file = ROOT.TFile(filename, 'read')
0064         tree = file.Get('events')
0065         print "Opened file '{}' containing TTree '{}'".format(
0066             file.GetName(), tree.GetName())
0067         return file, tree
0068     except Exception as e:
0069         print 'error in open_tppmc_file', e
0070 
0071 class Pdg:
0072     '''
0073     Class for look-up of static particle properties.
0074     Caches ROOT.TParticlePDG objects to avoid repeated
0075     calls to ROOT.TDatabasePDG.GetParticle().
0076     '''
0077     particles = {}
0078     database = ROOT.TDatabasePDG.Instance()
0079     pow = math.pow
0080     @classmethod
0081     def mass2(cls, pdgcode):
0082         # Populate the dict if this PDG code is not present
0083         if pdgcode not in cls.particles:
0084             cls.particles[pdgcode] = cls.database.GetParticle(pdgcode)
0085         # Return the mass if the particle is known, 0 if not
0086         if cls.particles[pdgcode]:
0087             return cls.pow(cls.particles[pdgcode].Mass(), 2.)
0088         else:
0089             return 0.
0090 
0091 
0092 '''
0093 def get_mass(pdg):
0094     Returns the mass (GeV/c^2) of the particle species identified
0095     by the PDG code, or zero if the particle cannot be determined.
0096     if ROOT.TDatabasePDG.Instance().GetParticle(pdg):
0097         return ROOT.TDatabasePDG.Instance().GetParticle(pdg).Mass()
0098     return 0.
0099 '''
0100 def tppmc_particle(tp, cme):
0101     '''
0102     Generate an erhic::hadronic::ParticleMC from a tppmc::Particle
0103     '''
0104     # TPPMC doesn't store particle energy, so
0105     # compute it from momentum and mass
0106     pdg = tp.Type()
0107     mom3 = tp.PxPyPz()
0108     energy = math.sqrt(mom3.Mag2() + math.pow(Pdg.mass(pdg), 2.))
0109 #    energy = math.sqrt(mom3.Mag2() + math.pow(get_mass(pdg), 2.))
0110     momentum = ROOT.TLorentzVector(mom3, energy)
0111     # All TPPMC particles are final-state (status = 1).
0112     # Vertex and parent index is not recorded, so use 0.
0113     ep = ROOT.erhic.hadronic.ParticleMC(
0114         momentum, ROOT.TVector3(0., 0., 0.), pdg, 1, 0)
0115     ep.SetXFeynman(ep.GetPz() * 2. / cme)
0116     return ep
0117 
0118 def qa(options):
0119     '''
0120     Make some simple plots comparing values in the TPPMC and
0121     EIC trees, to ensure values were properly copied.
0122     '''
0123     print type(options.tppmc)
0124     tppmcfile = ROOT.TFile(options.tppmc)
0125     tppmctree = tppmcfile.events
0126     tppmctree.AddFriend('EICTree', options.smear)
0127     window = ROOT.TCanvas()
0128     window.Print(options.qa + '[')
0129     option = 'box'
0130     for pattern in [
0131         'mHadrons.pz:mTracks.pz', 'mHadrons.PxPyPz().Eta():mTracks.eta',
0132         'mHadrons.type:mTracks.id', 'QSquared():EICTree.QSquared',
0133         'PartonX1():EICTree.x1', 'PartonX2():EICTree.x2']:
0134         tppmctree.Draw(pattern, '', option)
0135         window.Print(options.qa)
0136     tppmctree.Draw('EICTree.mTracks.xFeynman')
0137     window.Print(options.qa + ')')
0138 
0139 def build_detector():
0140     '''
0141     An example of a possible EIC detector.
0142     Put your own smearing definitions here.
0143     '''
0144     emcal = ROOT.Smear.Device(ROOT.Smear.kE, '0.15*sqrt(E)',
0145                               ROOT.Smear.kElectromagnetic)
0146     momentum = ROOT.Smear.Device(ROOT.Smear.kP, '0.005*P + 0.004*P*P')
0147     theta = ROOT.Smear.Device(ROOT.Smear.kTheta, '0.')
0148     phi = ROOT.Smear.Device(ROOT.Smear.kPhi, '0')
0149     pid = ROOT.Smear.ParticleID('PerfectPIDMatrix.dat')
0150 
0151     detector = ROOT.Smear.Detector()
0152     detector.SetEventKinematicsCalculator('NM JB DA')
0153     for d in [emcal, momentum, theta, phi, pid]:
0154         detector.AddDevice(d)
0155     
0156     return detector
0157 
0158 def runsmear(filename, detector, outname = ''):
0159     '''
0160     Use the SmearTree routine to run smearing.
0161     '''
0162     out = outname
0163     if len(out) == 0:
0164         base, ext = os.path.splitext(os.path.basename(filename))
0165         out = '.'.join([base, 'smear.root'])
0166     ROOT.SmearTree(detector, filename, out)
0167 
0168 def load_external_root_script(options):
0169     '''
0170     Check for the external ROOT script named by the command
0171     line options and load it into ROOT. Ensure that it provides
0172     the expected defined_smearing() function.
0173     Return True if everything is OK, or raise an exception
0174     if an error is encountered.
0175     '''
0176     if not os.path.exists(options.script):
0177         raise IOError(
0178         'External script {} does not exist'.format(options.script))
0179     ROOT.gROOT.LoadMacro(options.script)
0180     # Check that the user provided a function called define_smearing()
0181     # in their external script.
0182     if not ROOT.gROOT.GetGlobalFunction('define_smearing'):
0183         raise RuntimeError(
0184         '{} does not provide define_smearing()'.format(options.script))
0185     return True
0186 
0187 def get_detector(options):
0188     '''
0189     Returns a ROOT.Smear.Detector(), either defined in this
0190     script or provided by an external ROOT script, depening
0191     on command line options.
0192     '''
0193     # Check for an external script
0194     if options.script and load_external_root_script(options):
0195         print 'Reading smearing from', options.script
0196         detector = ROOT.Smear.Detector()
0197         # The external script loaded a function called define_smearing().
0198         ROOT.define_smearing(detector)
0199     else:
0200         print 'Using tppmc2smear smearing definition'
0201         detector = build_detector()
0202     return detector
0203 
0204 def generate(options):
0205     file, tree = open_tppmc_file(options.tppmc)
0206     eicfile = ROOT.TFile('.'.join(['unsmeared', options.smear]), 'recreate')
0207     eictree = ROOT.TTree('EICTree', 'Converted TPPMC event tree')
0208     eictree.Branch('event', ROOT.erhic.hadronic.EventPythiaPP())
0209     entries = tree.GetEntries()
0210     interval = entries / 10
0211     print 'Converting tree to suitable format...'
0212     event_loop(tree, eictree, entries, interval)
0213     eicfile.Write()
0214     # Now we have a tree corresponding to the input TPPMC tree, but
0215     # in a format that the smearing code will accept.
0216     runsmear(eicfile.GetName(), get_detector(options), options.smear)
0217     # Delete intermediate EIC file if requested
0218     if options.clean:
0219         subprocess.call(['rm', '-f', eicfile.GetName()])
0220 
0221 class TreeReader(object):
0222     '''
0223     Generator class for entry-by-entry reading of ROOT TTree.
0224     Each call returns the next event in the tree.
0225     '''
0226     def __init__(self, tree):
0227         self.tree = tree
0228         self.entries = tree.GetEntries()
0229         self.get = ROOT.TTree.GetEntry
0230     def __call__(self):
0231         for i in xrange(0, self.entries):
0232             self.get(self.tree, i)
0233             yield self.tree.event
0234 
0235 def event_loop(tree, eictree, entries, interval):
0236     # Not creating the vectors each time in the inner loop saves some time.
0237     vertex = ROOT.TVector3(0., 0., 0.)
0238     momentum = ROOT.TLorentzVector(0., 0., 0., 0.)
0239     # Read input tree event by event and copy properties to output event.
0240     read_events = TreeReader(tree)
0241     for te in read_events():
0242         event = ROOT.erhic.hadronic.EventPythiaPP(
0243             te.QSquared(), te.PartonX1(), te.PartonX2())
0244         # Convert and add hadrons to the eRHIC event
0245         hadrons = te.Hadrons()
0246         # This runs faster without having the particle creation
0247         # in a separate function.
0248         for i in hadrons:
0249             # TPPMC doesn't store particle energy, so
0250             # compute it from momentum and mass
0251             pdg = i.Type()
0252             mom3 = i.PxPyPz()
0253             energy = math.sqrt(mom3.Mag2() + Pdg.mass2(pdg))
0254             momentum.SetVect(mom3)
0255             momentum.SetE(energy)
0256             # All TPPMC particles are final-state (status = 1).
0257             # Vertex and parent index is not recorded, so use 0.
0258             ep = ROOT.erhic.hadronic.ParticleMC(momentum, vertex, pdg, 1, 0)
0259             ep.SetXFeynman(ep.GetPz() * 2. / te.mCentreOfMassEnergy)
0260             event.Add(ep)
0261         eictree.SetBranchAddress('event', event)
0262         eictree.Fill()
0263         # Print the number of events processed.
0264         # Pad the number correctly for nice formatting.
0265         if eictree.GetEntries() % interval == 0 and eictree.GetEntries() > 0:
0266             print str(eictree.GetEntries()).rjust(len(str(entries))), \
0267                   'of', entries, 'events'
0268 
0269 def process_arguments():
0270     '''
0271     Processes command line arguments.
0272     Returns an argparse.Namespace with the following fields:
0273         tppmc
0274         erhic
0275         qa
0276         script
0277         clean
0278     '''
0279     parser = argparse.ArgumentParser()
0280     parser.add_argument('tppmc', help='name of input TPPMC ROOT file')
0281     parser.add_argument('smear', help='name of output smeared ROOT file')
0282     parser.add_argument('--script', action='store',
0283         help='name of ROOT script defining smearing')
0284     parser.add_argument('--clean', action='store_const', const=True,
0285         default=False, help='delete intermediate EIC file')
0286     # This is just for testing, so suppress help
0287     parser.add_argument('--qa', action='store', default=None, help=argparse.SUPPRESS)
0288     options = parser.parse_args()
0289     return options
0290 
0291 def execute():
0292     ROOT.gSystem.Load('libtppmc')
0293     ROOT.gSystem.Load('libeicsmear')
0294     options = process_arguments()
0295     if options.qa:
0296         qa(options)
0297     else:
0298         generate(options)
0299 
0300 if __name__ == "__main__":
0301     execute()