ATLAS Offline Software
LheConverterUpc.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
2 
3 import os
4 import re
5 import math
6 import xml.dom.minidom
7 
8 from GeneratorModules.EvgenAnalysisAlg import EvgenAnalysisAlg
9 from AthenaPython.PyAthena import StatusCode
10 
11 
12 class LheConverterUpc(EvgenAnalysisAlg):
13  '''
14  Class for modifying output LHE file from Superchic and Madgraph + ensuring compatibility with Tauola
15  Intended for ultraperipheral collision (UPC) processes i.e. y y -> l+ l-
16  This code also contains a hack that was present in the earlier version in the Generators/Superchic_i/python/LheConverterTauolaPhotonHack.py
17  The hack was recommended by the Tauola authors, intended for the gamma gamma -> tau+ tau- process
18  The hack changes the PDG ID of the initial state particles, from photons to electrons
19  '''
20 
21  def __init__(self, name='LheConverterUpc', generator='Superchic', mode='Pythia8'):
22  super(LheConverterUpc, self).__init__(name=name)
23  self.generator = generator # options: 'Superchic' (default), 'Madgraph5'
24  self.mode = mode # options: 'Pythia8' (default), 'Tauolapp'
25 
26  outFileName = 'events.lhe'
27  done = False
28  leptons = ['11', '-11', '13', '-13', '15', '-15'] # e, µ, τ
29 
30  def initialize(self):
31 
32  self.inFileName = self.fileName
33 
34  if self.inFileName==self.outFileName:
35  import shutil
36  shutil.move('./events.lhe','events.lhe_tmpconverter')
37  self.inFileName = 'events.lhe_tmpconverter'
38  if(os.path.isfile(self.inFileName)):
39  print(self.fileName)
40  return self.convert()
41  else:
42  return StatusCode.Failure
43 
44  def convert(self):
45  '''
46  Modifies `events.lhe` output file from Madgraph by doing the following:
47  - Replaces init block
48  - Changes photon px and py to zero and energy to pz
49  - Recalculates energy scales as an average of lepton pair transverse momentum
50  '''
51  if not self.done:
52  DOMTree = xml.dom.minidom.parse(self.inFileName)
53  collection = DOMTree.documentElement
54 
55  # Replace init block
56  init = collection.getElementsByTagName('init')
57  init_repl = r'''
58  13 -13 2.510000e+03 2.510000e+03 0 0 0 0 3 1
59  1.000000e+00 0.000000e+00 1.000000e+00 9999
60  '''
61  init[0].firstChild.data = init_repl
62 
63  # The comment line below indicates which part of the regex grabs the parton-level information that's to be modified. The index in list(header.groups()) is also shown
64  # energy scale [1]
65  event_header = r'^(\s*\S*\s*\S*\s*\S*\s*)(\S*)(.*)$'
66 
67  # The comment line below indicates which part of the regex grabs the parton-level information that's to be modified. The index in list(particle) is also shown
68  # pdgid [1] px [3] py [5] pz [7] e [9]
69  event_particle = r'^(\s*)([0-9-]+)(\s+[0-9-]+\s+[0-9-]+\s+[0-9-]+\s+[0-9-]+\s+[0-9-]+\s+)(\S+)(\s+)(\S+)(\s+)(\S+)(\s+)(\S+)(.*)$'
70 
71  events = collection.getElementsByTagName('event')
72  for i, event in enumerate(events):
73 
74  # Remove the <mgrwt> block in case of Madgraph (not needed in UPC)
75  nodes = event.getElementsByTagName('mgrwt')
76  for node in nodes:
77  parent = node.parentNode
78  parent.removeChild(node)
79 
80  new_particles = []
81  lepton_mom = []
82 
83  particles = re.findall(event_particle, event.firstChild.data, re.MULTILINE)
84  for particle in particles:
85  particle = list(particle)
86  if particle[1] == '22': # photon
87  # Zero photon transverse momentum, change energy to be equal pz
88  particle[3] = '0.'
89  particle[5] = '0.'
90  particle[9] = particle[7]
91  # If Tauolapp requested, change PID of photons to electrons (hack recommended by Tauola authors)
92  if self.mode == 'Tauolapp':
93  if i%2 == 0:
94  particle[1] = '11' if float(particle[7]) > 0.0 else '-11'
95  else:
96  particle[1] = '-11' if float(particle[7]) > 0.0 else '11'
97  new_particles.append(''.join(particle))
98  elif particle[1] in self.leptons:
99  # Read leptons px and py
100  lepton_mom.append(float(particle[3]))
101  lepton_mom.append(float(particle[5]))
102  new_particles.append(''.join(particle))
103  else:
104  new_particles.append(''.join(particle))
105 
106  # Calculate new energy scale
107  l1_px, l1_py, l2_px, l2_py = lepton_mom
108  l1_pt = math.sqrt(l1_px**2 + l1_py**2)
109  l2_pt = math.sqrt(l2_px**2 + l2_py**2)
110  energy_scale = f'{(l1_pt + l2_pt) / 2.:.9E}'
111 
112  header = re.search(event_header, event.firstChild.data, re.MULTILINE)
113  header = list(header.groups())
114  header[1] = energy_scale
115 
116  if self.generator == 'Superchic':
117  event.firstChild.data = '\n'.join([''.join(header)] + new_particles) + '\n'
118  if self.generator == 'Madgraph5':
119  event.firstChild.data = '\n'.join([''.join(header)] + new_particles)
120 
121  with open(self.outFileName, 'w') as output:
122  output.write(DOMTree.toxml().replace('<?xml version="1.0" ?>', ' '))
123 
124  self.done = True
125 
126  return StatusCode.Success
127 
python.LheConverterUpc.LheConverterUpc
Definition: LheConverterUpc.py:12
replace
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition: hcg.cxx:307
python.LheConverterUpc.LheConverterUpc.__init__
def __init__(self, name='LheConverterUpc', generator='Superchic', mode='Pythia8')
Definition: LheConverterUpc.py:21
python.LheConverterUpc.LheConverterUpc.inFileName
inFileName
Definition: LheConverterUpc.py:32
python.LheConverterUpc.LheConverterUpc.outFileName
string outFileName
Definition: LheConverterUpc.py:26
python.LheConverterUpc.LheConverterUpc.mode
mode
Definition: LheConverterUpc.py:24
python.LheConverterUpc.LheConverterUpc.generator
generator
Definition: LheConverterUpc.py:23
python.LheConverterUpc.LheConverterUpc.leptons
list leptons
Definition: LheConverterUpc.py:28
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
python.LheConverterUpc.LheConverterUpc.convert
def convert(self)
Definition: LheConverterUpc.py:44
python.LheConverterUpc.LheConverterUpc.initialize
def initialize(self)
Definition: LheConverterUpc.py:30
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
Trk::open
@ open
Definition: BinningType.h:40
Muon::print
std::string print(const MuPatSegment &)
Definition: MuonTrackSteering.cxx:28
if
if(febId1==febId2)
Definition: LArRodBlockPhysicsV0.cxx:569
readCCLHist.float
float
Definition: readCCLHist.py:83
python.LheConverterUpc.LheConverterUpc.done
bool done
Definition: LheConverterUpc.py:27