ATLAS Offline Software
SUSY_Helpers.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2 
3 # Python helper functions for SUSY event generation
4 # written by Zach Marshall <zach.marshall@cern.ch>
5 
6 # Helper functions we need in MadGraphControl
7 from MadGraphControl.MadGraphUtils import (generate, generate_from_gridpack, modify_run_card,
8  add_lifetimes, arrange_output, MADGRAPH_GRIDPACK_LOCATION,
9  is_gen_from_gridpack, new_process, modify_param_card)
10 
11 # For moving files around
12 import shutil
13 
14 # For checking for files on the disk
15 import os
16 
17 # For the type hint on runArgs
18 from PyJobTransformsCore.runargs import RunArguments
19 
20 # For logging, we'll build our own logger
21 from AthenaCommon import Logging
22 susylog = Logging.logging.getLogger('MadGraphUtilsSUSY')
23 
25  """ Returns a static MadGraph particle definition-style list
26  of multi-particle definitions relevant for SUSY event generation
27  """
28 
29  return """
30 # Define multiparticle labels
31 define p = g u c d s u~ c~ d~ s~
32 define j = g u c d s u~ c~ d~ s~
33 define pb = g u c d s b u~ c~ d~ s~ b~
34 define jb = g u c d s b u~ c~ d~ s~ b~
35 define l+ = e+ mu+
36 define l- = e- mu-
37 define vl = ve vm vt
38 define vl~ = ve~ vm~ vt~
39 define fu = u c e+ mu+ ta+
40 define fu~ = u~ c~ e- mu- ta-
41 define fd = d s ve~ vm~ vt~
42 define fd~ = d~ s~ ve vm vt
43 define susystrong = go ul ur dl dr cl cr sl sr t1 t2 b1 b2 ul~ ur~ dl~ dr~ cl~ cr~ sl~ sr~ t1~ t2~ b1~ b2~
44 define susyweak = el- el+ er- er+ mul- mul+ mur- mur+ ta1- ta1+ ta2- ta2+ n1 n2 n3 n4 x1- x1+ x2- x2+ sve sve~ svm svm~ svt svt~
45 define susylq = ul ur dl dr cl cr sl sr
46 define susylq~ = ul~ ur~ dl~ dr~ cl~ cr~ sl~ sr~
47 define susysq = ul ur dl dr cl cr sl sr t1 t2 b1 b2
48 define susysq~ = ul~ ur~ dl~ dr~ cl~ cr~ sl~ sr~ t1~ t2~ b1~ b2~
49 define susysl = el- el+ er- er+ mul- mul+ mur- mur+ ta1- ta1+ ta2- ta2+
50 define susyv = sve svm svt
51 define susyv~ = sve~ svm~ svt~
52 """
53 
54 
55 def get_SUSY_variations( process: str, masses: dict[str, str | float], syst_mod: str | None = None, ktdurham: str | None = None ) -> float:
56  """
57  Provides varied matching scales for SUSY event generation based on inputs
58  Params:
59  process: the process to be generated (e.g. p p > go go). Used to figure
60  out which particles are relevant for the matching scale
61  masses: the dictionary of PDGID to mass mapping, used to figure out the
62  scale setting in GeV
63  syst_mod: the requested systematic variation (if any); can be msup,
64  msdw, or None
65  ktdurham: the matching scale in case the user provides it by hand
66  Returns:
67  the matching scale
68  """
69  # Don't override an explicit setting from the run card!
70  if ktdurham is None:
71  prod_particles = []
72  if process is not None:
73  id_map = {'go':'1000021','dl':'1000001','ul':'1000002','sl':'1000003','cl':'1000004','b1':'1000005','t1':'1000006',
74  'dr':'2000001','ur':'2000002','sr':'2000003','cr':'2000004','b2':'2000005','t2':'2000006',
75  'n1':'1000022','n2':'1000023','x1':'1000024','x2':'1000037','n3':'1000025','n4':'1000035',
76  'el':'1000011','mul':'1000013','ta1':'1000015','sve':'1000012','svm':'1000014','svt':'1000016',
77  'er':'2000011','mur':'2000013','ta2':'2000015'}
78  for l in process:
79  if 'generate' in l or 'add process' in l:
80  clean_proc = l.replace('generate','').replace('+','').replace('-','').replace('~','').replace('add process','').split('>')[1].split(',')[0]
81  for particle in clean_proc.split():
82  if particle not in id_map:
83  susylog.info(f'Particle {particle} not found in PDG ID map - skipping')
84  else:
85  prod_particles += id_map[particle]
86  # If we don't specify a process, then all we can do is guess based on available masses
87  # Same if we failed to identify the right particles
88  my_mass = 10000.
89  if len(prod_particles)>0:
90  for x in prod_particles:
91  if x in masses:
92  my_mass = min(my_mass,abs(float(masses[x])))
93  else:
94  susylog.info(f'Seem to ask for production of PDG ID {x}, but {x} not in mass dictionary?')
95  if my_mass>9999.:
96  strong_ids = ['1000001','1000002','1000003','1000004','1000005','1000006','2000001','2000002','2000003','2000004','2000005','2000006','1000021']
97  weak_ids = ['1000023','1000024','1000025','1000011','1000013','1000015','2000011','2000013','2000015','1000012','1000014','1000016']
98  # First check the lightest of the heavy sparticles - all squarks and gluino
99  my_mass = min([abs(float(masses[x])) for x in strong_ids if x in masses])
100  # Now check if strong production was not the key mode
101  if my_mass>10000.:
102  # This is a little tricky, but: we want the heaviest non-decoupled mass
103  my_mass = max([abs(float(masses[x])) for x in weak_ids if x in masses and float(masses[x])<10000.])
104  # Final check for N1N1 with everything else decoupled
105  if my_mass>10000. and '1000022' in masses:
106  my_mass = masses['1000022']
107  if my_mass>10000.:
108  raise RuntimeError('Could not understand which mass to use for matching cut in '+str(masses))
109 
110  # Now set the matching scale accordingly
111  ktdurham = min(my_mass*0.25,500)
112  # Should not be weirdly low - can't imagine a situation where you'd really want the scale below 15 GeV
113  ktdurham = max(ktdurham,15)
114  if syst_mod == 'msup':
115  susylog.info('Applying upward variation (by 2x) of matching scale')
116  ktdurham = ktdurham*2.
117  elif syst_mod == 'msdw':
118  susylog.info('Applying downward variation (by 2x) of matching scale')
119  ktdurham = ktdurham*0.5
120 
121  susylog.info('For matching, will use ktdurham of '+str(ktdurham))
122 
123  return abs(ktdurham)
124 
125 
126 
127 def SUSY_process(process: str = '') -> str:
128  '''
129  Helper function to turn a simplified model process definition into
130  a full, MG5_aMC-compliant process definition
131  '''
132 
133  # Generate the new process!
134  if 'import model' in process:
135  susylog.info('Assuming that you have specified the model in your process string already')
136  full_proc = ''
137  for l in process.split('\n'):
138  if 'import model' in l:
139  full_proc += l+'\n'
140  break
141  # Only magically add helpful definitions if we are in the right model
142  if 'MSSM_SLHA2' in full_proc:
143  full_proc+=helpful_SUSY_definitions()
144  for l in process.split('\n'):
145  if 'import model' not in l:
146  full_proc += l+'\n'
147  full_proc+="""
148 # Output processes to MadEvent directory
149 output -f
150 """
151  else:
152  full_proc = "import model MSSM_SLHA2\n"+helpful_SUSY_definitions()+"""
153 # Specify process(es) to run
154 
155 """+process+"""
156 # Output processes to MadEvent directory
157 output -f
158 """
159  return full_proc
160 
161 
162 def SUSY_Generation(runArgs: RunArguments | None = None, process: str | None = None, plugin: str | None = None,\
163  syst_mod: str | None = None, keepOutput: bool = False, param_card: str | None = None,\
164  writeGridpack: bool = False, madspin_card: str | None = None, run_settings: dict = {},
165  params: dict = {}, fixEventWeightsForBridgeMode: bool = False,\
166  add_lifetimes_lhe: bool = False, usePMGSettings: bool = True) -> float:
167 
168  """
169  Helper function for SUSY event generation, used in simplified model setups. Attempts to
170  simplify and harmonize a bunch of the things that normally have to be done by hand.
171  Keyword Arguments:
172  runArgs: passed from the job transform, includes random number seed, ecm energy, and setting for output files
173  process: simplified process definition for event generation
174  plugin: in case a MG5_aMC plugin is requested for event generation
175  syst_mod: requested systematic variation of parameter settings
176  keepOutput: retains the process directory created by MG5_aMC. Should always be false in production
177  param_card: In case an explicit parameter card is needed (e.g. for pMSSM), can be set this way
178  writeGridpack: used to construct gridpacks
179  madspin_card: used for MadSpin definitions
180  run_settings: any additional run card settings required (e.g. cuts on particle momenta). Dictionary to be
181  passed into modify_run_card(...)
182  params: any additional param card settings. Dictionary to be passed into modify_param_card(...)
183  fixEventWeightsForBridgeMode: In case Bridge mode is being used, this applies a fix to the event weights
184  add_lifetimes_lhe: if fundamental particles written to the LHE have a lifetime (e.g. sleptons or charginos), this
185  allows the inclusion of their time of flight lifetime in the LHE file directly
186  usePMGSettings (bool): See :py:func:`new_process`. Will set SM parameters to the appropriate values. Default: True.
187  returns:
188  the setting of the matching scale to be provided to Pythia8
189  """
190  ktdurham = run_settings['ktdurham'] if 'ktdurham' in run_settings else None
191  ktdurham = get_SUSY_variations( process, params['MASS'] , syst_mod , ktdurham=ktdurham )
192 
193  process_dir = MADGRAPH_GRIDPACK_LOCATION
194  if not is_gen_from_gridpack():
195  full_proc = SUSY_process(process)
196  process_dir = new_process(full_proc, plugin=plugin, usePMGSettings=usePMGSettings)
197  susylog.info('Using process directory '+str(process_dir))
198 
199  # Grab the param card and move the new masses into place
200  modify_param_card(param_card_input=param_card,process_dir=process_dir,params=params)
201 
202  # Set up the extras dictionary
203  settings = {'ktdurham':ktdurham}
204  settings.update(run_settings) # This allows explicit settings in the input to override these settings
205 
206  # Set up the run card
207  modify_run_card(process_dir=process_dir,runArgs=runArgs,settings=settings)
208 
209  # Set up madspin if needed
210  if madspin_card is not None:
211  if not os.access(madspin_card,os.R_OK):
212  raise RuntimeError('Could not locate madspin card at '+str(madspin_card))
213  shutil.copy(madspin_card,process_dir+'/Cards/madspin_card.dat')
214 
215  # Generate events!
217  generate_from_gridpack(runArgs=runArgs)
218  else:
219  # Grab the run card and move it into place
220  generate(runArgs=runArgs,process_dir=process_dir,grid_pack=writeGridpack)
221 
222  # Add lifetimes to LHE before arranging output if requested
223  if add_lifetimes_lhe :
224  susylog.info('Requested addition of lifetimes to LHE files: doing so now.')
226  add_lifetimes()
227  else:
228  add_lifetimes(process_dir=process_dir)
229 
230  # Move output files into the appropriate place, with the appropriate name
231  arrange_output(process_dir=process_dir,saveProcDir=keepOutput,runArgs=runArgs,fixEventWeightsForBridgeMode=fixEventWeightsForBridgeMode)
232 
233  susylog.info('All done generating events!!')
234  return settings['ktdurham']
235 
replace
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition: hcg.cxx:307
MadGraphUtils
python.SUSY_Helpers.SUSY_process
str SUSY_process(str process='')
Definition: SUSY_Helpers.py:127
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
python.MadGraphUtils.modify_param_card
def modify_param_card(param_card_input=None, param_card_backup=None, process_dir=MADGRAPH_GRIDPACK_LOCATION, params={}, output_location=None)
Definition: MadGraphUtils.py:1702
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
python.MadGraphUtils.arrange_output
def arrange_output(process_dir=MADGRAPH_GRIDPACK_LOCATION, lhe_version=None, saveProcDir=False, runArgs=None, fixEventWeightsForBridgeMode=False)
Definition: MadGraphUtils.py:1178
python.MadGraphUtils.new_process
def new_process(process='generate p p > t t~\noutput -f', plugin=None, keepJpegs=False, usePMGSettings=False)
Definition: MadGraphUtils.py:214
python.SUSY_Helpers.helpful_SUSY_definitions
str helpful_SUSY_definitions()
Definition: SUSY_Helpers.py:24
python.SUSY_Helpers.SUSY_Generation
float SUSY_Generation(RunArguments|None runArgs=None, str|None process=None, str|None plugin=None, str|None syst_mod=None, bool keepOutput=False, str|None param_card=None, bool writeGridpack=False, str|None madspin_card=None, dict run_settings={}, dict params={}, bool fixEventWeightsForBridgeMode=False, bool add_lifetimes_lhe=False, bool usePMGSettings=True)
Definition: SUSY_Helpers.py:162
python.MadGraphUtils.is_gen_from_gridpack
def is_gen_from_gridpack()
Definition: MadGraphUtils.py:2079
python.MadGraphUtils.modify_run_card
def modify_run_card(run_card_input=None, run_card_backup=None, process_dir=MADGRAPH_GRIDPACK_LOCATION, runArgs=None, settings={}, skipBaseFragment=False)
Definition: MadGraphUtils.py:1850
generate
Definition: generate.cxx:28
python.MadGraphUtils.generate_from_gridpack
def generate_from_gridpack(runArgs=None, extlhapath=None, gridpack_compile=None, requirePMGSettings=False)
Definition: MadGraphUtils.py:587
python.SUSY_Helpers.get_SUSY_variations
float get_SUSY_variations(str process, dict[str, str|float] masses, str|None syst_mod=None, str|None ktdurham=None)
Definition: SUSY_Helpers.py:55
str
Definition: BTagTrackIpAccessor.cxx:11
python.MadGraphUtils.add_lifetimes
def add_lifetimes(process_dir, threshold=None)
Definition: MadGraphUtils.py:993
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
python.LArMinBiasAlgConfig.float
float
Definition: LArMinBiasAlgConfig.py:65