ATLAS Offline Software
MadGraphUtilsHelpers.py
Go to the documentation of this file.
1 # Copyright (C) 2002-20204 CERN for the benefit of the ATLAS collaboration
2 
3 import os,glob
4 #The Import line is temporary for backwards compatibility of clients.
5 from AthenaCommon import Logging
6 mglog = Logging.logging.getLogger('MadGraphUtils')
7 
8 # Magic name of gridpack directory
9 MADGRAPH_GRIDPACK_LOCATION='madevent'
10 # For error handling
11 MADGRAPH_CATCH_ERRORS=True
12 MADGRAPH_COMMAND_STACK = []
13 
14 def getDictFromCard(card_loc,lowercase=False):
15  card=open(card_loc)
16  mydict={}
17  for line in iter(card):
18  if not line.strip().startswith('#'): # line commented out
19  command = line.split('!', 1)[0]
20  if '=' in command:
21  setting = command.split('=')[-1].strip()
22  value = '='.join(command.split('=')[:-1]).strip()
23  if lowercase:
24  value=value.lower()
25  setting=setting.lower()
26  mydict[setting]=value
27  card.close()
28  return mydict
29 
30 def settingIsTrue(setting):
31  if setting.replace("'",'').replace('"','').replace('.','').lower() in ['t','true']:
32  return True
33  return False
34 
36  y=str(x).lower().strip()
37  # remove leading and trailing "/'
38  while len(y)>0 and (y[0]=='"' or y[0]=="'"):
39  y=y[1:]
40  while len(y)>0 and (y[-1]=='"' or y[-1]=="'"):
41  y=y[:-1]
42  return y
43 
44 def checkSetting(key_,value_,mydict_):
45  key=totallyStripped(key_)
46  value=totallyStripped(value_)
47  mydict={}
48  for k in mydict_:
49  mydict[totallyStripped(k)]=totallyStripped(mydict_[k])
50  return key in mydict and mydict[key]==value
51 
52 def checkSettingIsTrue(key_,mydict_):
53  key=totallyStripped(key_)
54  mydict={}
55  for k in mydict_:
56  mydict[totallyStripped(k)]=totallyStripped(mydict_[k])
57  return key in mydict and mydict[key] in ['t','true']
58 
59 def checkSettingExists(key_,mydict_):
60  key=totallyStripped(key_)
61  keys=[]
62  for k in mydict_:
63  keys+=[totallyStripped(k)]
64  return key in keys
65 
67  # also need to find out the version (copied from generate)
68  import os
69  version=None
70  version_file = open(os.environ['MADPATH']+'/VERSION','r')
71 
72  for line in version_file:
73  if 'version' in line:
74  version=line.split('=')[1].strip()
75  version_file.close()
76 
77  if not version:
78  raise RuntimeError('Failed to find MadGraph/MadGraph5_aMC@NLO version in '+version_file)
79 
80  vs=[int(v) for v in version.split('.')]
81 
82  # this is lazy, let's hope there wont be a subversion > 100...
83  y=int(100**max(len(vs),len(args)))
84  testnumber=0
85  for x in args:
86  testnumber+=x*y
87  y/=100
88 
89  y=int(100**max(len(vs),len(args)))
90  versionnumber=0
91  for x in vs:
92  versionnumber+=x*y
93  y/=100
94  return versionnumber>=testnumber
95 
96 def isNLO_from_run_card(run_card):
97  f = open(run_card,'r')
98  if "parton_shower" in f.read().lower():
99  f.close()
100  return True
101  else:
102  f.close()
103  return False
104 
105 def get_runArgs_info(runArgs):
106  if runArgs is None:
107  raise RuntimeError('runArgs must be provided!')
108  if hasattr(runArgs,'ecmEnergy'):
109  beamEnergy = runArgs.ecmEnergy / 2.
110  else:
111  raise RuntimeError("No center of mass energy found in runArgs.")
112  if hasattr(runArgs,'randomSeed'):
113  random_seed = runArgs.randomSeed
114  else:
115  raise RuntimeError("No random seed found in runArgs.")
116  return beamEnergy,random_seed
117 
118 
119 def error_check(errors_a, return_code):
120  global MADGRAPH_CATCH_ERRORS
121  if not MADGRAPH_CATCH_ERRORS:
122  return
123  unmasked_error = False
124  my_debug_file = None
125  bad_variables = []
126  # Make sure we are getting a string and not a byte string (python3 ftw)
127  errors = errors_a
128  if type(errors)==bytes:
129  errors = errors.decode('utf-8')
130  if len(errors):
131  mglog.info('Some errors detected by MadGraphControl - checking for serious errors')
132  for err in errors.split('\n'):
133  if len(err.strip())==0:
134  continue
135  # Errors to do with I/O... not clear on their origin yet
136  if 'Inappropriate ioctl for device' in err:
137  mglog.info(err)
138  continue
139  if 'stty: standard input: Invalid argument' in err:
140  mglog.info(err)
141  continue
142  # Errors for PDF sets that should be fixed in MG5_aMC 2.7
143  if 'PDF already installed' in err:
144  mglog.info(err)
145  continue
146  if 'Read-only file system' in err:
147  mglog.info(err)
148  continue
149  if 'HTML' in err:
150  # https://bugs.launchpad.net/mg5amcnlo/+bug/1870217
151  mglog.info(err)
152  continue
153  if 'impossible to set default multiparticles' in err:
154  # https://answers.launchpad.net/mg5amcnlo/+question/690004
155  mglog.info(err)
156  continue
157  if 'More information is found in' in err:
158  my_debug_file = err.split("'")[1]
159  if err.startswith('tar'):
160  mglog.info(err)
161  continue
162  if 'python2 support will be removed' in err:
163  mglog.info(err)
164  continue
165  if 'python3.12 support is still experimental' in err:
166  mglog.info(err)
167  continue
168  # silly ghostscript issue in 21.6.46 nightly
169  if 'required by /lib64/libfontconfig.so' in err or\
170  'required by /lib64/libgs.so' in err:
171  mglog.info(err)
172  continue
173  if 'Error: Symbol' in err and 'has no IMPLICIT type' in err:
174  bad_variables += [ err.split('Symbol ')[1].split(' at ')[0] ]
175  # error output from tqdm (progress bar)
176  if 'it/s' in err:
177  mglog.info(err)
178  continue
179  mglog.error(err)
180  unmasked_error = True
181  # This is a bit clunky, but needed because we could be several places when we get here
182  if my_debug_file is None:
183  debug_files = glob.glob('*debug.log')+glob.glob('*/*debug.log')
184  for debug_file in debug_files:
185  # This protects against somebody piping their output to my_debug.log and it being caught here
186  has_subproc = os.access(os.path.join(os.path.dirname(debug_file),'SubProcesses'),os.R_OK)
187  if has_subproc:
188  my_debug_file = debug_file
189  break
190 
191  if my_debug_file is not None:
192  if not unmasked_error:
193  mglog.warning('Found a debug file at '+my_debug_file+' but no apparent error. Will terminate.')
194  mglog.error('MadGraph5_aMC@NLO appears to have crashed. Debug file output follows.')
195  with open(my_debug_file,'r') as error_output:
196  for l in error_output:
197  mglog.error(l.replace('\n',''))
198  mglog.error('End of debug file output')
199 
200  if bad_variables:
201  mglog.warning('Appeared to detect variables in your run card that MadGraph did not understand:')
202  mglog.warning(' Check your run card / JO settings for %s',bad_variables)
203 
204  # Check the return code
205  if return_code!=0:
206  mglog.error(f'Detected a bad return code: {return_code}')
207  unmasked_error = True
208 
209  # Now raise an error if we were in either of the error states
210  if unmasked_error or my_debug_file is not None:
212  raise RuntimeError('Error detected in MadGraphControl process')
213  return
214 
215 
216 # Write a short test script for standalone debugging
218  mglog.info('Will write a stand-alone debugging script.')
219  mglog.info('This is an attempt to provide you commands that you can use')
220  mglog.info('to reproduce the error locally. If you make additional')
221  mglog.info('modifications by hand (not using MadGraphControl) in your JO,')
222  mglog.info('make sure that you check and modify the script as needed.\n\n')
223  global MADGRAPH_COMMAND_STACK
224  mglog.info('# Script start; trim off columns left of the "#"')
225  # Write offline stand-alone reproduction script
226  with open('standalone_script.sh','w') as standalone_script:
227  for command in MADGRAPH_COMMAND_STACK:
228  for line in command.split('\n'):
229  mglog.info(line)
230  standalone_script.write(line+'\n')
231  mglog.info('# Script end')
232  mglog.info('Script also written to %s/standalone_script.sh',os.getcwd())
233 
235  # Addition for models directory
236  global MADGRAPH_COMMAND_STACK
237  if 'PYTHONPATH' in os.environ:
238  if not any( [('Generators/madgraph/models' in x and 'shutil_patch' not in x) for x in os.environ['PYTHONPATH'].split(':') ]):
239  os.environ['PYTHONPATH'] += ':/cvmfs/atlas.cern.ch/repo/sw/Generators/madgraph/models/latest'
240  MADGRAPH_COMMAND_STACK += ['export PYTHONPATH=${PYTHONPATH}:/cvmfs/atlas.cern.ch/repo/sw/Generators/madgraph/models/latest']
241  # Make sure that gfortran doesn't write to somewhere it shouldn't
242  if 'GFORTRAN_TMPDIR' in os.environ:
243  return
244  if 'TMPDIR' in os.environ:
245  os.environ['GFORTRAN_TMPDIR']=os.environ['TMPDIR']
246  MADGRAPH_COMMAND_STACK += ['export GFORTRAN_TMPDIR=${TMPDIR}']
247  return
248  if 'TMP' in os.environ:
249  os.environ['GFORTRAN_TMPDIR']=os.environ['TMP']
250  MADGRAPH_COMMAND_STACK += ['export GFORTRAN_TMPDIR=${TMP}']
251  return
252 
253 def get_default_config_card(process_dir=MADGRAPH_GRIDPACK_LOCATION):
254 
255  lo_config_card=process_dir+'/Cards/me5_configuration.txt'
256  nlo_config_card=process_dir+'/Cards/amcatnlo_configuration.txt'
257 
258  if os.access(lo_config_card,os.R_OK) and not os.access(nlo_config_card,os.R_OK):
259  return lo_config_card
260  elif os.access(nlo_config_card,os.R_OK) and not os.access(lo_config_card,os.R_OK):
261  return nlo_config_card
262  elif os.access(nlo_config_card,os.R_OK) and os.access(lo_config_card,os.R_OK):
263  mglog.error('Found both types of config card in '+process_dir)
264  else:
265  mglog.error('No config card in '+process_dir)
266  raise RuntimeError('Unable to locate configuration card')
267 
268 def is_NLO_run(process_dir=MADGRAPH_GRIDPACK_LOCATION):
269  # Very simple check based on the above config card grabbing
270  return get_default_config_card(process_dir=process_dir)==process_dir+'/Cards/amcatnlo_configuration.txt'
replace
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition: hcg.cxx:307
python.MadGraphUtilsHelpers.isNLO_from_run_card
def isNLO_from_run_card(run_card)
Definition: MadGraphUtilsHelpers.py:96
createLinkingScheme.iter
iter
Definition: createLinkingScheme.py:62
python.MadGraphUtilsHelpers.settingIsTrue
def settingIsTrue(setting)
Definition: MadGraphUtilsHelpers.py:30
python.MadGraphUtilsHelpers.checkSettingIsTrue
def checkSettingIsTrue(key_, mydict_)
Definition: MadGraphUtilsHelpers.py:52
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
python.MadGraphUtilsHelpers.is_NLO_run
def is_NLO_run(process_dir=MADGRAPH_GRIDPACK_LOCATION)
Definition: MadGraphUtilsHelpers.py:268
python.MadGraphUtilsHelpers.get_runArgs_info
def get_runArgs_info(runArgs)
Definition: MadGraphUtilsHelpers.py:105
python.MadGraphUtilsHelpers.checkSetting
def checkSetting(key_, value_, mydict_)
Definition: MadGraphUtilsHelpers.py:44
python.MadGraphUtilsHelpers.setup_path_protection
def setup_path_protection()
Definition: MadGraphUtilsHelpers.py:234
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
python.MadGraphUtilsHelpers.write_test_script
def write_test_script()
Definition: MadGraphUtilsHelpers.py:217
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
python.MadGraphUtilsHelpers.get_default_config_card
def get_default_config_card(process_dir=MADGRAPH_GRIDPACK_LOCATION)
Definition: MadGraphUtilsHelpers.py:253
python.MadGraphUtilsHelpers.error_check
def error_check(errors_a, return_code)
Definition: MadGraphUtilsHelpers.py:119
python.MadGraphUtilsHelpers.checkSettingExists
def checkSettingExists(key_, mydict_)
Definition: MadGraphUtilsHelpers.py:59
Trk::open
@ open
Definition: BinningType.h:40
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
str
Definition: BTagTrackIpAccessor.cxx:11
python.MadGraphUtilsHelpers.totallyStripped
def totallyStripped(x)
Definition: MadGraphUtilsHelpers.py:35
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
python.MadGraphUtilsHelpers.getDictFromCard
def getDictFromCard(card_loc, lowercase=False)
Definition: MadGraphUtilsHelpers.py:14
python.MadGraphUtilsHelpers.is_version_or_newer
def is_version_or_newer(args)
Definition: MadGraphUtilsHelpers.py:66