1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """A user friendly command line interface to access MadGraph5_aMC@NLO features.
16 Uses the cmd package for command interpretation and tab completion.
17 """
18 from __future__ import division
19
20
21
22 from __future__ import absolute_import
23 from __future__ import print_function
24 import ast
25 import logging
26 import math
27 import os
28 import re
29 import shutil
30 import signal
31 import stat
32 import subprocess
33 import sys
34 import time
35 import traceback
36 import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
37 import glob
38 from six.moves import range
39 from six.moves import input
40 import six
41 StringIO = six
42 try:
43 import readline
44 GNU_SPLITTING = ('GNU' in readline.__doc__)
45 except:
46 GNU_SPLITTING = True
47
48 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
49 root_path = os.path.split(root_path)[0]
50 sys.path.insert(0, os.path.join(root_path,'bin'))
51
52
53 pjoin = os.path.join
54
55 logger = logging.getLogger('madgraph.stdout')
56 logger_stderr = logging.getLogger('madgraph.stderr')
57
58 try:
59 import madgraph
60 except ImportError:
61
62 import internal.extended_cmd as cmd
63 import internal.banner as banner_mod
64 import internal.shower_card as shower_card_mod
65 import internal.misc as misc
66 import internal.cluster as cluster
67 import internal.check_param_card as param_card_mod
68 import internal.files as files
69
70 import internal.save_load_object as save_load_object
71 import internal.gen_crossxhtml as gen_crossxhtml
72 import internal.lhe_parser as lhe_parser
73 import internal.FO_analyse_card as FO_analyse_card
74 import internal.sum_html as sum_html
75 from internal import InvalidCmd, MadGraph5Error
76
77 MADEVENT=True
78 else:
79
80 import madgraph.interface.extended_cmd as cmd
81 import madgraph.various.banner as banner_mod
82 import madgraph.various.shower_card as shower_card_mod
83 import madgraph.various.misc as misc
84 import madgraph.iolibs.files as files
85 import madgraph.various.cluster as cluster
86 import madgraph.various.lhe_parser as lhe_parser
87 import madgraph.various.FO_analyse_card as FO_analyse_card
88 import madgraph.iolibs.save_load_object as save_load_object
89 import madgraph.madevent.gen_crossxhtml as gen_crossxhtml
90 import models.check_param_card as param_card_mod
91 import madgraph.madevent.sum_html as sum_html
92
93
94 from madgraph import InvalidCmd, MadGraph5Error, MG5DIR
95 MADEVENT=False
101 """ The Series of help routins in common between amcatnlo_run and
102 madevent interface"""
103
105 logger.info("syntax: treatcards [param|run] [--output_dir=] [--param_card=] [--run_card=]")
106 logger.info("-- create the .inc files containing the cards information." )
107
109 logger.info("syntax: set %s argument" % "|".join(self._set_options))
110 logger.info("-- set options")
111 logger.info(" stdout_level DEBUG|INFO|WARNING|ERROR|CRITICAL")
112 logger.info(" change the default level for printed information")
113 logger.info(" timeout VALUE")
114 logger.info(" (default 20) Seconds allowed to answer questions.")
115 logger.info(" Note that pressing tab always stops the timer.")
116 logger.info(" cluster_temp_path PATH")
117 logger.info(" (default None) Allow to perform the run in PATH directory")
118 logger.info(" This allow to not run on the central disk. This is not used")
119 logger.info(" by condor cluster (since condor has it's own way to prevent it).")
120
122 logger.info("syntax: plot [RUN] [%s] [-f]" % '|'.join(self._plot_mode))
123 logger.info("-- create the plot for the RUN (current run by default)")
124 logger.info(" at the different stage of the event generation")
125 logger.info(" Note than more than one mode can be specified in the same command.")
126 logger.info(" This requires to have MadAnalysis and td installed.")
127 logger.info(" -f options: answer all question by default.")
128
130 logger.info("syntax: compute_widths Particle [Particles] [OPTIONS]")
131 logger.info("-- Compute the widths for the particles specified.")
132 logger.info(" By default, this takes the current param_card and overwrites it.")
133 logger.info(" Precision allows to define when to include three/four/... body decays (LO).")
134 logger.info(" If this number is an integer then all N-body decay will be included.")
135 logger.info(" Various options:\n")
136 logger.info(" --body_decay=X: Parameter to control the precision of the computation")
137 logger.info(" if X is an integer, we compute all channels up to X-body decay.")
138 logger.info(" if X <1, then we stop when the estimated error is lower than X.")
139 logger.info(" if X >1 BUT not an integer, then we X = N + M, with M <1 and N an integer")
140 logger.info(" We then either stop at the N-body decay or when the estimated error is lower than M.")
141 logger.info(" default: 4.0025")
142 logger.info(" --min_br=X: All channel which are estimated below this value will not be integrated numerically.")
143 logger.info(" default: precision (decimal part of the body_decay options) divided by four")
144 logger.info(" --precision_channel=X: requested numerical precision for each channel")
145 logger.info(" default: 0.01")
146 logger.info(" --path=X: path for param_card")
147 logger.info(" default: take value from the model")
148 logger.info(" --output=X: path where to write the resulting card. ")
149 logger.info(" default: overwrite input file. If no input file, write it in the model directory")
150 logger.info(" --nlo: Compute NLO width [if the model support it]")
151
153 logger.info("syntax: shower [shower_name] [shower_options]")
154 logger.info("-- This is equivalent to running '[shower_name] [shower_options]'")
155
157 logger.info("syntax: pgs [RUN] [--run_options]")
158 logger.info("-- run pgs on RUN (current one by default)")
159 self.run_options_help([('-f','answer all question by default'),
160 ('--tag=', 'define the tag for the pgs run'),
161 ('--no_default', 'not run if pgs_card not present')])
162
164 logger.info("syntax: delphes [RUN] [--run_options]")
165 logger.info("-- run delphes on RUN (current one by default)")
166 self.run_options_help([('-f','answer all question by default'),
167 ('--tag=', 'define the tag for the delphes run'),
168 ('--no_default', 'not run if delphes_card not present')])
169
171 if not skip_syntax:
172 logger.info("syntax: decay_events [RUN]")
173 logger.info("This functionality allows for the decay of resonances")
174 logger.info("in a .lhe file, keeping track of the spin correlation effets.")
175 logger.info("BE AWARE OF THE CURRENT LIMITATIONS:")
176 logger.info(" (1) Only a succession of 2 body decay are currently allowed")
177
181 """ The Series of check routines in common between amcatnlo_run and
182 madevent interface"""
183
185 """ check the validity of the line"""
186
187
188 if len(args) < 2:
189 if len(args)==1 and "=" in args[0]:
190 args[:] = args[0].split("=",1)
191 else:
192 self.help_set()
193 raise self.InvalidCmd('set needs an option and an argument')
194
195 if args[0] not in self._set_options + list(self.options.keys()):
196 self.help_set()
197 raise self.InvalidCmd('Possible options for set are %s' % \
198 (self._set_options+list(self.options.keys())))
199
200 if args[0] in ['stdout_level']:
201 if args[1] not in ['DEBUG','INFO','WARNING','ERROR','CRITICAL'] \
202 and not args[1].isdigit():
203 raise self.InvalidCmd('output_level needs ' + \
204 'a valid level')
205
206 if args[0] in ['timeout']:
207 if not args[1].isdigit():
208 raise self.InvalidCmd('timeout values should be a integer')
209
211 """check that the model is loadable and check that the format is of the
212 type: PART PATH --output=PATH -f --precision=N
213 return the model.
214 """
215
216
217 if MADEVENT and not self.options['mg5_path']:
218 raise self.InvalidCmd('''The automatic computations of widths requires that MG5 is installed on the system.
219 You can install it and set his path in ./Cards/me5_configuration.txt''')
220 elif MADEVENT:
221 sys.path.append(self.options['mg5_path'])
222 try:
223 import models.model_reader as model_reader
224 import models.import_ufo as import_ufo
225 except ImportError:
226 raise self.ConfigurationError('''Can\'t load MG5.
227 The variable mg5_path should not be correctly configure.''')
228
229
230 ufo_path = pjoin(self.me_dir,'bin','internal', 'ufomodel')
231
232 if not MADEVENT:
233 modelname = self.find_model_name()
234
235
236
237
238 force_CMS = self.mother and self.mother.options['complex_mass_scheme']
239 model = import_ufo.import_model(modelname, decay=True,
240 restrict=True, complex_mass_scheme=force_CMS)
241 else:
242 force_CMS = self.proc_characteristics['complex_mass_scheme']
243 model = import_ufo.import_model(pjoin(self.me_dir,'bin','internal',
244 'ufomodel'), decay=True, complex_mass_scheme=force_CMS)
245
246
247
248
249
250 if '-modelname' not in open(pjoin(self.me_dir,'Cards','proc_card_mg5.dat')).read():
251 model.pass_particles_name_in_mg_default()
252 model = model_reader.ModelReader(model)
253 particles_name = dict([(p.get('name'), p.get('pdg_code'))
254 for p in model.get('particles')])
255 particles_name.update(dict([(p.get('antiname'), p.get('pdg_code'))
256 for p in model.get('particles')]))
257
258 output = {'model': model, 'force': False, 'output': None,
259 'path':None, 'particles': set(), 'body_decay':4.0025,
260 'min_br':None, 'precision_channel':0.01}
261 for arg in args:
262 if arg.startswith('--output='):
263 output_path = arg.split('=',1)[1]
264 if not os.path.exists(output_path):
265 raise self.InvalidCmd('Invalid Path for the output. Please retry.')
266 if not os.path.isfile(output_path):
267 output_path = pjoin(output_path, 'param_card.dat')
268 output['output'] = output_path
269 elif arg == '-f':
270 output['force'] = True
271 elif os.path.isfile(arg):
272 ftype = self.detect_card_type(arg)
273 if ftype != 'param_card.dat':
274 raise self.InvalidCmd('%s is not a valid param_card.' % arg)
275 output['path'] = arg
276 elif arg.startswith('--path='):
277 arg = arg.split('=',1)[1]
278 ftype = self.detect_card_type(arg)
279 if ftype != 'param_card.dat':
280 raise self.InvalidCmd('%s is not a valid param_card.' % arg)
281 output['path'] = arg
282 elif arg.startswith('--'):
283 if "=" in arg:
284 name, value = arg.split('=',1)
285 try:
286 value = float(value)
287 except Exception:
288 raise self.InvalidCmd('--%s requires integer or a float' % name)
289 output[name[2:]] = float(value)
290 elif arg == "--nlo":
291 output["nlo"] = True
292 elif arg in particles_name:
293
294 output['particles'].add(particles_name[arg])
295 elif arg.isdigit() and int(arg) in list(particles_name.values()):
296 output['particles'].add(ast.literal_eval(arg))
297 elif arg == 'all':
298 output['particles'] = set(['all'])
299 else:
300 self.help_compute_widths()
301 raise self.InvalidCmd('%s is not a valid argument for compute_widths' % arg)
302 if self.force:
303 output['force'] = True
304
305 if not output['particles']:
306 raise self.InvalidCmd('''This routines requires at least one particle in order to compute
307 the related width''')
308
309 if output['output'] is None:
310 output['output'] = output['path']
311
312 return output
313
315 """Check the argument for pythia command
316 syntax: delphes [NAME]
317 Note that other option are already remove at this point
318 """
319
320
321 if not self.options['delphes_path']:
322 logger.info('Retry to read configuration file to find delphes path')
323 self.set_configuration()
324
325 if not self.options['delphes_path']:
326 error_msg = 'No valid Delphes path set.\n'
327 error_msg += 'Please use the set command to define the path and retry.\n'
328 error_msg += 'You can also define it in the configuration file.\n'
329 raise self.InvalidCmd(error_msg)
330
331 tag = [a for a in arg if a.startswith('--tag=')]
332 if tag:
333 arg.remove(tag[0])
334 tag = tag[0][6:]
335
336
337 if len(arg) == 0 and not self.run_name:
338 if self.results.lastrun:
339 arg.insert(0, self.results.lastrun)
340 else:
341 raise self.InvalidCmd('No run name currently define. Please add this information.')
342
343 if len(arg) == 1 and self.run_name == arg[0]:
344 arg.pop(0)
345
346 filepath = None
347 if not len(arg):
348 prev_tag = self.set_run_name(self.run_name, tag, 'delphes')
349 paths = [pjoin(self.me_dir,'Events',self.run_name, '%(tag)s_pythia_events.hep.gz'),
350 pjoin(self.me_dir,'Events',self.run_name, '%(tag)s_pythia8_events.hepmc.gz'),
351 pjoin(self.me_dir,'Events',self.run_name, '%(tag)s_pythia_events.hep'),
352 pjoin(self.me_dir,'Events',self.run_name, '%(tag)s_pythia8_events.hepmc'),
353 pjoin(self.me_dir,'Events','pythia_events.hep'),
354 pjoin(self.me_dir,'Events','pythia_events.hepmc'),
355 pjoin(self.me_dir,'Events','pythia8_events.hep.gz'),
356 pjoin(self.me_dir,'Events','pythia8_events.hepmc.gz')
357 ]
358 for p in paths:
359 if os.path.exists(p % {'tag': prev_tag}):
360 filepath = p % {'tag': prev_tag}
361 break
362 else:
363 a = input("NO INPUT")
364 if nodefault:
365 return False
366 else:
367 self.help_pgs()
368 raise self.InvalidCmd('''No file file pythia_events.* currently available
369 Please specify a valid run_name''')
370
371 if len(arg) == 1:
372 prev_tag = self.set_run_name(arg[0], tag, 'delphes')
373 if os.path.exists(pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep.gz' % prev_tag)):
374 filepath = pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep.gz' % prev_tag)
375 elif os.path.exists(pjoin(self.me_dir,'Events',self.run_name, '%s_pythia8_events.hepmc.gz' % prev_tag)):
376 filepath = pjoin(self.me_dir,'Events',self.run_name, '%s_pythia8_events.hepmc.gz' % prev_tag)
377 elif os.path.exists(pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep' % prev_tag)):
378 filepath = pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep.gz' % prev_tag)
379 elif os.path.exists(pjoin(self.me_dir,'Events',self.run_name, '%s_pythia8_events.hepmc' % prev_tag)):
380 filepath = pjoin(self.me_dir,'Events',self.run_name, '%s_pythia8_events.hepmc.gz' % prev_tag)
381 else:
382 raise self.InvalidCmd('No events file corresponding to %s run with tag %s.:%s '\
383 % (self.run_name, prev_tag,
384 pjoin(self.me_dir,'Events',self.run_name, '%s_pythia_events.hep.gz' % prev_tag)))
385 else:
386 if tag:
387 self.run_card['run_tag'] = tag
388 self.set_run_name(self.run_name, tag, 'delphes')
389
390 return filepath
391
392
393
394
395
396
397
399 """ check the validity of the line """
400
401 if len(args) != 1:
402 self.help_open()
403 raise self.InvalidCmd('OPEN command requires exactly one argument')
404
405 if args[0].startswith('./'):
406 if not os.path.isfile(args[0]):
407 raise self.InvalidCmd('%s: not such file' % args[0])
408 return True
409
410
411 if not self.me_dir:
412 if not os.path.isfile(args[0]):
413 self.help_open()
414 raise self.InvalidCmd('No MadEvent path defined. Unable to associate this name to a file')
415 else:
416 return True
417
418 path = self.me_dir
419 if os.path.isfile(os.path.join(path,args[0])):
420 args[0] = os.path.join(path,args[0])
421 elif os.path.isfile(os.path.join(path,'Cards',args[0])):
422 args[0] = os.path.join(path,'Cards',args[0])
423 elif os.path.isfile(os.path.join(path,'HTML',args[0])):
424 args[0] = os.path.join(path,'HTML',args[0])
425
426 elif '_card.dat' in args[0]:
427 name = args[0].replace('_card.dat','_card_default.dat')
428 if os.path.isfile(os.path.join(path,'Cards', name)):
429 files.cp(os.path.join(path,'Cards', name), os.path.join(path,'Cards', args[0]))
430 args[0] = os.path.join(path,'Cards', args[0])
431 else:
432 raise self.InvalidCmd('No default path for this file')
433 elif not os.path.isfile(args[0]):
434 raise self.InvalidCmd('No default path for this file')
435
437 """check that treatcards arguments are valid
438 [param|run|all] [--output_dir=] [--param_card=] [--run_card=]
439 """
440
441 opt = {'output_dir':pjoin(self.me_dir,'Source'),
442 'param_card':pjoin(self.me_dir,'Cards','param_card.dat'),
443 'run_card':pjoin(self.me_dir,'Cards','run_card.dat')}
444 mode = 'all'
445 for arg in args:
446 if arg.startswith('--') and '=' in arg:
447 key,value =arg[2:].split('=',1)
448 if not key in opt:
449 self.help_treatcards()
450 raise self.InvalidCmd('Invalid option for treatcards command:%s ' \
451 % key)
452 if key in ['param_card', 'run_card']:
453 if os.path.isfile(value):
454 card_name = self.detect_card_type(value)
455 if card_name != key:
456 raise self.InvalidCmd('Format for input file detected as %s while expecting %s'
457 % (card_name, key))
458 opt[key] = value
459 elif os.path.isfile(pjoin(self.me_dir,value)):
460 card_name = self.detect_card_type(pjoin(self.me_dir,value))
461 if card_name != key:
462 raise self.InvalidCmd('Format for input file detected as %s while expecting %s'
463 % (card_name, key))
464 opt[key] = value
465 else:
466 raise self.InvalidCmd('No such file: %s ' % value)
467 elif key in ['output_dir']:
468 if os.path.isdir(value):
469 opt[key] = value
470 elif os.path.isdir(pjoin(self.me_dir,value)):
471 opt[key] = pjoin(self.me_dir, value)
472 else:
473 raise self.InvalidCmd('No such directory: %s' % value)
474 elif arg in ['MadLoop','param','run','all']:
475 mode = arg
476 else:
477 self.help_treatcards()
478 raise self.InvalidCmd('Unvalid argument %s' % arg)
479
480 return mode, opt
481
483 """Check the argument for decay_events command
484 syntax is "decay_events [NAME]"
485 Note that other option are already remove at this point
486 """
487
488 opts = []
489 if '-from_cards' in args:
490 args.remove('-from_cards')
491 opts.append('-from_cards')
492
493 if any(t.startswith('--plugin=') for t in args):
494 plugin = [t for t in args if t.startswith('--plugin')][0]
495 args.remove(plugin)
496 opts.append(plugin)
497
498
499 if len(args) == 0:
500 if self.run_name:
501 args.insert(0, self.run_name)
502 elif self.results.lastrun:
503 args.insert(0, self.results.lastrun)
504 else:
505 raise self.InvalidCmd('No run name currently defined. Please add this information.')
506 return
507
508 if args[0] != self.run_name:
509 self.set_run_name(args[0])
510
511 args[0] = self.get_events_path(args[0])
512
513 args += opts
514
515
517 """Check the argument for decay_events command
518 syntax is "decay_events [NAME]"
519 Note that other option are already remove at this point
520 """
521
522 if len(args) == 0:
523 if self.run_name:
524 args.insert(0, self.run_name)
525 elif self.results.lastrun:
526 args.insert(0, self.results.lastrun)
527 else:
528 raise self.InvalidCmd('No run name currently defined. Please add this information.')
529 return
530
531 if args[0] and os.path.isfile(args[0]):
532 pass
533 else:
534 if args[0] != self.run_name:
535 self.set_run_name(args[0], allow_new_tag=False)
536
537 args[0] = self.get_events_path(args[0])
538
539
541 """return the path to the output events
542 """
543
544 if self.mode == 'madevent':
545 possible_path = [
546 pjoin(self.me_dir,'Events', run_name, 'unweighted_events.lhe.gz'),
547 pjoin(self.me_dir,'Events', run_name, 'unweighted_events.lhe')]
548 else:
549 possible_path = [
550 pjoin(self.me_dir,'Events', run_name, 'events.lhe.gz'),
551 pjoin(self.me_dir,'Events', run_name, 'events.lhe')]
552
553 for path in possible_path:
554 if os.path.exists(path):
555 correct_path = path
556 break
557 else:
558 if os.path.exists(run_name):
559 correct_path = run_name
560 else:
561 raise self.InvalidCmd('No events file corresponding to %s run. ' % run_name)
562 return correct_path
563
570
572
573
574
575
576 -class CommonRunCmd(HelpToCmd, CheckValidForCmd, cmd.Cmd):
577
578
579 debug_output = 'ME5_debug'
580 helporder = ['Main Commands', 'Documented commands', 'Require MG5 directory',
581 'Advanced commands']
582 sleep_for_error = True
583
584
585
586 options_configuration = {'pythia8_path': './pythia8',
587 'hwpp_path': './herwigPP',
588 'thepeg_path': './thepeg',
589 'hepmc_path': './hepmc',
590 'madanalysis_path': './MadAnalysis',
591 'madanalysis5_path': './HEPTools/madanalysis5',
592 'pythia-pgs_path':'./pythia-pgs',
593 'td_path':'./td',
594 'delphes_path':'./Delphes',
595 'exrootanalysis_path':'./ExRootAnalysis',
596 'syscalc_path': './SysCalc',
597 'lhapdf': 'lhapdf-config',
598 'lhapdf_py2': None,
599 'lhapdf_py3': None,
600 'timeout': 60,
601 'f2py_compiler':None,
602 'f2py_compiler_py2':None,
603 'f2py_compiler_py3':None,
604 'web_browser':None,
605 'eps_viewer':None,
606 'text_editor':None,
607 'fortran_compiler':None,
608 'cpp_compiler': None,
609 'auto_update':7,
610 'cluster_type': 'condor',
611 'cluster_status_update': (600, 30),
612 'cluster_nb_retry':1,
613 'cluster_local_path': None,
614 'cluster_retry_wait':300}
615
616 options_madgraph= {'stdout_level':None}
617
618 options_madevent = {'automatic_html_opening':True,
619 'notification_center':True,
620 'run_mode':2,
621 'cluster_queue':None,
622 'cluster_time':None,
623 'cluster_size':100,
624 'cluster_memory':None,
625 'nb_core': None,
626 'cluster_temp_path':None}
627
628
629 - def __init__(self, me_dir, options, *args, **opts):
630 """common"""
631
632 self.force_run = False
633 self.stop_for_runweb = False
634 if 'force_run' in opts and opts['force_run']:
635 self.force_run = True
636 del opts['force_run']
637
638 cmd.Cmd.__init__(self, *args, **opts)
639
640 if me_dir is None and MADEVENT:
641 me_dir = root_path
642
643 if os.path.isabs(me_dir):
644 self.me_dir = me_dir
645 else:
646 self.me_dir = pjoin(os.getcwd(),me_dir)
647
648 self.options = options
649
650 self.param_card_iterator = []
651
652
653 self.status = pjoin(self.me_dir, 'status')
654 self.error = pjoin(self.me_dir, 'error')
655 self.dirbin = pjoin(self.me_dir, 'bin', 'internal')
656
657
658 if not self.force_run:
659 if os.path.exists(pjoin(me_dir,'RunWeb')):
660 message = '''Another instance of the program is currently running.
661 (for this exact same directory) Please wait that this is instance is
662 closed. If no instance is running, you can delete the file
663 %s and try again.''' % pjoin(me_dir,'RunWeb')
664 self.stop_for_runweb = True
665 raise AlreadyRunning(message)
666 else:
667 self.write_RunWeb(me_dir)
668
669 self.to_store = []
670 self.run_name = None
671 self.run_tag = None
672 self.banner = None
673
674 self.set_configuration()
675
676
677
678 self.get_characteristics()
679
680 if not self.proc_characteristics['ninitial']:
681
682 nexternal = open(pjoin(self.me_dir,'Source','nexternal.inc')).read()
683 found = re.search("PARAMETER\s*\(NINCOMING=(\d)\)", nexternal)
684 self.ninitial = int(found.group(1))
685 else:
686 self.ninitial = self.proc_characteristics['ninitial']
687
690
691
695
696 @staticmethod
698 pid = os.getpid()
699 fsock = open(pjoin(me_dir,'RunWeb'),'w')
700 fsock.write(repr(pid))
701 fsock.close()
702
704
705 - def __init__(self, me_dir, crashifpresent=True, warnifpresent=True):
706 """raise error if RunWeb already exists
707 me_dir is the directory where the write RunWeb"""
708
709 self.remove_run_web = True
710 self.me_dir = me_dir
711
712 if crashifpresent or warnifpresent:
713 if os.path.exists(pjoin(me_dir, 'RunWeb')):
714 pid = open(pjoin(me_dir, 'RunWeb')).read()
715 try:
716 pid = int(pid)
717 except Exception:
718 pid = "unknown"
719
720 if pid == 'unknown' or misc.pid_exists(pid):
721
722 if crashifpresent:
723 if isinstance(crashifpresent, Exception):
724 raise crashifpresent
725 else:
726 message = '''Another instance of the program is currently running (pid = %s).
727 (for this exact same directory). Please wait that this is instance is
728 closed. If no instance is running, you can delete the file
729 %s and try again.''' % (pid, pjoin(me_dir, 'RunWeb'))
730 raise AlreadyRunning(message)
731 elif warnifpresent:
732 if isinstance( warnifpresent, bool):
733 logger.warning("%s/RunWeb is present. Please check that only one run is running in that directory.")
734 else:
735 logger.log(warnifpresent, "%s/RunWeb is present. Please check that only one run is running in that directory.")
736 self.remove_run_web = False
737 else:
738 logger.debug('RunWeb exists but no associated process. Will Ignore it!')
739 return
740
741
742
743 CommonRunCmd.writeRunWeb(me_dir)
744
747
748 - def __exit__(self,exc_type, exc_value, traceback):
749
750 if self.remove_run_web:
751 try:
752 os.remove(pjoin(self.me_dir,'RunWeb'))
753 except Exception:
754 if os.path.exists(pjoin(self.me_dir,'RunWeb')):
755 logger.warning('fail to remove: %s' % pjoin(self.me_dir,'RunWeb'))
756 return
757
759 """allow to use this as decorator as well"""
760 def wrapper(*args, **kw):
761 with self:
762 return f(*args, **kw)
763 return wrapper
764
765
766
767
768
769
803
804
805 @misc.multiple_try(nb_try=5, sleep=2)
807 """load the current results status"""
808
809
810 if os.path.exists(pjoin(self.me_dir,'HTML','results.pkl')):
811 try:
812 self.results = save_load_object.load_from_file(pjoin(self.me_dir,'HTML','results.pkl'))
813 except Exception:
814
815 model = self.find_model_name()
816 process = self.process
817 self.results = gen_crossxhtml.AllResults(model, process, self.me_dir)
818 self.results.resetall(self.me_dir)
819 else:
820 try:
821 self.results.resetall(self.me_dir)
822 except Exception as error:
823 logger.debug(error)
824
825 model = self.find_model_name()
826 process = self.process
827 self.results = gen_crossxhtml.AllResults(model, process, self.me_dir)
828 self.results.resetall(self.me_dir)
829 self.last_mode = ''
830 try:
831 self.last_mode = self.results[self.results.lastrun][-1]['run_mode']
832 except:
833 self.results.resetall(self.me_dir)
834 self.last_mode = ''
835
836 else:
837 model = self.find_model_name()
838 process = self.process
839 self.results = gen_crossxhtml.AllResults(model, process, self.me_dir)
840 self.results.resetall(self.me_dir)
841 self.last_mode=''
842
843 return self.results
844
845
847 """Advanced commands: create .inc files from param_card.dat/run_card.dat"""
848
849
850
851 if hasattr(self, 'run_card'):
852 self.cluster.modify_interface(self)
853 else:
854 try:
855 self.cluster.modify_interface(self)
856 except Exception as error:
857 misc.sprint(str(error))
858
859 keepwidth = False
860 if '--keepwidth' in line:
861 keepwidth = True
862 line = line.replace('--keepwidth', '')
863 args = self.split_arg(line)
864 mode, opt = self.check_treatcards(args)
865
866 if mode in ['run', 'all']:
867 if not hasattr(self, 'run_card'):
868 run_card = banner_mod.RunCard(opt['run_card'])
869 else:
870 run_card = self.run_card
871
872
873 if amcatnlo and run_card['pdlabel']=='lhapdf':
874 pdfsetsdir=self.get_lhapdf_pdfsetsdir()
875 pdfsets=self.get_lhapdf_pdfsets_list(pdfsetsdir)
876 lhapdfsetname=[]
877 for lhaid in run_card['lhaid']:
878 if lhaid in pdfsets:
879 lhapdfsetname.append(pdfsets[lhaid]['filename'])
880 else:
881 raise MadGraph5Error("lhaid %s is not a valid PDF identification number. This can be due to the use of an outdated version of LHAPDF, or %s is not a LHAGlue number corresponding to a central PDF set (but rather one of the error sets)." % (lhaid,lhaid))
882 run_card['lhapdfsetname']=lhapdfsetname
883 run_card.write_include_file(opt['output_dir'])
884
885 if mode in ['MadLoop', 'all']:
886 if os.path.exists(pjoin(self.me_dir, 'Cards', 'MadLoopParams.dat')):
887 self.MadLoopparam = banner_mod.MadLoopParam(pjoin(self.me_dir,
888 'Cards', 'MadLoopParams.dat'))
889
890 self.MadLoopparam.write(pjoin(self.me_dir,"SubProcesses",
891 "MadLoopParams.dat"))
892
893 if mode in ['param', 'all']:
894 if os.path.exists(pjoin(self.me_dir, 'Source', 'MODEL', 'mp_coupl.inc')):
895 param_card = param_card_mod.ParamCardMP(opt['param_card'])
896 else:
897 param_card = param_card_mod.ParamCard(opt['param_card'])
898 outfile = pjoin(opt['output_dir'], 'param_card.inc')
899 ident_card = pjoin(self.me_dir,'Cards','ident_card.dat')
900 if os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat')):
901 default = pjoin(self.me_dir,'bin','internal','ufomodel','restrict_default.dat')
902 elif os.path.isfile(pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')):
903 default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')
904 elif not os.path.exists(pjoin(self.me_dir,'bin','internal','ufomodel')):
905 fsock = open(pjoin(self.me_dir,'Source','param_card.inc'),'w')
906 fsock.write(' ')
907 fsock.close()
908 return
909 else:
910 devnull = open(os.devnull, 'w')
911 subprocess.call([sys.executable, 'write_param_card.py'],
912 cwd=pjoin(self.me_dir,'bin','internal','ufomodel'), stdout=devnull, stderr=devnull)
913 default = pjoin(self.me_dir,'bin','internal','ufomodel','param_card.dat')
914 if not os.path.exists(default):
915 files.cp(pjoin(self.me_dir, 'Cards','param_card_default.dat'), default)
916
917
918 if amcatnlo and not keepwidth:
919
920 pids = self.get_pid_final_initial_states()
921
922 if pjoin(self.me_dir,'bin','internal','ufomodel') not in sys.path:
923 sys.path.insert(0,pjoin(self.me_dir,'bin','internal', 'ufomodel'))
924 if pjoin(self.me_dir,'bin','internal') not in sys.path:
925 sys.path.insert(0,pjoin(self.me_dir,'bin','internal'))
926
927
928
929 to_del = [name for name in sys.modules.keys()
930 if name.startswith('internal.ufomodel')
931 or name.startswith('ufomodel')]
932 for name in ['particles', 'object_library', 'couplings', 'function_library', 'lorentz', 'parameters', 'vertices', 'coupling_orders', 'write_param_card',
933 'CT_couplings', 'CT_vertices', 'CT_parameters'] + to_del:
934 try:
935 del sys.modules[name]
936 except Exception:
937 continue
938
939
940
941 import ufomodel as ufomodel
942 zero = ufomodel.parameters.ZERO
943 no_width = [p for p in ufomodel.all_particles
944 if (str(p.pdg_code) in pids or str(-p.pdg_code) in pids)
945 and p.color != 1 and p.width != zero]
946 done = []
947 for part in no_width:
948 if abs(part.pdg_code) in done:
949 continue
950 done.append(abs(part.pdg_code))
951 param = param_card['decay'].get((part.pdg_code,))
952
953 if param.value != 0:
954 logger.info('''For gauge cancellation, the width of \'%s\' has been set to zero.'''\
955 % part.name,'$MG:BOLD')
956 param.value = 0
957
958 param_card.write_inc_file(outfile, ident_card, default)
959
961 """return the model related to this process"""
962
963 if self.options['mg5_path']:
964 sys.path.append(self.options['mg5_path'])
965 import models.import_ufo as import_ufo
966 complexmass = self.proc_characteristics['complex_mass_scheme']
967 with misc.MuteLogger(['madgraph.model'],[50]):
968 out= import_ufo.import_model(pjoin(self.me_dir,'bin','internal','ufomodel'),
969 complex_mass_scheme=complexmass)
970 return out
971
972
973
974 else:
975 return None
976
977 - def ask_edit_cards(self, cards, mode='fixed', plot=True, first_cmd=None, from_banner=None,
978 banner=None):
979 """ """
980 if not self.options['madanalysis_path']:
981 plot = False
982
983 self.ask_edit_card_static(cards, mode, plot, self.options['timeout'],
984 self.ask, first_cmd=first_cmd, from_banner=from_banner,
985 banner=banner)
986
987 for c in cards:
988 if not os.path.isabs(c):
989 c = pjoin(self.me_dir, c)
990 if not os.path.exists(c):
991 default = c.replace('dat', '_default.dat')
992 if os.path.exists(default):
993 files.cp(default, c)
994
995
996
997 @staticmethod
1000 if not ask:
1001 ask = CommonRunCmd.ask
1002
1003 def path2name(path):
1004 if '_card' in path:
1005 return path.split('_card')[0]
1006 elif path == 'delphes_trigger.dat':
1007 return 'trigger'
1008 elif path == 'input.lhco':
1009 return 'lhco'
1010 elif path == 'MadLoopParams.dat':
1011 return 'MadLoopParams'
1012 else:
1013 raise Exception('Unknow cards name %s' % path)
1014
1015
1016
1017 question = """Do you want to edit a card (press enter to bypass editing)?\n"""
1018 possible_answer = ['0', 'done']
1019 card = {0:'done'}
1020
1021 indent = max(len(path2name(card_name)) for card_name in cards)
1022 question += '/'+'-'*60+'\\\n'
1023 for i, card_name in enumerate(cards):
1024 imode = path2name(card_name)
1025 possible_answer.append(i+1)
1026 possible_answer.append(imode)
1027 question += '| %-77s|\n'%((' \x1b[31m%%s\x1b[0m. %%-%ds : \x1b[32m%%s\x1b[0m'%indent)%(i+1, imode, card_name))
1028 card[i+1] = imode
1029
1030 if plot and not 'plot_card.dat' in cards:
1031 question += '| %-77s|\n'%((' \x1b[31m9\x1b[0m. %%-%ds : \x1b[32mplot_card.dat\x1b[0m'%indent) % 'plot')
1032 possible_answer.append(9)
1033 possible_answer.append('plot')
1034 card[9] = 'plot'
1035
1036 question += '\\'+'-'*60+'/\n'
1037
1038 if 'param_card.dat' in cards:
1039
1040 question += ' you can also\n'
1041 question += ' - enter the path to a valid card or banner.\n'
1042 question += ' - use the \'set\' command to modify a parameter directly.\n'
1043 question += ' The set option works only for param_card and run_card.\n'
1044 question += ' Type \'help set\' for more information on this command.\n'
1045 question += ' - call an external program (ASperGE/MadWidth/...).\n'
1046 question += ' Type \'help\' for the list of available command\n'
1047 else:
1048 question += ' you can also\n'
1049 question += ' - enter the path to a valid card.\n'
1050 if 'transfer_card.dat' in cards:
1051 question += ' - use the \'change_tf\' command to set a transfer functions.\n'
1052
1053 out = 'to_run'
1054 while out not in ['0', 'done']:
1055 out = ask(question, '0', possible_answer, timeout=int(1.5*timeout),
1056 path_msg='enter path', ask_class = AskforEditCard,
1057 cards=cards, mode=mode, **opt)
1058 if 'return_instance' in opt and opt['return_instance']:
1059 out, cmd = out
1060 if 'return_instance' in opt and opt['return_instance']:
1061 return (out, cmd)
1062 return out
1063
1064 @staticmethod
1066 """detect the type of the card. Return value are
1067 banner
1068 param_card.dat
1069 run_card.dat
1070 pythia_card.dat
1071 pythia8_card.dat
1072 plot_card.dat
1073 pgs_card.dat
1074 delphes_card.dat
1075 delphes_trigger.dat
1076 shower_card.dat [aMCatNLO]
1077 FO_analyse_card.dat [aMCatNLO]
1078 madspin_card.dat [MS]
1079 transfer_card.dat [MW]
1080 madweight_card.dat [MW]
1081 madanalysis5_hadron_card.dat
1082 madanalysis5_parton_card.dat
1083
1084 Please update the unit-test: test_card_type_recognition when adding
1085 cards.
1086 """
1087
1088 fulltext = open(path).read(50000)
1089 if fulltext == '':
1090 logger.warning('File %s is empty' % path)
1091 return 'unknown'
1092
1093 to_search = ['<MGVersion>',
1094 '<mg5proccard>'
1095 'ParticlePropagator',
1096 'ExecutionPath',
1097 'Treewriter',
1098 'CEN_max_tracker',
1099 '#TRIGGER CARD',
1100 'parameter set name',
1101 'muon eta coverage',
1102 'req_acc_FO',
1103 'MSTP',
1104 'b_stable',
1105 'FO_ANALYSIS_FORMAT',
1106 'MSTU',
1107 'Begin Minpts',
1108 'gridpack',
1109 'ebeam1',
1110 'block\s+mw_run',
1111 'BLOCK',
1112 'DECAY',
1113 'launch',
1114 'madspin',
1115 'transfer_card\.dat',
1116 'set',
1117 'main:numberofevents',
1118 '@MG5aMC skip_analysis',
1119 '@MG5aMC\s*inputs\s*=\s*\*\.(?:hepmc|lhe)',
1120 '@MG5aMC\s*reconstruction_name',
1121 '@MG5aMC'
1122 ]
1123
1124
1125 text = re.findall('(%s)' % '|'.join(to_search), fulltext, re.I)
1126 text = [t.lower() for t in text]
1127 if '<mgversion>' in text or '<mg5proccard>' in text:
1128 return 'banner'
1129 elif 'particlepropagator' in text or 'executionpath' in text or 'treewriter' in text:
1130 return 'delphes_card.dat'
1131 elif 'cen_max_tracker' in text:
1132 return 'delphes_card.dat'
1133 elif '@mg5amc' in text:
1134 ma5_flag = [f[7:].strip() for f in text if f.startswith('@mg5amc')]
1135 if any(f.startswith('reconstruction_name') for f in ma5_flag):
1136 return 'madanalysis5_hadron_card.dat'
1137 ma5_flag = [f.split('*.')[1] for f in ma5_flag if '*.' in f]
1138 if any(f.startswith('lhe') for f in ma5_flag):
1139 return 'madanalysis5_parton_card.dat'
1140 if any(f.startswith(('hepmc','hep','stdhep','lhco')) for f in ma5_flag):
1141 return 'madanalysis5_hadron_card.dat'
1142 else:
1143 return 'unknown'
1144 elif '#trigger card' in text:
1145 return 'delphes_trigger.dat'
1146 elif 'parameter set name' in text:
1147 return 'pgs_card.dat'
1148 elif 'muon eta coverage' in text:
1149 return 'pgs_card.dat'
1150 elif 'mstp' in text and not 'b_stable' in text:
1151 return 'pythia_card.dat'
1152 elif 'begin minpts' in text:
1153 return 'plot_card.dat'
1154 elif ('gridpack' in text and 'ebeam1' in text) or \
1155 ('req_acc_fo' in text and 'ebeam1' in text):
1156 return 'run_card.dat'
1157 elif any(t.endswith('mw_run') for t in text):
1158 return 'madweight_card.dat'
1159 elif 'transfer_card.dat' in text:
1160 return 'transfer_card.dat'
1161 elif 'block' in text and 'decay' in text:
1162 return 'param_card.dat'
1163 elif 'b_stable' in text:
1164 return 'shower_card.dat'
1165 elif 'fo_analysis_format' in text:
1166 return 'FO_analyse_card.dat'
1167 elif 'main:numberofevents' in text:
1168 return 'pythia8_card.dat'
1169 elif 'launch' in text:
1170
1171
1172 if 'madspin' in text:
1173 return 'madspin_card.dat'
1174 if 'decay' in text:
1175
1176 if re.search("(^|;)\s*decay", fulltext):
1177 return 'madspin_card.dat'
1178 else:
1179 return 'reweight_card.dat'
1180 else:
1181 return 'reweight_card.dat'
1182 else:
1183 return 'unknown'
1184
1185
1186
1188 """create automatically a tag"""
1189
1190 used_tags = [r['tag'] for r in self.results[self.run_name]]
1191 i=0
1192 while 1:
1193 i+=1
1194 if 'tag_%s' %i not in used_tags:
1195 return 'tag_%s' % i
1196
1197
1198
1199 @misc.mute_logger(names=['madgraph.various.histograms',
1200 'internal.histograms'],levels=[20,20])
1204 """Generated the HwU plots from Pythia8 driver output for a specific
1205 observable."""
1206
1207 try:
1208 import madgraph
1209 except ImportError:
1210 import internal.histograms as histograms
1211 else:
1212 import madgraph.various.histograms as histograms
1213
1214
1215 if not os.path.isfile(data_path):
1216 return False
1217
1218
1219 histos = histograms.HwUList(data_path, consider_reweights='ALL',run_id=0)
1220 if len(histos)==0:
1221 return False
1222
1223
1224 merging_scales_available = [label[1] for label in \
1225 histos[0].bins.weight_labels if
1226 histograms.HwU.get_HwU_wgt_label_type(label)=='merging_scale']
1227 if len(merging_scales_available)>=2:
1228 min_merging_scale = min(merging_scales_available)
1229 max_merging_scale = max(merging_scales_available)
1230 else:
1231 min_merging_scale = None
1232 max_merging_scale = None
1233
1234
1235 histo_output_options = {
1236 'format':'gnuplot',
1237 'uncertainties':['scale','pdf','statistical',
1238 'merging_scale','alpsfact'],
1239 'ratio_correlations':True,
1240 'arg_string':'Automatic plotting from MG5aMC',
1241 'jet_samples_to_keep':None,
1242 'use_band':['merging_scale','alpsfact'],
1243 'auto_open':False
1244 }
1245
1246 if not (int(self.run_card['ickkw'])==1):
1247 histo_output_options['uncertainties'].pop(
1248 histo_output_options['uncertainties'].index('alpsfact'))
1249 histo_output_options['use_band'].pop(
1250 histo_output_options['use_band'].index('alpsfact'))
1251
1252 histos.output(pjoin(plot_root_path,
1253 'central_%s_%s_plots'%(merging_scale_name,observable_name)),
1254 **histo_output_options)
1255
1256 for scale in merging_scales_available:
1257 that_scale_histos = histograms.HwUList(
1258 data_path, run_id=0, merging_scale=scale)
1259 that_scale_histos.output(pjoin(plot_root_path,
1260 '%s_%.3g_%s_plots'%(merging_scale_name,scale,observable_name)),
1261 **histo_output_options)
1262
1263
1264
1265
1266 if not min_merging_scale is None:
1267 min_scale_histos = histograms.HwUList(data_path,
1268 consider_reweights=[], run_id=0,
1269 merging_scale=min_merging_scale)
1270 max_scale_histos = histograms.HwUList(data_path,
1271 consider_reweights=[], run_id=0,
1272 merging_scale=max_merging_scale)
1273
1274
1275 for histo in min_scale_histos:
1276 if histo.type is None:
1277 histo.type = '%s=%.4g'%(merging_scale_name, min_merging_scale)
1278 else:
1279 histo.type += '|%s=%.4g'%(merging_scale_name, min_merging_scale)
1280 for histo in max_scale_histos:
1281 if histo.type is None:
1282 histo.type = '%s=%.4g'%(merging_scale_name, max_merging_scale)
1283 else:
1284 histo.type += '|%s=%.4g'%(merging_scale_name, max_merging_scale)
1285
1286
1287 histograms.HwUList(min_scale_histos+max_scale_histos).output(
1288 pjoin(plot_root_path,'min_max_%s_%s_comparison'
1289 %(merging_scale_name,observable_name)),
1290 format='gnuplot',
1291 uncertainties=[],
1292 ratio_correlations=True,
1293 arg_string='Automatic plotting from MG5aMC',
1294 jet_samples_to_keep=None,
1295 use_band=[],
1296 auto_open=False)
1297 return True
1298
1300 """ """
1301 devnull = open(os.devnull, 'w')
1302 try:
1303 misc.call(['./bin/internal/gen_cardhtml-pl'], cwd=self.me_dir,
1304 stdout=devnull, stderr=devnull)
1305 except Exception:
1306 pass
1307 devnull.close()
1308
1309
1310 - def create_plot(self, mode='parton', event_path=None, output=None, tag=None):
1311 """create the plot"""
1312
1313 if not tag:
1314 tag = self.run_card['run_tag']
1315
1316 if mode != 'Pythia8':
1317 madir = self.options['madanalysis_path']
1318 td = self.options['td_path']
1319
1320 if not madir or not td or \
1321 not os.path.exists(pjoin(self.me_dir, 'Cards', 'plot_card.dat')):
1322 return False
1323 else:
1324 PY8_plots_root_path = pjoin(self.me_dir,'HTML',
1325 self.run_name,'%s_PY8_plots'%tag)
1326
1327 if 'ickkw' in self.run_card:
1328 if int(self.run_card['ickkw']) and mode == 'Pythia':
1329 self.update_status('Create matching plots for Pythia', level='pythia')
1330
1331 if not os.path.exists(pjoin(self.me_dir,'Events','events.tree')):
1332 misc.gunzip(pjoin(self.me_dir,'Events',
1333 self.run_name, '%s_pythia_events.tree.gz' % tag), keep=True,
1334 stdout=pjoin(self.me_dir,'Events','events.tree'))
1335 files.mv(pjoin(self.me_dir,'Events',self.run_name, tag+'_pythia_xsecs.tree'),
1336 pjoin(self.me_dir,'Events','xsecs.tree'))
1337
1338
1339 misc.call([self.dirbin+'/create_matching_plots.sh',
1340 self.run_name, tag, madir],
1341 stdout = os.open(os.devnull, os.O_RDWR),
1342 cwd=pjoin(self.me_dir,'Events'))
1343
1344
1345 misc.gzip(pjoin(self.me_dir,"Events","events.tree"),
1346 stdout=pjoin(self.me_dir,'Events',self.run_name, tag + '_pythia_events.tree.gz'))
1347 files.mv(pjoin(self.me_dir,'Events','xsecs.tree'),
1348 pjoin(self.me_dir,'Events',self.run_name, tag+'_pythia_xsecs.tree'))
1349
1350 elif mode == 'Pythia8' and (int(self.run_card['ickkw'])==1 or \
1351 self.run_card['ktdurham']>0.0 or self.run_card['ptlund']>0.0):
1352
1353 self.update_status('Create matching plots for Pythia8',
1354 level='pythia8')
1355
1356
1357 if not os.path.isdir(PY8_plots_root_path):
1358 os.makedirs(PY8_plots_root_path)
1359
1360 merging_scale_name = 'qCut' if int(self.run_card['ickkw'])==1 \
1361 else 'TMS'
1362
1363 djr_path = pjoin(self.me_dir,'Events',
1364 self.run_name, '%s_djrs.dat' % tag)
1365 pt_path = pjoin(self.me_dir,'Events',
1366 self.run_name, '%s_pts.dat' % tag)
1367 for observable_name, data_path in [('djr',djr_path),
1368 ('pt',pt_path)]:
1369 if not self.generate_Pythia8_HwU_plots(
1370 PY8_plots_root_path, merging_scale_name,
1371 observable_name,data_path):
1372 return False
1373
1374 if mode == 'Pythia8':
1375 plot_files = glob.glob(pjoin(PY8_plots_root_path,'*.gnuplot'))
1376 if not misc.which('gnuplot'):
1377 logger.warning("Install gnuplot to be able to view the plots"+\
1378 " generated at :\n "+\
1379 '\n '.join('%s.gnuplot'%p for p in plot_files))
1380 return True
1381 for plot in plot_files:
1382 command = ['gnuplot',plot]
1383 try:
1384 subprocess.call(command,cwd=PY8_plots_root_path,stderr=subprocess.PIPE)
1385 except Exception as e:
1386 logger.warning("Automatic processing of the Pythia8 "+\
1387 "merging plots with gnuplot failed. Try the"+\
1388 " following command by hand:\n %s"%(' '.join(command))+\
1389 "\nException was: %s"%str(e))
1390 return False
1391
1392 plot_files = glob.glob(pjoin(PY8_plots_root_path,'*.pdf'))
1393 if len(plot_files)>0:
1394
1395 html = "<html>\n<head>\n<TITLE>PLOT FOR PYTHIA8</TITLE>"
1396 html+= '<link rel=stylesheet href="../../mgstyle.css" type="text/css">\n</head>\n<body>\n'
1397 html += "<h2> Plot for Pythia8 </h2>\n"
1398 html += '<a href=../../../crossx.html>return to summary</a><br>'
1399 html += "<table>\n<tr> <td> <b>Obs.</b> </td> <td> <b>Type of plot</b> </td> <td><b> PDF</b> </td> <td><b> input file</b> </td> </tr>\n"
1400 def sorted_plots(elem):
1401 name = os.path.basename(elem[1])
1402 if 'central' in name:
1403 return -100
1404 if 'min_max' in name:
1405 return -10
1406 merging_re = re.match(r'^.*_(\d+)_.*$',name)
1407 if not merging_re is None:
1408 return int(merging_re.group(1))
1409 else:
1410 return 1e10
1411 djr_plot_files = sorted(
1412 (('DJR',p) for p in plot_files if '_djr_' in p),
1413 key = sorted_plots)
1414 pt_plot_files = sorted(
1415 (('Pt',p) for p in plot_files if '_pt_' in p),
1416 key = sorted_plots)
1417 last_obs = None
1418 for obs, one_plot in djr_plot_files+pt_plot_files:
1419 if obs!=last_obs:
1420
1421 html += "<tr><td></td></tr>"
1422 last_obs = obs
1423 name = os.path.basename(one_plot).replace('.pdf','')
1424 short_name = name
1425 for dummy in ['_plots','_djr','_pt']:
1426 short_name = short_name.replace(dummy,'')
1427 short_name = short_name.replace('_',' ')
1428 if 'min max' in short_name:
1429 short_name = "%s comparison with min/max merging scale"%obs
1430 if 'central' in short_name:
1431 short_name = "Merging uncertainty band around central scale"
1432 html += "<tr><td>%(obs)s</td><td>%(sn)s</td><td> <a href=./%(n)s.pdf>PDF</a> </td><td> <a href=./%(n)s.HwU>HwU</a> <a href=./%(n)s.gnuplot>GNUPLOT</a> </td></tr>\n" %\
1433 {'obs':obs, 'sn': short_name, 'n': name}
1434 html += '</table>\n'
1435 html += '<a href=../../../bin/internal/plot_djrs.py> Example of code to plot the above with matplotlib </a><br><br>'
1436 html+='</body>\n</html>'
1437 ff=open(pjoin(PY8_plots_root_path, 'index.html'),'w')
1438 ff.write(html)
1439 return True
1440
1441 if not event_path:
1442 if mode == 'parton':
1443 possibilities=[
1444 pjoin(self.me_dir, 'Events', 'unweighted_events.lhe'),
1445 pjoin(self.me_dir, 'Events', 'unweighted_events.lhe.gz'),
1446 pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe'),
1447 pjoin(self.me_dir, 'Events', self.run_name, 'unweighted_events.lhe.gz')]
1448 for event_path in possibilities:
1449 if os.path.exists(event_path):
1450 break
1451 output = pjoin(self.me_dir, 'HTML',self.run_name, 'plots_parton.html')
1452
1453 elif mode == 'Pythia':
1454 event_path = pjoin(self.me_dir, 'Events','pythia_events.lhe')
1455 output = pjoin(self.me_dir, 'HTML',self.run_name,
1456 'plots_pythia_%s.html' % tag)
1457 elif mode == 'PGS':
1458 event_path = pjoin(self.me_dir, 'Events', self.run_name,
1459 '%s_pgs_events.lhco' % tag)
1460 output = pjoin(self.me_dir, 'HTML',self.run_name,
1461 'plots_pgs_%s.html' % tag)
1462 elif mode == 'Delphes':
1463 event_path = pjoin(self.me_dir, 'Events', self.run_name,'%s_delphes_events.lhco' % tag)
1464 output = pjoin(self.me_dir, 'HTML',self.run_name,
1465 'plots_delphes_%s.html' % tag)
1466 elif mode == "shower":
1467 event_path = pjoin(self.me_dir, 'Events','pythia_events.lhe')
1468 output = pjoin(self.me_dir, 'HTML',self.run_name,
1469 'plots_shower_%s.html' % tag)
1470 if not self.options['pythia-pgs_path']:
1471 return
1472 else:
1473 raise self.InvalidCmd('Invalid mode %s' % mode)
1474 elif mode == 'reweight' and not output:
1475 output = pjoin(self.me_dir, 'HTML',self.run_name,
1476 'plots_%s.html' % tag)
1477
1478 if not os.path.exists(event_path):
1479 if os.path.exists(event_path+'.gz'):
1480 misc.gunzip('%s.gz' % event_path)
1481 else:
1482 raise self.InvalidCmd('Events file %s does not exist' % event_path)
1483 elif event_path.endswith(".gz"):
1484 misc.gunzip(event_path, keep=True)
1485 event_path = event_path[:-3]
1486
1487
1488 self.update_status('Creating Plots for %s level' % mode, level = mode.lower())
1489
1490 mode = mode.lower()
1491 if mode not in ['parton', 'reweight']:
1492 plot_dir = pjoin(self.me_dir, 'HTML', self.run_name,'plots_%s_%s' % (mode.lower(),tag))
1493 elif mode == 'parton':
1494 plot_dir = pjoin(self.me_dir, 'HTML', self.run_name,'plots_parton')
1495 else:
1496 plot_dir =pjoin(self.me_dir, 'HTML', self.run_name,'plots_%s' % (tag))
1497
1498 if not os.path.isdir(plot_dir):
1499 os.makedirs(plot_dir)
1500
1501 files.ln(pjoin(self.me_dir, 'Cards','plot_card.dat'), plot_dir, 'ma_card.dat')
1502
1503 try:
1504 proc = misc.Popen([os.path.join(madir, 'plot_events')],
1505 stdout = open(pjoin(plot_dir, 'plot.log'),'w'),
1506 stderr = subprocess.STDOUT,
1507 stdin=subprocess.PIPE,
1508 cwd=plot_dir)
1509 proc.communicate(('%s\n' % event_path).encode('utf-8'))
1510 del proc
1511
1512 misc.call(['%s/plot' % self.dirbin, madir, td],
1513 stdout = open(pjoin(plot_dir, 'plot.log'),'a'),
1514 stderr = subprocess.STDOUT,
1515 cwd=plot_dir)
1516
1517 misc.call(['%s/plot_page-pl' % self.dirbin,
1518 os.path.basename(plot_dir),
1519 mode],
1520 stdout = open(pjoin(plot_dir, 'plot.log'),'a'),
1521 stderr = subprocess.STDOUT,
1522 cwd=pjoin(self.me_dir, 'HTML', self.run_name))
1523
1524 shutil.move(pjoin(self.me_dir, 'HTML',self.run_name ,'plots.html'),
1525 output)
1526
1527 logger.info("Plots for %s level generated, see %s" % \
1528 (mode, output))
1529 except OSError as error:
1530 logger.error('fail to create plot: %s. Please check that MadAnalysis is correctly installed.' % error)
1531
1532 self.update_status('End Plots for %s level' % mode, level = mode.lower(),
1533 makehtml=False)
1534
1535
1536 return True
1537
1539 """Run hep2lhe on the file Events/pythia_events.hep"""
1540
1541 if not self.options['pythia-pgs_path']:
1542 raise self.InvalidCmd('No pythia-pgs path defined')
1543
1544 pydir = pjoin(self.options['pythia-pgs_path'], 'src')
1545 eradir = self.options['exrootanalysis_path']
1546
1547
1548 if misc.is_executable(pjoin(pydir, 'hep2lhe')):
1549 self.update_status('Creating shower LHE File (for plot)', level='pythia')
1550
1551 out = open(pjoin(self.me_dir,'Events','pythia_events.lhe'), 'w')
1552
1553 out.writelines('<!--\n')
1554 out.writelines('# Warning! Never use this file for detector studies!\n')
1555 out.writelines('-->\n<!--\n')
1556 if banner_path:
1557 out.writelines(open(banner_path).read().replace('<LesHouchesEvents version="1.0">',''))
1558 out.writelines('\n-->\n')
1559 out.close()
1560
1561 self.cluster.launch_and_wait(self.dirbin+'/run_hep2lhe',
1562 argument= [pydir],
1563 cwd=pjoin(self.me_dir,'Events'),
1564 stdout=os.devnull)
1565
1566 logger.info('Warning! Never use this lhe file for detector studies!')
1567
1568 if eradir and misc.is_executable(pjoin(eradir, 'ExRootLHEFConverter')):
1569 self.update_status('Creating Pythia LHE Root File', level='pythia')
1570 try:
1571 misc.call([eradir+'/ExRootLHEFConverter',
1572 'pythia_events.lhe',
1573 pjoin(self.run_name, '%s_pythia_lhe_events.root' % self.run_tag)],
1574 cwd=pjoin(self.me_dir,'Events'))
1575 except Exception as error:
1576 misc.sprint('ExRootLHEFConverter fails', str(error),
1577 log=logger)
1578 pass
1579
1581 """Dummy routine, to be overwritten by daughter classes"""
1582
1583 pass
1584
1585
1587 """help for systematics command"""
1588 logger.info("syntax: systematics RUN_NAME [OUTPUT] [options]",'$MG:BOLD')
1589 logger.info("-- Run the systematics run on the RUN_NAME run.")
1590 logger.info(" RUN_NAME can be a path to a lhef file.")
1591 logger.info(" OUTPUT can be the path to the output lhe file, otherwise the input file will be overwritten")
1592 logger.info("")
1593 logger.info("options: (values written are the default)", '$MG:BOLD')
1594 logger.info("")
1595 logger.info(" --mur=0.5,1,2 # specify the values for renormalisation scale variation")
1596 logger.info(" --muf=0.5,1,2 # specify the values for factorisation scale variation")
1597 logger.info(" --alps=1 # specify the values for MLM emission scale variation (LO only)")
1598 logger.info(" --dyn=-1,1,2,3,4 # specify the dynamical schemes to use.")
1599 logger.info(" # -1 is the one used by the sample.")
1600 logger.info(" # > 0 correspond to options of dynamical_scale_choice of the run_card.")
1601 logger.info(" --pdf=errorset # specify the pdfs to use for pdf variation. (see below)")
1602 logger.info(" --together=mur,muf,dyn # lists the parameter that must be varied simultaneously so as to ")
1603 logger.info(" # compute the weights for all combinations of their variations.")
1604 logger.info(" --from_card # use the information from the run_card (LO only).")
1605 logger.info(" --remove_weights= # remove previously written weights matching the descriptions")
1606 logger.info(" --keep_weights= # force to keep the weight even if in the list of remove_weights")
1607 logger.info(" --start_id= # define the starting digit for the additial weight. If not specify it is determine automatically")
1608 logger.info(" --only_beam=0 # only apply the new pdf set to the beam selected.")
1609 logger.info(" --ion_scaling=True# if original sample was using rescaled PDF: apply the same rescaling for all PDF sets.")
1610 logger.info(" --weight_format=\"%(id)i\" # allow to customise the name of the weight. The resulting name SHOULD be unique.")
1611 logger.info(" --weight_info= # allow to customise the text describing the weights.")
1612 logger.info("")
1613 logger.info(" Allowed value for the pdf options:", '$MG:BOLD')
1614 logger.info(" central : Do not perform any pdf variation" )
1615 logger.info(" errorset : runs over the all the members of the PDF set used to generate the events")
1616 logger.info(" 244800 : runs over the associated set and all its members")
1617 logger.info(" 244800@0 : runs over the central member of the associated set")
1618
1619 logger.info(" CT10 : runs over the associated set and all its members")
1620 logger.info(" CT10@0 : runs over the central member of the associated set")
1621 logger.info(" CT10@X : runs over the Xth member of the associated PDF set")
1622 logger.info(" XX,YY,ZZ : runs over the sets for XX,YY,ZZ (those three follows above syntax)")
1623 logger.info("")
1624 logger.info(" Allowed value for the keep/remove_wgts options:", '$MG:BOLD')
1625 logger.info(" all : keep/remove all weights")
1626 logger.info(" name : keep/remove that particular weight")
1627 logger.info(" id1,id2 : keep/remove all the weights between those two values --included--")
1628 logger.info(" PATTERN : keep/remove all the weights matching the (python) regular expression.")
1629 logger.info(" note that multiple entry of those arguments are allowed")
1630 logger.info("")
1631 logger.info(" Input for weight format")
1632 logger.info(" The parameter will be interpreted by python using: https://docs.python.org/2/library/stdtypes.html#string-formatting")
1633 logger.info(" The allowed parameters are 'muf','mur','pdf','dyn','alps','id'")
1635 """auto completion for the systematics command"""
1636
1637 args = self.split_arg(line[0:begidx], error=False)
1638 options = ['--mur=', '--muf=', '--pdf=', '--dyn=','--alps=',
1639 '--together=','--from_card ','--remove_wgts=',
1640 '--keep_wgts=','--start_id=']
1641
1642 if len(args) == 1 and os.path.sep not in text:
1643
1644 data = misc.glob(pjoin('*','*events.lhe*'), pjoin(self.me_dir, 'Events'))
1645 data = [n.rsplit('/',2)[1] for n in data]
1646 return self.list_completion(text, data, line)
1647 elif len(args)==1:
1648
1649 return self.path_completion(text,
1650 os.path.join('.',*[a for a in args \
1651 if a.endswith(os.path.sep)]))
1652 elif len(args)==2 and os.path.sep in args[1]:
1653
1654 return self.path_completion(text, '.')
1655
1656 elif not line.endswith(tuple(options)):
1657 return self.list_completion(text, options)
1658
1659
1660
1662 """ syntax is 'systematics [INPUT [OUTPUT]] OPTIONS'
1663 --mur=0.5,1,2
1664 --muf=0.5,1,2
1665 --alps=1
1666 --dyn=-1
1667 --together=mur,muf #can be repeated
1668
1669 #special options
1670 --from_card=
1671 """
1672
1673 try:
1674 lhapdf_version = self.get_lhapdf_version()
1675 except Exception:
1676 logger.info('No version of lhapdf. Can not run systematics computation')
1677 return
1678 else:
1679 if lhapdf_version.startswith('5'):
1680 logger.info('can not run systematics with lhapdf 5')
1681 return
1682
1683 lhapdf = misc.import_python_lhapdf(self.options['lhapdf'])
1684 if not lhapdf:
1685 logger.info('can not run systematics since can not link python to lhapdf')
1686 return
1687
1688
1689
1690
1691 self.update_status('Running Systematics computation', level='parton')
1692 args = self.split_arg(line)
1693
1694 opts= []
1695 args = [a for a in args if not a.startswith('-') or opts.append(a)]
1696
1697
1698 if any(not o.startswith(('--mur=', '--muf=', '--alps=','--dyn=','--together=','--from_card','--pdf=',
1699 '--remove_wgts=', '--keep_wgts','--start_id=', '--weight_format=',
1700 '--weight_info='))
1701 for o in opts):
1702 raise self.InvalidCmd("command systematics called with invalid option syntax. Please retry.")
1703
1704
1705 if len(args) == 0:
1706 if self.run_name:
1707 args[0] = self.run_name
1708 else:
1709 raise self.InvalidCmd('no default run. Please specify the run_name')
1710
1711 if args[0] != self.run_name:
1712 self.set_run_name(args[0])
1713
1714
1715 result_file= sys.stdout
1716 if not os.path.isfile(args[0]) and not os.path.sep in args[0]:
1717 path = [pjoin(self.me_dir, 'Events', args[0], 'unweighted_events.lhe.gz'),
1718 pjoin(self.me_dir, 'Events', args[0], 'unweighted_events.lhe'),
1719 pjoin(self.me_dir, 'Events', args[0], 'events.lhe.gz'),
1720 pjoin(self.me_dir, 'Events', args[0], 'events.lhe')]
1721
1722 for p in path:
1723 if os.path.exists(p):
1724 nb_event = self.results[args[0]].get_current_info()['nb_event']
1725
1726
1727 if self.run_name != args[0]:
1728 tag = self.results[args[0]].tags[0]
1729 self.set_run_name(args[0], tag,'parton', False)
1730 result_file = open(pjoin(self.me_dir,'Events', self.run_name, 'parton_systematics.log'),'w')
1731 args[0] = p
1732 break
1733 else:
1734 raise self.InvalidCmd('Invalid run name. Please retry')
1735 elif self.options['nb_core'] != 1:
1736 lhe = lhe_parser.EventFile(args[0])
1737 nb_event = len(lhe)
1738 lhe.close()
1739
1740 input = args[0]
1741 if len(args)>1:
1742 output = pjoin(os.getcwd(),args[1])
1743 else:
1744 output = input
1745
1746 lhaid = [self.run_card.get_lhapdf_id()]
1747 if 'store_rwgt_info' in self.run_card and not self.run_card['store_rwgt_info']:
1748 raise self.InvalidCmd("The events was not generated with store_rwgt_info=True. Can not evaluate systematics error on this event file.")
1749 elif 'use_syst' in self.run_card:
1750 if not self.run_card['use_syst']:
1751 raise self.InvalidCmd("The events was not generated with use_syst=True. Can not evaluate systematics error on this event file.")
1752 elif self.proc_characteristics['ninitial'] ==1:
1753 if '--from_card' in opts:
1754 logger.warning('systematics not available for decay processes. Bypass it')
1755 return
1756 else:
1757 raise self.InvalidCmd('systematics not available for decay processes.')
1758
1759 try:
1760 pdfsets_dir = self.get_lhapdf_pdfsetsdir()
1761 except Exception as error:
1762 logger.debug(str(error))
1763 logger.warning('Systematic computation requires lhapdf to run. Bypass Systematics')
1764 return
1765
1766 if '--from_card' in opts:
1767 opts.remove('--from_card')
1768 opts.append('--from_card=internal')
1769
1770
1771 if 'systematics_arguments' in self.run_card.user_set:
1772 pdf = [a[6:] for a in self.run_card['systematics_arguments']
1773 if a.startswith('--pdf=')]
1774 lhaid += [t.split('@')[0] for p in pdf for t in p.split(',')
1775 if t not in ['errorset', 'central']]
1776 elif 'sys_pdf' in self.run_card.user_set:
1777 if '&&' in self.run_card['sys_pdf']:
1778 if isinstance(self.run_card['sys_pdf'], list):
1779 line = ' '.join(self.run_card['sys_pdf'])
1780 else:
1781 line = self.run_card['sys_pdf']
1782 sys_pdf = line.split('&&')
1783 lhaid += [l.split()[0] for l in sys_pdf]
1784 else:
1785 lhaid += [l for l in self.run_card['sys_pdf'].split() if not l.isdigit() or int(l) > 500]
1786
1787 else:
1788
1789 pdf = [a[6:] for a in opts if a.startswith('--pdf=')]
1790 lhaid += [t.split('@')[0] for p in pdf for t in p.split(',')
1791 if t not in ['errorset', 'central']]
1792
1793
1794 try:
1795 [self.copy_lhapdf_set([onelha], pdfsets_dir, require_local=False) for onelha in lhaid]
1796 except Exception as error:
1797 logger.debug(str(error))
1798 logger.warning('impossible to download all the pdfsets. Bypass systematics')
1799 return
1800
1801 if self.options['run_mode'] ==2 and self.options['nb_core'] != 1:
1802 nb_submit = min(int(self.options['nb_core']), nb_event//2500)
1803 elif self.options['run_mode'] ==1:
1804 try:
1805 nb_submit = min(int(self.options['cluster_size']), nb_event//25000)
1806 except Exception:
1807 nb_submit =1
1808 else:
1809 nb_submit =1
1810
1811 if MADEVENT:
1812 import internal.systematics as systematics
1813 else:
1814 import madgraph.various.systematics as systematics
1815
1816
1817 if nb_submit in [0,1]:
1818 systematics.call_systematics([input, output] + opts,
1819 log=lambda x: logger.info(str(x)),
1820 result=result_file
1821 )
1822
1823 elif self.options['run_mode'] in [1,2]:
1824 event_per_job = nb_event // nb_submit
1825 nb_job_with_plus_one = nb_event % nb_submit
1826 start_event, stop_event = 0,0
1827 if sys.version_info[1] == 6 and sys.version_info[0] == 2:
1828 if input.endswith('.gz'):
1829 misc.gunzip(input)
1830 input = input[:-3]
1831
1832 for i in range(nb_submit):
1833
1834 event_requested = event_per_job
1835 if i < nb_job_with_plus_one:
1836 event_requested += 1
1837 start_event = stop_event
1838 stop_event = start_event + event_requested
1839
1840 prog = sys.executable
1841 input_files = [os.path.basename(input)]
1842 output_files = ['./tmp_%s_%s' % (i, os.path.basename(output)),
1843 './log_sys_%s.txt' % (i)]
1844 argument = []
1845 if not __debug__:
1846 argument.append('-O')
1847 argument += [pjoin(self.me_dir, 'bin', 'internal', 'systematics.py'),
1848 input_files[0], output_files[0]] + opts +\
1849 ['--start_event=%i' % start_event,
1850 '--stop_event=%i' %stop_event,
1851 '--result=./log_sys_%s.txt' %i,
1852 '--lhapdf_config=%s' % self.options['lhapdf']]
1853 required_output = output_files
1854 self.cluster.cluster_submit(prog, argument,
1855 input_files=input_files,
1856 output_files=output_files,
1857 cwd=os.path.dirname(output),
1858 required_output=required_output,
1859 stdout='/dev/null'
1860 )
1861 starttime = time.time()
1862 update_status = lambda idle, run, finish: \
1863 self.update_status((idle, run, finish, 'running systematics'), level=None,
1864 force=False, starttime=starttime)
1865
1866 try:
1867 self.cluster.wait(os.path.dirname(output), update_status, update_first=update_status)
1868 except Exception:
1869 self.cluster.remove()
1870 old_run_mode = self.options['run_mode']
1871 self.options['run_mode'] =0
1872 try:
1873 out = self.do_systematics(line)
1874 finally:
1875 self.options['run_mode'] = old_run_mode
1876
1877 all_cross = []
1878 for i in range(nb_submit):
1879 pos=0
1880 for line in open(pjoin(os.path.dirname(output), 'log_sys_%s.txt'%i)):
1881 if line.startswith('#'):
1882 continue
1883 split = line.split()
1884 if len(split) in [0,1]:
1885 continue
1886 key = tuple(float(x) for x in split[:-1])
1887 cross= float(split[-1])
1888 if 'event_norm' in self.run_card and \
1889 self.run_card['event_norm'] in ['average', 'unity', 'bias']:
1890 cross *= (event_per_job+1 if i <nb_job_with_plus_one else event_per_job)
1891 if len(all_cross) > pos:
1892 all_cross[pos] += cross
1893 else:
1894 all_cross.append(cross)
1895 pos+=1
1896
1897 if 'event_norm' in self.run_card and \
1898 self.run_card['event_norm'] in ['unity']:
1899 all_cross= [cross/nb_event for cross in all_cross]
1900
1901 sys_obj = systematics.call_systematics([input, None] + opts,
1902 log=lambda x: logger.info(str(x)),
1903 result=result_file,
1904 running=False
1905 )
1906 sys_obj.print_cross_sections(all_cross, nb_event, result_file)
1907
1908
1909 subprocess.call(['cat']+\
1910 ['./tmp_%s_%s' % (i, os.path.basename(output)) for i in range(nb_submit)],
1911 stdout=open(output,'w'),
1912 cwd=os.path.dirname(output))
1913 for i in range(nb_submit):
1914 os.remove('%s/tmp_%s_%s' %(os.path.dirname(output),i,os.path.basename(output)))
1915
1916
1917
1918
1919
1920
1921 self.update_status('End of systematics computation', level='parton', makehtml=False)
1922
1923
1924
1926 """ syntax is "reweight RUN_NAME"
1927 Allow to reweight the events generated with a new choices of model
1928 parameter. Description of the methods are available here
1929 cp3.irmp.ucl.ac.be/projects/madgraph/wiki/Reweight
1930 """
1931
1932
1933
1934 def check_multicore(self):
1935 """ determine if the cards are save for multicore use"""
1936 card = pjoin(self.me_dir, 'Cards', 'reweight_card.dat')
1937
1938 multicore = True
1939 if self.options['run_mode'] in [0,1]:
1940 return False
1941
1942 lines = [l.strip() for l in open(card) if not l.strip().startswith('#')]
1943 while lines and not lines[0].startswith('launch'):
1944 line = lines.pop(0)
1945
1946 if line.startswith('change') and line[6:].strip().startswith('output'):
1947 return False
1948 if line.startswith('change') and line[6:].strip().startswith('multicore'):
1949 split_line = line.split()
1950 if len(split_line) > 2:
1951 multicore = bool(split_line[2])
1952
1953
1954 lines = [line[6:].strip() for line in lines if line.startswith('change')]
1955 for line in lines:
1956 if line.startswith(('process','model','output', 'rwgt_dir')):
1957 return False
1958 elif line.startswith('multicore'):
1959 split_line = line.split()
1960 if len(split_line) > 1:
1961 multicore = bool(split_line[1])
1962
1963 return multicore
1964
1965
1966
1967 if '-from_cards' in line and not os.path.exists(pjoin(self.me_dir, 'Cards', 'reweight_card.dat')):
1968 return
1969
1970 if '--multicore=create' in line:
1971 multicore='create'
1972 elif '--multicore=wait' in line:
1973 multicore='wait'
1974 else:
1975 multicore=False
1976
1977
1978 plugin = False
1979 if '--plugin=' in line:
1980 plugin = [l.split('=',1)[1] for l in line.split() if '--plugin=' in l][0]
1981 elif hasattr(self, 'switch') and self.switch['reweight'] not in ['ON','OFF']:
1982 plugin=self.switch['reweight']
1983
1984
1985
1986
1987 if MADEVENT and not self.options['mg5_path']:
1988 raise self.InvalidCmd('''The module reweight requires that MG5 is installed on the system.
1989 You can install it and set its path in ./Cards/me5_configuration.txt''')
1990 elif MADEVENT:
1991 sys.path.append(self.options['mg5_path'])
1992 try:
1993 import madgraph.interface.reweight_interface as reweight_interface
1994 except ImportError:
1995 raise self.ConfigurationError('''Can\'t load Reweight module.
1996 The variable mg5_path might not be correctly configured.''')
1997
1998
1999
2000 if not '-from_cards' in line:
2001 self.keep_cards(['reweight_card.dat'], ignore=['*'])
2002 self.ask_edit_cards(['reweight_card.dat'], 'fixed', plot=False)
2003
2004
2005 args = self.split_arg(line)
2006 if plugin and '--plugin=' not in line:
2007 args.append('--plugin=%s' % plugin)
2008
2009
2010 if not self.force_run:
2011
2012 if self.run_name and self.results.current and self.results.current['cross'] == 0:
2013 self.results.delete_run(self.run_name, self.run_tag)
2014 self.results.save()
2015
2016 if not hasattr(self, 'run_card'):
2017 self.run_card = banner_mod.RunCard(pjoin(self.me_dir, 'Cards', 'run_card.dat'))
2018
2019
2020 command = [sys.executable]
2021 if os.path.exists(pjoin(self.me_dir, 'bin', 'madevent')):
2022 command.append(pjoin(self.me_dir, 'bin', 'internal','madevent_interface.py'))
2023 else:
2024 command.append(pjoin(self.me_dir, 'bin', 'internal', 'amcatnlo_run_interface.py'))
2025 if not isinstance(self, cmd.CmdShell):
2026 command.append('--web')
2027 command.append('reweight')
2028
2029
2030 if self.options['nb_core']==1 or self.run_card['nevents'] < 101 or not check_multicore(self):
2031 if self.run_name:
2032 command.append(self.run_name)
2033 else:
2034 command += args
2035 if '-from_cards' not in command:
2036 command.append('-from_cards')
2037 p = misc.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, cwd=os.getcwd())
2038 while p.poll() is None:
2039 line = p.stdout.readline().decode(errors='ignore')
2040 if any(t in line for t in ['INFO:', 'WARNING:', 'CRITICAL:', 'ERROR:', 'root:','KEEP:']) and \
2041 not '***********' in line:
2042 print(line[:-1].replace('INFO', 'REWEIGHT').replace('KEEP:',''))
2043 elif __debug__ and line:
2044 logger.debug(line[:-1])
2045 if p.returncode !=0:
2046 logger.error("Reweighting failed")
2047 return
2048 self.results = self.load_results_db()
2049
2050 try:
2051 if self.results[self.run_name][-2]['cross']==0:
2052 self.results.delete_run(self.run_name,self.results[self.run_name][-2]['tag'])
2053 except:
2054 pass
2055 try:
2056 if self.results.current['cross'] == 0 and self.run_name:
2057 self.results.delete_run(self.run_name, self.run_tag)
2058 except:
2059 pass
2060
2061 try:
2062 self.results.def_current(self.run_name, self.run_tag)
2063 except Exception:
2064 pass
2065 return
2066
2067 else:
2068
2069 if not isinstance(self.cluster, cluster.MultiCore):
2070 mycluster = cluster.MultiCore(nb_core=self.options['nb_core'])
2071 else:
2072 mycluster = self.cluster
2073
2074 new_args=list(args)
2075 self.check_decay_events(new_args)
2076 try:
2077 os.remove(pjoin(self.me_dir,'rw_me','rwgt.pkl'))
2078 except Exception as error:
2079 pass
2080
2081 import madgraph.various.lhe_parser as lhe_parser
2082
2083 if 'nevt_job' in self.run_card and self.run_card['nevt_job'] !=-1:
2084 nevt_job = self.run_card['nevt_job']
2085 else:
2086 nevt_job = max(2500, self.run_card['nevents']/self.options['nb_core'])
2087 logger.info("split the event file in bunch of %s events" % nevt_job)
2088 nb_file = lhe_parser.EventFile(new_args[0]).split(nevt_job)
2089 starttime = time.time()
2090 update_status = lambda idle, run, finish: \
2091 self.update_status((idle, run, finish, 'reweight'), level=None,
2092 force=False, starttime=starttime)
2093
2094 all_lhe = []
2095
2096 to_zip=True
2097 if not os.path.exists(new_args[0]) and new_args[0].endswith('.gz') and\
2098 os.path.exists(new_args[0][:-3]):
2099 to_zip = False
2100 devnull= open(os.devnull)
2101
2102 for i in range(nb_file):
2103 new_command = list(command)
2104 if to_zip:
2105 new_command.append('%s_%s.lhe' % (new_args[0],i))
2106 all_lhe.append('%s_%s.lhe' % (new_args[0],i))
2107 else:
2108 new_command.append('%s_%s.lhe' % (new_args[0][:-3],i))
2109 all_lhe.append('%s_%s.lhe' % (new_args[0][:-3],i))
2110
2111 if '-from_cards' not in command:
2112 new_command.append('-from_cards')
2113 if plugin:
2114 new_command.append('--plugin=%s' % plugin)
2115 if i==0:
2116 if __debug__:
2117 stdout = None
2118 else:
2119 stdout = open(pjoin(self.me_dir,'Events', self.run_name, 'reweight.log'),'w')
2120 new_command.append('--multicore=create')
2121 else:
2122 stdout = devnull
2123 if six.PY3:
2124 stdout = subprocess.DEVNULL
2125
2126 new_command.append('--multicore=wait')
2127 mycluster.submit(prog=command[0], argument=new_command[1:], stdout=stdout, cwd=os.getcwd())
2128 mycluster.wait(self.me_dir,update_status)
2129 devnull.close()
2130 logger.info("Collect and combine the various output file.")
2131
2132 lhe = lhe_parser.MultiEventFile(all_lhe, parse=False)
2133 nb_event, cross_sections = lhe.write(new_args[0], get_info=True)
2134 if any(os.path.exists('%s_%s_debug.log' % (f, self.run_tag)) for f in all_lhe):
2135 for f in all_lhe:
2136 if os.path.exists('%s_%s_debug.log' % (f, self.run_tag)):
2137 raise Exception("Some of the run failed: Please read %s_%s_debug.log" % (f, self.run_tag))
2138
2139
2140 if 'event_norm' in self.run_card and self.run_card['event_norm'] in ['average','bias']:
2141 for key, value in cross_sections.items():
2142 cross_sections[key] = value / (nb_event+1)
2143 lhe.remove()
2144 for key in cross_sections:
2145 if key == 'orig' or key.isdigit():
2146 continue
2147 logger.info('%s : %s pb' % (key, cross_sections[key]))
2148 return
2149
2150
2151
2152 self.to_store.append('event')
2153
2154 if not self.force_run and self.results.current['cross'] == 0 and self.run_name:
2155 self.results.delete_run(self.run_name, self.run_tag)
2156
2157 self.check_decay_events(args)
2158
2159 rwgt_interface = reweight_interface.ReweightInterface
2160 if plugin:
2161 rwgt_interface = misc.from_plugin_import(self.plugin_path, 'new_reweight',
2162 plugin, warning=False,
2163 info="Will use re-weighting from pluging %(plug)s")
2164
2165 reweight_cmd = rwgt_interface(args[0], mother=self)
2166
2167
2168 wgt_names = reweight_cmd.get_weight_names()
2169 if wgt_names == [''] and reweight_cmd.has_nlo:
2170 self.update_status('Running Reweighting (LO approximate)', level='madspin')
2171 else:
2172 self.update_status('Running Reweighting', level='madspin')
2173
2174 path = pjoin(self.me_dir, 'Cards', 'reweight_card.dat')
2175 reweight_cmd.raw_input=False
2176 reweight_cmd.me_dir = self.me_dir
2177 reweight_cmd.multicore = multicore
2178 reweight_cmd.import_command_file(path)
2179 reweight_cmd.do_quit('')
2180
2181 logger.info("quit rwgt")
2182
2183
2184
2185
2186 try:
2187 self.results.def_current(self.run_name, self.run_tag)
2188 except Exception:
2189 pass
2190
2191
2193 """launch pgs"""
2194
2195 args = self.split_arg(line)
2196
2197 if '--no_default' in args:
2198 no_default = True
2199 args.remove('--no_default')
2200 else:
2201 no_default = False
2202
2203 if no_default and not os.path.exists(pjoin(self.me_dir, 'Cards', 'pgs_card.dat')):
2204 logger.info('No pgs_card detected, so not run pgs')
2205 return
2206
2207
2208
2209
2210
2211
2212 lock = self.check_pgs(args, no_default=no_default)
2213
2214
2215 if not os.path.exists(pjoin(self.me_dir, 'Cards', 'pgs_card.dat')):
2216 files.cp(pjoin(self.me_dir, 'Cards', 'pgs_card_default.dat'),
2217 pjoin(self.me_dir, 'Cards', 'pgs_card.dat'))
2218 logger.info('No pgs card found. Take the default one.')
2219
2220 if not (no_default or self.force):
2221 self.ask_edit_cards(['pgs_card.dat'])
2222
2223 self.update_status('prepare PGS run', level=None)
2224
2225 pgsdir = pjoin(self.options['pythia-pgs_path'], 'src')
2226 eradir = self.options['exrootanalysis_path']
2227 madir = self.options['madanalysis_path']
2228 td = self.options['td_path']
2229
2230
2231 if not misc.is_executable(pjoin(pgsdir, 'pgs')):
2232 logger.info('No PGS executable -- running make')
2233 misc.compile(cwd=pgsdir)
2234
2235 self.update_status('Running PGS', level='pgs')
2236
2237 tag = self.run_tag
2238
2239 banner_path = pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, self.run_tag))
2240 if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')):
2241 self.banner.add(pjoin(self.me_dir, 'Cards','pgs_card.dat'))
2242 self.banner.write(banner_path)
2243 else:
2244 open(banner_path, 'w').close()
2245
2246
2247
2248
2249 if lock:
2250 lock.wait()
2251
2252 ff = open(pjoin(self.me_dir, 'Events', 'pgs_events.lhco'), 'w')
2253 if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')):
2254 text = open(banner_path).read()
2255 text = '#%s' % text.replace('\n','\n#')
2256 dico = self.results[self.run_name].get_current_info()
2257 text +='\n## Integrated weight (pb) : %.4g' % dico['cross']
2258 text +='\n## Number of Event : %s\n' % dico['nb_event']
2259 ff.writelines(text)
2260 ff.close()
2261
2262 try:
2263 os.remove(pjoin(self.me_dir, 'Events', 'pgs.done'))
2264 except Exception:
2265 pass
2266
2267 pgs_log = pjoin(self.me_dir, 'Events', self.run_name, "%s_pgs.log" % tag)
2268 self.cluster.launch_and_wait('../bin/internal/run_pgs',
2269 argument=[pgsdir], cwd=pjoin(self.me_dir,'Events'),
2270 stdout=pgs_log, stderr=subprocess.STDOUT)
2271
2272 if not os.path.exists(pjoin(self.me_dir, 'Events', 'pgs.done')):
2273 logger.error('Fail to create LHCO events')
2274 return
2275 else:
2276 os.remove(pjoin(self.me_dir, 'Events', 'pgs.done'))
2277
2278 if os.path.getsize(banner_path) == os.path.getsize(pjoin(self.me_dir, 'Events','pgs_events.lhco')):
2279 misc.call(['cat pgs_uncleaned_events.lhco >> pgs_events.lhco'],
2280 cwd=pjoin(self.me_dir, 'Events'))
2281 os.remove(pjoin(self.me_dir, 'Events', 'pgs_uncleaned_events.lhco '))
2282
2283
2284 if eradir and misc.is_executable(pjoin(eradir, 'ExRootLHCOlympicsConverter')):
2285 self.update_status('Creating PGS Root File', level='pgs')
2286 try:
2287 misc.call([eradir+'/ExRootLHCOlympicsConverter',
2288 'pgs_events.lhco',pjoin('%s/%s_pgs_events.root' % (self.run_name, tag))],
2289 cwd=pjoin(self.me_dir, 'Events'))
2290 except Exception:
2291 logger.warning('fail to produce Root output [problem with ExRootAnalysis')
2292 if os.path.exists(pjoin(self.me_dir, 'Events', 'pgs_events.lhco')):
2293
2294 files.mv(pjoin(self.me_dir, 'Events', 'pgs_events.lhco'),
2295 pjoin(self.me_dir, 'Events', self.run_name, '%s_pgs_events.lhco' % tag))
2296 self.create_plot('PGS')
2297 misc.gzip(pjoin(self.me_dir, 'Events', self.run_name, '%s_pgs_events.lhco' % tag))
2298
2299 self.update_status('finish', level='pgs', makehtml=False)
2300
2301
2303 """Require MG5 directory: Compute automatically the widths of a set
2304 of particles"""
2305
2306 args = self.split_arg(line)
2307 opts = self.check_compute_widths(args)
2308
2309 from madgraph.interface.master_interface import MasterCmd
2310 cmd = MasterCmd()
2311 self.define_child_cmd_interface(cmd, interface=False)
2312 cmd.options.update(self.options)
2313 cmd.exec_cmd('set automatic_html_opening False --no_save')
2314 if not opts['path']:
2315 opts['path'] = pjoin(self.me_dir, 'Cards', 'param_card.dat')
2316 if not opts['force'] :
2317 self.ask_edit_cards(['param_card.dat'],[], plot=False)
2318
2319
2320 line = 'compute_widths %s %s' % \
2321 (' '.join([str(i) for i in opts['particles']]),
2322 ' '.join('--%s=%s' % (key,value) for (key,value) in opts.items()
2323 if key not in ['model', 'force', 'particles'] and value))
2324 out = cmd.exec_cmd(line, model=opts['model'])
2325
2326
2327 self.child = None
2328 del cmd
2329 return out
2330
2331
2332
2333
2335 """Not in help:Print the cross-section/ number of events for a given run"""
2336
2337 args = self.split_arg(line)
2338 options={'path':None, 'mode':'w', 'format':'full'}
2339 for arg in list(args):
2340 if arg.startswith('--') and '=' in arg:
2341 name,value=arg.split('=',1)
2342 name = name [2:]
2343 options[name] = value
2344 args.remove(arg)
2345
2346
2347 if len(args) > 0:
2348 run_name = args[0]
2349 else:
2350 for i, run_name in enumerate(self.results.order):
2351 for j, one_result in enumerate(self.results[run_name]):
2352 if i or j:
2353 options['mode'] = "a"
2354 if options['path']:
2355 self.print_results_in_file(one_result, options['path'], options['mode'], options['format'])
2356 else:
2357 self.print_results_in_shell(one_result)
2358 return
2359
2360 if run_name not in self.results:
2361 raise self.InvalidCmd('%s is not a valid run_name or it doesn\'t have any information' \
2362 % run_name)
2363
2364
2365 if len(args) == 2:
2366 tag = args[1]
2367 if tag.isdigit():
2368 tag = int(tag) - 1
2369 if len(self.results[run_name]) < tag:
2370 raise self.InvalidCmd('Only %s different tag available' % \
2371 len(self.results[run_name]))
2372 data = self.results[run_name][tag]
2373 else:
2374 data = self.results[run_name].return_tag(tag)
2375 else:
2376 data = self.results[run_name].return_tag(None)
2377
2378 if options['path']:
2379 self.print_results_in_file(data, options['path'], options['mode'], options['format'])
2380 else:
2381 self.print_results_in_shell(data)
2382
2387
2388
2389
2390
2391
2392 @staticmethod
2393 - def runMA5(MA5_interpreter, MA5_cmds, MA5_runtag, logfile_path, advertise_log=True):
2394 """ Run MA5 in a controlled environnment."""
2395 successfull_MA5_run = True
2396
2397 try:
2398
2399 MA5_logger = None
2400 MA5_logger = logging.getLogger('MA5')
2401 BackUp_MA5_handlers = MA5_logger.handlers
2402 for handler in BackUp_MA5_handlers:
2403 MA5_logger.removeHandler(handler)
2404 file_handler = logging.FileHandler(logfile_path)
2405 MA5_logger.addHandler(file_handler)
2406 if advertise_log:
2407 logger.info("Follow Madanalysis5 run with the following command in a separate terminal:")
2408 logger.info(' tail -f %s'%logfile_path)
2409
2410 with misc.stdchannel_redirected(sys.stdout, os.devnull):
2411 with misc.stdchannel_redirected(sys.stderr, os.devnull):
2412 MA5_interpreter.print_banner()
2413 MA5_interpreter.load(MA5_cmds)
2414 except Exception as e:
2415 logger.warning("MadAnalysis5 failed to run the commands for task "+
2416 "'%s'. Madanalys5 analysis will be skipped."%MA5_runtag)
2417 error=StringIO.StringIO()
2418 traceback.print_exc(file=error)
2419 logger.debug('MadAnalysis5 error was:')
2420 logger.debug('-'*60)
2421 logger.debug(error.getvalue()[:-1])
2422 logger.debug('-'*60)
2423 successfull_MA5_run = False
2424 finally:
2425 if not MA5_logger is None:
2426 for handler in MA5_logger.handlers:
2427 MA5_logger.removeHandler(handler)
2428 for handler in BackUp_MA5_handlers:
2429 MA5_logger.addHandler(handler)
2430
2431 return successfull_MA5_run
2432
2433
2434
2435
2436 @staticmethod
2440 """ Makes sure to correctly setup paths and constructs and return an MA5 path"""
2441
2442 MA5path = os.path.normpath(pjoin(mg5_path,ma5_path))
2443
2444 if MA5path is None or not os.path.isfile(pjoin(MA5path,'bin','ma5')):
2445 return None
2446 if MA5path not in sys.path:
2447 sys.path.insert(0, MA5path)
2448
2449 try:
2450
2451
2452 import readline
2453 old_completer = readline.get_completer()
2454 old_delims = readline.get_completer_delims()
2455 old_history = [readline.get_history_item(i) for i in range(1,readline.get_current_history_length()+1)]
2456 except ImportError:
2457 old_completer, old_delims, old_history = None, None, None
2458 try:
2459 from madanalysis.interpreter.ma5_interpreter import MA5Interpreter
2460 with misc.stdchannel_redirected(sys.stdout, os.devnull):
2461 with misc.stdchannel_redirected(sys.stderr, os.devnull):
2462 MA5_interpreter = MA5Interpreter(MA5path, LoggerLevel=loglevel,
2463 LoggerStream=logstream,forced=forced,
2464 no_compilation=not compilation)
2465 except Exception as e:
2466 if six.PY3 and not __debug__:
2467 logger.info('MadAnalysis5 instalation not python3 compatible')
2468 return None
2469 logger.warning('MadAnalysis5 failed to start so that MA5 analysis will be skipped.')
2470 error=StringIO.StringIO()
2471 traceback.print_exc(file=error)
2472 logger.debug('MadAnalysis5 error was:')
2473 logger.debug('-'*60)
2474 logger.debug(error.getvalue()[:-1])
2475 logger.debug('-'*60)
2476 MA5_interpreter = None
2477 finally:
2478
2479 if not old_history is None:
2480 readline.clear_history()
2481 for line in old_history:
2482 readline.add_history(line)
2483 if not old_completer is None:
2484 readline.set_completer(old_completer)
2485 if not old_delims is None:
2486 readline.set_completer_delims(old_delims)
2487
2488
2489 if not mg5_interface is None and any(not elem is None for elem in [old_completer, old_delims, old_history]):
2490 mg5_interface.set_readline_completion_display_matches_hook()
2491
2492 return MA5_interpreter
2493
2495 """Check the argument for the madanalysis5 command
2496 syntax: madanalysis5_parton [NAME]
2497 """
2498
2499 MA5_options = {'MA5_stdout_lvl':'default'}
2500
2501 stdout_level_tags = [a for a in args if a.startswith('--MA5_stdout_lvl=')]
2502 for slt in stdout_level_tags:
2503 lvl = slt.split('=')[1].strip()
2504 try:
2505
2506 MA5_options['MA5_stdout_lvl']=int(lvl)
2507 except ValueError:
2508 if lvl.startswith('logging.'):
2509 lvl = lvl[8:]
2510 try:
2511 MA5_options['MA5_stdout_lvl'] = getattr(logging, lvl)
2512 except:
2513 raise InvalidCmd("MA5 output level specification"+\
2514 " '%s' is incorrect." % str(lvl))
2515 args.remove(slt)
2516
2517 if mode=='parton':
2518
2519
2520 MA5_options['inputs'] = '*.lhe'
2521 elif mode=='hadron':
2522
2523
2524
2525 MA5_options['inputs'] = ['fromCard']
2526 else:
2527 raise MadGraph5Error('Mode %s not reckognized'%mode+
2528 ' in function check_madanalysis5.')
2529
2530 if not self.options['madanalysis5_path']:
2531 logger.info('Now trying to read the configuration file again'+
2532 ' to find MadAnalysis5 path')
2533 self.set_configuration()
2534
2535 if not self.options['madanalysis5_path'] or not \
2536 os.path.exists(pjoin(self.options['madanalysis5_path'],'bin','ma5')):
2537 error_msg = 'No valid MadAnalysis5 path set.\n'
2538 error_msg += 'Please use the set command to define the path and retry.\n'
2539 error_msg += 'You can also define it in the configuration file.\n'
2540 error_msg += 'Finally, it can be installed automatically using the'
2541 error_msg += ' install command.\n'
2542 raise self.InvalidCmd(error_msg)
2543
2544
2545 if not os.path.isfile(pjoin(self.me_dir,
2546 'Cards','madanalysis5_%s_card.dat'%mode)):
2547 raise self.InvalidCmd('Your installed version of MadAnalysis5 and/or'+\
2548 ' MadGraph5_aMCatNLO does not seem to support analysis at'+
2549 '%s level.'%mode)
2550
2551 tag = [a for a in args if a.startswith('--tag=')]
2552 if tag:
2553 args.remove(tag[0])
2554 tag = tag[0][6:]
2555
2556 if len(args) == 0 and not self.run_name:
2557 if self.results.lastrun:
2558 args.insert(0, self.results.lastrun)
2559 else:
2560 raise self.InvalidCmd('No run name currently defined. '+
2561 'Please add this information.')
2562
2563 if len(args) >= 1:
2564 if mode=='parton' and args[0] != self.run_name and \
2565 not os.path.exists(pjoin(self.me_dir,'Events',args[0],
2566 'unweighted_events.lhe.gz')) and not os.path.exists(
2567 pjoin(self.me_dir,'Events',args[0])):
2568 raise self.InvalidCmd('No events file in the %s run.'%args[0])
2569 self.set_run_name(args[0], tag, level='madanalysis5_%s'%mode)
2570 else:
2571 if tag:
2572 self.run_card['run_tag'] = args[0]
2573 self.set_run_name(self.run_name, tag, level='madanalysis5_%s'%mode)
2574
2575 if mode=='parton':
2576 if any(t for t in args if t.startswith('--input=')):
2577 raise InvalidCmd('The option --input=<input_file> is not'+
2578 ' available when running partonic MadAnalysis5 analysis. The'+
2579 ' .lhe output of the selected run is used automatically.')
2580 input_file = pjoin(self.me_dir,'Events',self.run_name, 'unweighted_events.lhe')
2581 MA5_options['inputs'] = '%s.gz'%input_file
2582 if not os.path.exists('%s.gz'%input_file):
2583 if os.path.exists(input_file):
2584 misc.gzip(input_file, stdout='%s.gz' % input_file)
2585 else:
2586 logger.warning("LHE event file not found in \n%s\ns"%input_file+
2587 "Parton-level MA5 analysis will be skipped.")
2588
2589 if mode=='hadron':
2590
2591
2592 self.store_result()
2593
2594 hadron_tag = [t for t in args if t.startswith('--input=')]
2595 if hadron_tag and hadron_tag[0][8:]:
2596 hadron_inputs = hadron_tag[0][8:].split(',')
2597
2598
2599 elif MA5_options['inputs'] == ['fromCard']:
2600 hadron_inputs = banner_mod.MadAnalysis5Card(pjoin(self.me_dir,
2601 'Cards','madanalysis5_hadron_card.dat'),mode='hadron')['inputs']
2602
2603
2604
2605 MA5_options['inputs'] = []
2606 special_source_tags = []
2607 for htag in hadron_inputs:
2608
2609 if htag in special_source_tags:
2610
2611 continue
2612
2613 if os.path.isfile(htag) or (os.path.exists(htag) and
2614 stat.S_ISFIFO(os.stat(htag).st_mode)):
2615 MA5_options['inputs'].append(htag)
2616 continue
2617
2618
2619
2620 file_candidates = misc.glob(htag, pjoin(self.me_dir,'Events',self.run_name))+\
2621 misc.glob('%s.gz'%htag, pjoin(self.me_dir,'Events',self.run_name))
2622 priority_files = [f for f in file_candidates if
2623 self.run_card['run_tag'] in os.path.basename(f)]
2624 priority_files = [f for f in priority_files if
2625 'EVENTS' in os.path.basename(f).upper()]
2626
2627 for f in file_candidates:
2628 if os.path.basename(f).startswith('unweighted_events.lhe'):
2629 priority_files.append(f)
2630 if priority_files:
2631 MA5_options['inputs'].append(priority_files[-1])
2632 continue
2633 if file_candidates:
2634 MA5_options['inputs'] += file_candidates
2635 continue
2636
2637 return MA5_options
2638
2640 """Ask the question when launching madanalysis5.
2641 In the future we can ask here further question about the MA5 run, but
2642 for now we just edit the cards"""
2643
2644 cards = ['madanalysis5_%s_card.dat'%runtype]
2645 self.keep_cards(cards)
2646
2647 if self.force:
2648 return runtype
2649
2650
2651
2652 auto=False
2653 if mode=='auto':
2654 auto=True
2655 if auto:
2656 self.ask_edit_cards(cards, mode='auto', plot=False)
2657 else:
2658 self.ask_edit_cards(cards, plot=False)
2659
2660
2661
2662 mode = runtype
2663 return mode
2664
2666 "Complete the madanalysis5 command"
2667 args = self.split_arg(line[0:begidx], error=False)
2668 if len(args) == 1:
2669
2670 data = []
2671 for name in banner_mod.MadAnalysis5Card._default_hadron_inputs:
2672 data += misc.glob(pjoin('*','%s'%name), pjoin(self.me_dir, 'Events'))
2673 data += misc.glob(pjoin('*','%s.gz'%name), pjoin(self.me_dir, 'Events'))
2674 data = [n.rsplit('/',2)[1] for n in data]
2675 tmp1 = self.list_completion(text, data)
2676 if not self.run_name:
2677 return tmp1
2678 else:
2679 tmp2 = self.list_completion(text, ['-f',
2680 '--MA5_stdout_lvl=','--input=','--no_default', '--tag='], line)
2681 return tmp1 + tmp2
2682
2683 elif '--MA5_stdout_lvl=' in line and not any(arg.startswith(
2684 '--MA5_stdout_lvl=') for arg in args):
2685 return self.list_completion(text,
2686 ['--MA5_stdout_lvl=%s'%opt for opt in
2687 ['logging.INFO','logging.DEBUG','logging.WARNING',
2688 'logging.CRITICAL','90']], line)
2689 elif '--input=' in line and not any(arg.startswith(
2690 '--input=') for arg in args):
2691 return self.list_completion(text, ['--input=%s'%opt for opt in
2692 (banner_mod.MadAnalysis5Card._default_hadron_inputs +['path'])], line)
2693 else:
2694 return self.list_completion(text, ['-f',
2695 '--MA5_stdout_lvl=','--input=','--no_default', '--tag='], line)
2696
2698 """launch MadAnalysis5 at the hadron level."""
2699 return self.run_madanalysis5(line,mode='hadron')
2700
2702 """launch MadAnalysis5 at the parton level or at the hadron level with
2703 a specific command line."""
2704
2705
2706 args = self.split_arg(line)
2707
2708 if '--no_default' in args:
2709 no_default = True
2710 args.remove('--no_default')
2711 else:
2712 no_default = False
2713
2714 if no_default:
2715
2716 if mode=='parton' and not os.path.exists(pjoin(self.me_dir, 'Cards',
2717 'madanalysis5_parton_card.dat')):
2718 return
2719 if mode=='hadron' and not os.path.exists(pjoin(self.me_dir, 'Cards',
2720 'madanalysis5_hadron_card.dat')):
2721 return
2722 else:
2723
2724
2725 self.ask_madanalysis5_run_configuration(runtype=mode)
2726
2727 if not self.options['madanalysis5_path'] or \
2728 all(not os.path.exists(pjoin(self.me_dir, 'Cards',card)) for card in
2729 ['madanalysis5_parton_card.dat','madanalysis5_hadron_card.dat']):
2730 if no_default:
2731 return
2732 else:
2733 raise InvalidCmd('You must have MadAnalysis5 available to run'+
2734 " this command. Consider installing it with the 'install' function.")
2735
2736 if not self.run_name:
2737 MA5_opts = self.check_madanalysis5(args, mode=mode)
2738 self.configure_directory(html_opening =False)
2739 else:
2740
2741 self.configure_directory(html_opening =False)
2742 MA5_opts = self.check_madanalysis5(args, mode=mode)
2743
2744
2745 if MA5_opts['inputs']==[]:
2746 if no_default:
2747 logger.warning('No hadron level input found to run MadAnalysis5 on.'+
2748 ' Skipping its hadron-level analysis.')
2749 return
2750 else:
2751 raise self.InvalidCmd('\nNo input files specified or availabled for'+
2752 ' this MadAnalysis5 hadron-level run.\nPlease double-check the options of this'+
2753 ' MA5 command (or card) and which output files\nare currently in the chosen'+
2754 " run directory '%s'."%self.run_name)
2755
2756 MA5_card = banner_mod.MadAnalysis5Card(pjoin(self.me_dir, 'Cards',
2757 'madanalysis5_%s_card.dat'%mode), mode=mode)
2758
2759 if MA5_card._skip_analysis:
2760 logger.info('Madanalysis5 %s-level analysis was skipped following user request.'%mode)
2761 logger.info("To run the analysis, remove or comment the tag '%s skip_analysis' "
2762 %banner_mod.MadAnalysis5Card._MG5aMC_escape_tag+
2763 "in\n '%s'."%pjoin(self.me_dir, 'Cards','madanalysis5_%s_card.dat'%mode))
2764 return
2765
2766 MA5_cmds_list = MA5_card.get_MA5_cmds(MA5_opts['inputs'],
2767 pjoin(self.me_dir,'MA5_%s_ANALYSIS'%mode.upper()),
2768 run_dir_path = pjoin(self.me_dir,'Events', self.run_name),
2769 UFO_model_path=pjoin(self.me_dir,'bin','internal','ufomodel'),
2770 run_tag = self.run_tag)
2771
2772
2773 if __debug__:
2774 for MA5_runtag, MA5_cmds in MA5_cmds_list:
2775 misc.sprint('****************************************')
2776 misc.sprint('* Commands for MA5 runtag %s:'%MA5_runtag)
2777 misc.sprint('\n'+('\n'.join('* %s'%cmd for cmd in MA5_cmds)))
2778 misc.sprint('****************************************')
2779
2780 self.update_status('\033[92mRunning MadAnalysis5 [arXiv:1206.1599]\033[0m',
2781 level='madanalysis5_%s'%mode)
2782 if mode=='hadron':
2783 logger.info('Hadron input files considered:')
2784 for input in MA5_opts['inputs']:
2785 logger.info(' --> %s'%input)
2786 elif mode=='parton':
2787 logger.info('Parton input file considered:')
2788 logger.info(' --> %s'%MA5_opts['inputs'])
2789
2790
2791
2792
2793 if MA5_opts['MA5_stdout_lvl']=='default':
2794 if MA5_card['stdout_lvl'] is None:
2795 MA5_lvl = self.options['stdout_level']
2796 else:
2797 MA5_lvl = MA5_card['stdout_lvl']
2798 else:
2799 MA5_lvl = MA5_opts['MA5_stdout_lvl']
2800
2801
2802 MA5_interpreter = CommonRunCmd.get_MadAnalysis5_interpreter(
2803 self.options['mg5_path'],
2804 self.options['madanalysis5_path'],
2805 logstream=sys.stdout,
2806 loglevel=100,
2807 forced=True,
2808 compilation=True)
2809
2810
2811
2812 if MA5_interpreter is None:
2813 return
2814
2815
2816 used_up_fifos = []
2817
2818 for MA5_run_number, (MA5_runtag, MA5_cmds) in enumerate(MA5_cmds_list):
2819
2820
2821
2822 MA5_run_number = 0
2823
2824 MA5_interpreter.setLogLevel(100)
2825
2826 if mode=='hadron':
2827 MA5_interpreter.init_reco()
2828 else:
2829 MA5_interpreter.init_parton()
2830 MA5_interpreter.setLogLevel(MA5_lvl)
2831
2832 if MA5_runtag!='default':
2833 if MA5_runtag.startswith('_reco_'):
2834 logger.info("MadAnalysis5 now running the reconstruction '%s'..."%
2835 MA5_runtag[6:],'$MG:color:GREEN')
2836 elif MA5_runtag=='Recasting':
2837 logger.info("MadAnalysis5 now running the recasting...",
2838 '$MG:color:GREEN')
2839 else:
2840 logger.info("MadAnalysis5 now running the '%s' analysis..."%
2841 MA5_runtag,'$MG:color:GREEN')
2842
2843
2844
2845 if not CommonRunCmd.runMA5(MA5_interpreter, MA5_cmds, MA5_runtag,
2846 pjoin(self.me_dir,'Events',self.run_name,'%s_MA5_%s.log'%(self.run_tag,MA5_runtag))):
2847
2848 return
2849
2850 if MA5_runtag.startswith('_reco_'):
2851
2852
2853
2854
2855 links_created=[]
2856 for i, input in enumerate(MA5_opts['inputs']):
2857
2858
2859 if not banner_mod.MadAnalysis5Card.events_can_be_reconstructed(input):
2860 continue
2861
2862 if input.endswith('.fifo'):
2863 if input in used_up_fifos:
2864
2865 continue
2866 else:
2867 used_up_fifos.append(input)
2868
2869 reco_output = pjoin(self.me_dir,
2870 'MA5_%s_ANALYSIS%s_%d'%(mode.upper(),MA5_runtag,i+1))
2871
2872 reco_event_file = misc.glob('*.lhe.gz',pjoin(reco_output,'Output','SAF','_reco_events','lheEvents0_%d'%MA5_run_number))+\
2873 misc.glob('*.root',pjoin(reco_output,'Output','SAF','_reco_events', 'RecoEvents0_%d'%MA5_run_number))
2874 if len(reco_event_file)==0:
2875 raise MadGraph5Error("MadAnalysis5 failed to produce the "+\
2876 "reconstructed event file for reconstruction '%s'."%MA5_runtag[6:])
2877 reco_event_file = reco_event_file[0]
2878
2879 shutil.move(reco_output,pjoin(self.me_dir,'HTML',
2880 self.run_name,'%s_MA5_%s_ANALYSIS%s_%d'%
2881 (self.run_tag,mode.upper(),MA5_runtag,i+1)))
2882
2883
2884 links_created.append(os.path.basename(reco_event_file))
2885 parent_dir_name = os.path.basename(os.path.dirname(reco_event_file))
2886 files.ln(pjoin(self.me_dir,'HTML',self.run_name,
2887 '%s_MA5_%s_ANALYSIS%s_%d'%(self.run_tag,mode.upper(),
2888 MA5_runtag,i+1),'Output','SAF','_reco_events',parent_dir_name,links_created[-1]),
2889 pjoin(self.me_dir,'Events',self.run_name))
2890
2891 logger.info("MadAnalysis5 successfully completed the reconstruction "+
2892 "'%s'. Links to the reconstructed event files are:"%MA5_runtag[6:])
2893 for link in links_created:
2894 logger.info(' --> %s'%pjoin(self.me_dir,'Events',self.run_name,link))
2895 continue
2896
2897 if MA5_runtag.upper()=='RECASTING':
2898 target = pjoin(self.me_dir,'MA5_%s_ANALYSIS_%s'\
2899 %(mode.upper(),MA5_runtag),'Output','CLs_output_summary.dat')
2900 else:
2901 target = pjoin(self.me_dir,'MA5_%s_ANALYSIS_%s'\
2902 %(mode.upper(),MA5_runtag),'Output','PDF','MadAnalysis5job_%d'%MA5_run_number,'main.pdf')
2903 has_pdf = True
2904 if not os.path.isfile(target):
2905 has_pdf = False
2906
2907
2908 if MA5_runtag.upper()=='RECASTING':
2909 carboncopy_name = '%s_MA5_CLs.dat'%(self.run_tag)
2910 else:
2911 carboncopy_name = '%s_MA5_%s_analysis_%s.pdf'%(
2912 self.run_tag,mode,MA5_runtag)
2913 if has_pdf:
2914 shutil.copy(target, pjoin(self.me_dir,'Events',self.run_name,carboncopy_name))
2915 else:
2916 logger.error('MadAnalysis5 failed to create PDF output')
2917 if MA5_runtag!='default':
2918 logger.info("MadAnalysis5 successfully completed the "+
2919 "%s. Reported results are placed in:"%("analysis '%s'"%MA5_runtag
2920 if MA5_runtag.upper()!='RECASTING' else "recasting"))
2921 else:
2922 logger.info("MadAnalysis5 successfully completed the analysis."+
2923 " Reported results are placed in:")
2924 logger.info(' --> %s'%pjoin(self.me_dir,'Events',self.run_name,carboncopy_name))
2925
2926 anal_dir = pjoin(self.me_dir,'MA5_%s_ANALYSIS_%s' %(mode.upper(),MA5_runtag))
2927 if not os.path.exists(anal_dir):
2928 logger.error('MadAnalysis5 failed to completed succesfully')
2929 return
2930
2931 shutil.move(anal_dir, pjoin(self.me_dir,'HTML',self.run_name,
2932 '%s_MA5_%s_ANALYSIS_%s'%(self.run_tag,mode.upper(),MA5_runtag)))
2933
2934
2935
2936 new_details={}
2937 for detail in ['nb_event','cross','error']:
2938 new_details[detail] = \
2939 self.results[self.run_name].get_current_info()[detail]
2940 for detail in new_details:
2941 self.results.add_detail(detail,new_details[detail])
2942
2943 self.update_status('Finished MA5 analyses.', level='madanalysis5_%s'%mode,
2944 makehtml=False)
2945
2946
2947 self.banner.add(pjoin(self.me_dir, 'Cards',
2948 'madanalysis5_%s_card.dat'%mode))
2949 banner_path = pjoin(self.me_dir,'Events', self.run_name,
2950 '%s_%s_banner.txt'%(self.run_name, self.run_tag))
2951 self.banner.write(banner_path)
2952
2953 if not no_default:
2954 logger.info('Find more information about this run on the HTML local page')
2955 logger.info(' --> %s'%pjoin(self.me_dir,'index.html'))
2956
2957
2958
2959
2960
2962 """ run delphes and make associate root file/plot """
2963
2964 args = self.split_arg(line)
2965
2966 if '--no_default' in args:
2967 no_default = True
2968 args.remove('--no_default')
2969 else:
2970 no_default = False
2971
2972 if no_default and not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')):
2973 logger.info('No delphes_card detected, so not run Delphes')
2974 return
2975
2976
2977 filepath = self.check_delphes(args, nodefault=no_default)
2978 if no_default and not filepath:
2979 return
2980
2981 self.update_status('prepare delphes run', level=None)
2982
2983 if os.path.exists(pjoin(self.options['delphes_path'], 'data')):
2984 delphes3 = False
2985 prog = '../bin/internal/run_delphes'
2986 if filepath and '.hepmc' in filepath[:-10]:
2987 raise self.InvalidCmd('delphes2 do not support hepmc')
2988 else:
2989 delphes3 = True
2990 prog = '../bin/internal/run_delphes3'
2991
2992
2993
2994 if not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')):
2995 if no_default:
2996 logger.info('No delphes_card detected, so not running Delphes')
2997 return
2998 files.cp(pjoin(self.me_dir, 'Cards', 'delphes_card_default.dat'),
2999 pjoin(self.me_dir, 'Cards', 'delphes_card.dat'))
3000 logger.info('No delphes card found. Take the default one.')
3001 if not delphes3 and not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_trigger.dat')):
3002 files.cp(pjoin(self.me_dir, 'Cards', 'delphes_trigger_default.dat'),
3003 pjoin(self.me_dir, 'Cards', 'delphes_trigger.dat'))
3004 if not (no_default or self.force):
3005 if delphes3:
3006 self.ask_edit_cards(['delphes_card.dat'], args)
3007 else:
3008 self.ask_edit_cards(['delphes_card.dat', 'delphes_trigger.dat'], args)
3009
3010 self.update_status('Running Delphes', level=None)
3011
3012 delphes_dir = self.options['delphes_path']
3013 tag = self.run_tag
3014 if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')):
3015 self.banner.add(pjoin(self.me_dir, 'Cards','delphes_card.dat'))
3016 if not delphes3:
3017 self.banner.add(pjoin(self.me_dir, 'Cards','delphes_trigger.dat'))
3018 self.banner.write(pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, tag)))
3019
3020 cross = self.results[self.run_name].get_current_info()['cross']
3021
3022 delphes_log = pjoin(self.me_dir, 'Events', self.run_name, "%s_delphes.log" % tag)
3023 if not self.cluster:
3024 clus = cluster.onecore
3025 else:
3026 clus = self.cluster
3027 clus.launch_and_wait(prog,
3028 argument= [delphes_dir, self.run_name, tag, str(cross), filepath],
3029 stdout=delphes_log, stderr=subprocess.STDOUT,
3030 cwd=pjoin(self.me_dir,'Events'))
3031
3032 if not os.path.exists(pjoin(self.me_dir, 'Events',
3033 self.run_name, '%s_delphes_events.lhco.gz' % tag))\
3034 and not os.path.exists(pjoin(self.me_dir, 'Events',
3035 self.run_name, '%s_delphes_events.lhco' % tag)):
3036 logger.info('If you are interested in lhco output. please run root2lhco converter.')
3037 logger.info(' or edit bin/internal/run_delphes3 to run the converter automatically.')
3038
3039
3040
3041 madir = self.options['madanalysis_path']
3042 td = self.options['td_path']
3043
3044 if os.path.exists(pjoin(self.me_dir, 'Events',
3045 self.run_name, '%s_delphes_events.lhco' % tag)):
3046
3047 self.create_plot('Delphes')
3048
3049 if os.path.exists(pjoin(self.me_dir, 'Events', self.run_name, '%s_delphes_events.lhco' % tag)):
3050 misc.gzip(pjoin(self.me_dir, 'Events', self.run_name, '%s_delphes_events.lhco' % tag))
3051
3052 self.update_status('delphes done', level='delphes', makehtml=False)
3053
3054
3055
3057 """Find the pid of all particles in the final and initial states"""
3058 pids = set()
3059 subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses',
3060 'subproc.mg'))]
3061 nb_init = self.ninitial
3062 pat = re.compile(r'''DATA \(IDUP\(I,\d+\),I=1,\d+\)/([\+\-\d,\s]*)/''', re.I)
3063 for Pdir in subproc:
3064 text = open(pjoin(self.me_dir, 'SubProcesses', Pdir, 'born_leshouche.inc')).read()
3065 group = pat.findall(text)
3066 for particles in group:
3067 particles = particles.split(',')
3068 pids.update(set(particles))
3069
3070 return pids
3071
3072
3097
3098
3099 if hasattr(self, 'pdffile') and self.pdffile:
3100 return self.pdffile
3101 else:
3102 for line in open(pjoin(self.me_dir,'Source','PDF','pdf_list.txt')):
3103 data = line.split()
3104 if len(data) < 4:
3105 continue
3106 if data[1].lower() == self.run_card['pdlabel'].lower():
3107 self.pdffile = check_cluster(pjoin(self.me_dir, 'lib', 'Pdfdata', data[2]))
3108 return self.pdffile
3109 else:
3110
3111 path = pjoin(self.me_dir, 'lib', 'PDFsets')
3112 if os.path.exists(path):
3113 self.pdffile = path
3114 else:
3115 self.pdffile = " "
3116 return self.pdffile
3117
3118
3128
3129
3130 - def do_set(self, line, log=True):
3131 """Set an option, which will be default for coming generations/outputs
3132 """
3133
3134
3135
3136 args = self.split_arg(line)
3137
3138 self.check_set(args)
3139
3140 if args[0] in self.options_configuration and '--no_save' not in args:
3141 self.do_save('options --auto')
3142
3143 if args[0] == "stdout_level":
3144 if args[1].isdigit():
3145 logging.root.setLevel(int(args[1]))
3146 logging.getLogger('madgraph').setLevel(int(args[1]))
3147 else:
3148 logging.root.setLevel(eval('logging.' + args[1]))
3149 logging.getLogger('madgraph').setLevel(eval('logging.' + args[1]))
3150 if log: logger.info('set output information to level: %s' % args[1])
3151 elif args[0] == "fortran_compiler":
3152 if args[1] == 'None':
3153 args[1] = None
3154 self.options['fortran_compiler'] = args[1]
3155 current = misc.detect_current_compiler(pjoin(self.me_dir,'Source','make_opts'), 'fortran')
3156 if current != args[1] and args[1] != None:
3157 misc.mod_compilator(self.me_dir, args[1], current, 'gfortran')
3158 elif args[0] == "cpp_compiler":
3159 if args[1] == 'None':
3160 args[1] = None
3161 self.options['cpp_compiler'] = args[1]
3162 current = misc.detect_current_compiler(pjoin(self.me_dir,'Source','make_opts'), 'cpp')
3163 if current != args[1] and args[1] != None:
3164 misc.mod_compilator(self.me_dir, args[1], current, 'cpp')
3165 elif args[0] == "run_mode":
3166 if not args[1] in [0,1,2,'0','1','2']:
3167 raise self.InvalidCmd('run_mode should be 0, 1 or 2.')
3168 self.cluster_mode = int(args[1])
3169 self.options['run_mode'] = self.cluster_mode
3170 elif args[0] in ['cluster_type', 'cluster_queue', 'cluster_temp_path']:
3171 if args[1] == 'None':
3172 args[1] = None
3173 self.options[args[0]] = args[1]
3174
3175
3176 elif args[0] in ['cluster_nb_retry', 'cluster_retry_wait', 'cluster_size']:
3177 self.options[args[0]] = int(args[1])
3178
3179 elif args[0] == 'nb_core':
3180 if args[1] == 'None':
3181 import multiprocessing
3182 self.nb_core = multiprocessing.cpu_count()
3183 self.options['nb_core'] = self.nb_core
3184 return
3185 if not args[1].isdigit():
3186 raise self.InvalidCmd('nb_core should be a positive number')
3187 self.nb_core = int(args[1])
3188 self.options['nb_core'] = self.nb_core
3189 elif args[0] == 'timeout':
3190 self.options[args[0]] = int(args[1])
3191 elif args[0] == 'cluster_status_update':
3192 if '(' in args[1]:
3193 data = ' '.join([a for a in args[1:] if not a.startswith('-')])
3194 data = data.replace('(','').replace(')','').replace(',',' ').split()
3195 first, second = data[:2]
3196 else:
3197 first, second = args[1:3]
3198
3199 self.options[args[0]] = (int(first), int(second))
3200 elif args[0] == 'notification_center':
3201 if args[1] in ['None','True','False']:
3202 self.allow_notification_center = eval(args[1])
3203 self.options[args[0]] = eval(args[1])
3204 else:
3205 raise self.InvalidCmd('Not a valid value for notification_center')
3206
3207 elif args[0] in ['crash_on_error']:
3208 try:
3209 tmp = banner_mod.ConfigFile.format_variable(args[1], bool, 'crash_on_error')
3210 except:
3211 if args[1].lower() in ['never']:
3212 tmp = args[1].lower()
3213 else:
3214 raise
3215 self.options[args[0]] = tmp
3216 elif args[0].startswith('f2py_compiler'):
3217 to_do = True
3218 if args[0].endswith('_py2') and six.PY3:
3219 to_do = False
3220 elif args[0].endswith('_py3') and six.PY2:
3221 to_do = False
3222 if to_do:
3223 if args[1] == 'None':
3224 self.options['f2py_compiler'] = None
3225 else:
3226 logger.info('set f2py compiler to %s' % args[1])
3227 self.options['f2py_compiler'] = args[1]
3228 elif args[0].startswith('lhapdf'):
3229 to_do = True
3230 if args[0].endswith('_py2') and six.PY3:
3231 to_do = False
3232 elif args[0].endswith('_py3') and six.PY2:
3233 to_do = False
3234 if to_do and args[1] != 'None':
3235 self.options['lhapdf'] = args[1]
3236 elif args[0] in self.options:
3237 if args[1] in ['None','True','False']:
3238 self.options[args[0]] = ast.literal_eval(args[1])
3239 elif args[0].endswith('path'):
3240 if os.path.exists(args[1]):
3241 self.options[args[0]] = args[1]
3242 elif os.path.exists(pjoin(self.me_dir, args[1])):
3243 self.options[args[0]] = pjoin(self.me_dir, args[1])
3244 else:
3245 raise self.InvalidCmd('Not a valid path: keep previous value: \'%s\' for %s instead of %s' % (self.options[args[0]], args[0], args[1]) )
3246 else:
3247 self.options[args[0]] = args[1]
3248
3249 - def post_set(self, stop, line):
3250 """Check if we need to save this in the option file"""
3251 try:
3252 args = self.split_arg(line)
3253 if 'cluster' in args[0] or args[0] == 'run_mode':
3254 self.configure_run_mode(self.options['run_mode'])
3255
3256
3257
3258 self.check_set(args)
3259
3260 if args[0] in self.options_configuration and '--no_save' not in args:
3261 self.exec_cmd('save options %s --auto' % args[0])
3262 elif args[0] in self.options_madevent:
3263 logger.info('This option will be the default in any output that you are going to create in this session.')
3264 logger.info('In order to keep this changes permanent please run \'save options\'')
3265 return stop
3266 except self.InvalidCmd:
3267 return stop
3268
3312
3314 """
3315 1) Check that no scan parameter are present
3316 2) Check that all the width are define in the param_card.
3317 - If a scan parameter is define. create the iterator and recall this fonction
3318 on the first element.
3319 - If some width are set on 'Auto', call the computation tools.
3320 - Check that no width are too small (raise a warning if this is the case)
3321 3) if dependent is on True check for dependent parameter (automatic for scan)"""
3322
3323 self.static_check_param_card(path, self, run=run, dependent=dependent)
3324
3325 card = param_card_mod.ParamCard(path)
3326 for param in card['decay']:
3327 width = param.value
3328 if width == 0:
3329 continue
3330 try:
3331 mass = card['mass'].get(param.lhacode).value
3332 except Exception:
3333 continue
3334
3335
3336
3337 @staticmethod
3340 pattern_scan = re.compile(r'''^(decay)?[\s\d]*scan''', re.I+re.M)
3341 pattern_width = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I)
3342 text = open(path).read()
3343
3344 if pattern_scan.search(text):
3345 if not isinstance(interface, cmd.CmdShell):
3346
3347 raise Exception("Scan are not allowed in web mode")
3348
3349 main_card = iterator_class(text)
3350 interface.param_card_iterator = main_card
3351 first_card = main_card.next(autostart=True)
3352 first_card.write(path)
3353 return CommonRunCmd.static_check_param_card(path, interface, run, dependent=True)
3354
3355 pdg_info = pattern_width.findall(text)
3356 if pdg_info:
3357 if run:
3358 logger.info('Computing the width set on auto in the param_card.dat')
3359 has_nlo = any(nlo.lower()=="@nlo" for _,nlo in pdg_info)
3360 pdg = [pdg for pdg,nlo in pdg_info]
3361 if not has_nlo:
3362 line = '%s' % (' '.join(pdg))
3363 else:
3364 line = '%s --nlo' % (' '.join(pdg))
3365 CommonRunCmd.static_compute_widths(line, interface, path)
3366 else:
3367 logger.info('''Some width are on Auto in the card.
3368 Those will be computed as soon as you have finish the edition of the cards.
3369 If you want to force the computation right now and being able to re-edit
3370 the cards afterwards, you can type \"compute_wdiths\".''')
3371
3372 card = param_card_mod.ParamCard(path)
3373 if dependent:
3374 AskforEditCard.update_dependent(interface, interface.me_dir, card, path, timer=20)
3375
3376 for param in card['decay']:
3377 width = param.value
3378 if width == 0:
3379 continue
3380 try:
3381 mass = card['mass'].get(param.lhacode).value
3382 except Exception:
3383 logger.warning('Missing mass in the lhef file (%s) . Please fix this (use the "update missing" command if needed)', param.lhacode[0])
3384 continue
3385 if mass and abs(width/mass) < 1e-12:
3386 if hasattr(interface, 'run_card') and isinstance(interface.run_card, banner_mod.RunCardLO):
3387 if interface.run_card['small_width_treatment'] < 1e-12:
3388 logger.error('The width of particle %s is too small for an s-channel resonance (%s) and the small_width_treatment parameter is too small to prevent numerical issues. If you have this particle in an s-channel, this is likely to create numerical instabilities .', param.lhacode[0], width)
3389 else:
3390 logger.error('The width of particle %s is too small for an s-channel resonance (%s). If you have this particle in an s-channel, this is likely to create numerical instabilities .', param.lhacode[0], width)
3391 if CommonRunCmd.sleep_for_error:
3392 time.sleep(5)
3393 CommonRunCmd.sleep_for_error = False
3394 elif not mass and width:
3395 logger.error('The width of particle %s is different of zero for a massless particle.', param.lhacode[0])
3396 if CommonRunCmd.sleep_for_error:
3397 time.sleep(5)
3398 CommonRunCmd.sleep_for_error = False
3399 return
3400
3401 @staticmethod
3403 """ factory to try to find a way to call the static method"""
3404
3405 handled = True
3406 if isinstance(interface, CommonRunCmd):
3407 if path:
3408 line = '%s %s' % (line, path)
3409 interface.do_compute_widths(line)
3410 else:
3411 handled = False
3412
3413 if handled:
3414 return
3415
3416 if hasattr(interface, 'do_compute_width'):
3417 interface.do_compute_widths('%s --path=%s' % (line, path))
3418 elif hasattr(interface, 'mother') and interface.mother and isinstance(interface, CommonRunCmd):
3419 return CommonRunCmd.static_compute_width(line, interface.mother, path)
3420 elif not MADEVENT:
3421 from madgraph.interface.master_interface import MasterCmd
3422 cmd = MasterCmd()
3423 interface.define_child_cmd_interface(cmd, interface=False)
3424 if hasattr(interface, 'options'):
3425 cmd.options.update(interface.options)
3426 try:
3427 cmd.exec_cmd('set automatic_html_opening False --no_save')
3428 except Exception:
3429 pass
3430
3431 model = interface.get_model()
3432
3433
3434 line = 'compute_widths %s --path=%s' % (line, path)
3435 cmd.exec_cmd(line, model=model)
3436 interface.child = None
3437 del cmd
3438 return
3439
3440
3441
3442 raise Exception('fail to find a way to handle Auto width')
3443
3444
3446 """return the information that need to be kept for the scan summary.
3447 Auto-width are automatically added."""
3448
3449 return {'cross': self.results.current['cross']}
3450
3451
3453 """If a ME run is currently running add a link in the html output"""
3454
3455
3456
3457 if hasattr(self, 'results') and hasattr(self.results, 'current') and\
3458 self.results.current and 'run_name' in self.results.current and \
3459 hasattr(self, 'me_dir'):
3460 name = self.results.current['run_name']
3461 tag = self.results.current['tag']
3462 self.debug_output = pjoin(self.me_dir, '%s_%s_debug.log' % (name,tag))
3463 if errortype:
3464 self.results.current.debug = errortype
3465 else:
3466 self.results.current.debug = self.debug_output
3467
3468 else:
3469
3470 self.debug_output = CommonRunCmd.debug_output
3471 if os.path.exists('ME5_debug') and not 'ME5_debug' in self.debug_output:
3472 try:
3473 os.remove('ME5_debug')
3474 except Exception:
3475 pass
3476 if not 'ME5_debug' in self.debug_output:
3477 os.system('ln -s %s ME5_debug &> /dev/null' % self.debug_output)
3478
3479
3481 """Not in help: exit """
3482
3483 if not self.force_run:
3484 try:
3485 os.remove(pjoin(self.me_dir,'RunWeb'))
3486 except Exception:
3487 pass
3488
3489 try:
3490 self.store_result()
3491 except Exception:
3492
3493 pass
3494
3495 try:
3496 self.update_status('', level=None)
3497 except Exception as error:
3498 pass
3499
3500 self.gen_card_html()
3501 return super(CommonRunCmd, self).do_quit(line)
3502
3503
3504 do_EOF = do_quit
3505 do_exit = do_quit
3506
3508 """try to remove RunWeb?"""
3509
3510 if not self.stop_for_runweb and not self.force_run:
3511 try:
3512 os.remove(pjoin(self.me_dir,'RunWeb'))
3513 except Exception:
3514 pass
3515
3516
3517 - def update_status(self, status, level, makehtml=True, force=True,
3518 error=False, starttime = None, update_results=True,
3519 print_log=True):
3520 """ update the index status """
3521
3522 if makehtml and not force:
3523 if hasattr(self, 'next_update') and time.time() < self.next_update:
3524 return
3525 else:
3526 self.next_update = time.time() + 3
3527
3528 if print_log:
3529 if isinstance(status, str):
3530 if '<br>' not in status:
3531 logger.info(status)
3532 elif starttime:
3533 running_time = misc.format_timer(time.time()-starttime)
3534 logger.info(' Idle: %s, Running: %s, Completed: %s [ %s ]' % \
3535 (status[0], status[1], status[2], running_time))
3536 else:
3537 logger.info(' Idle: %s, Running: %s, Completed: %s' % status[:3])
3538
3539 if isinstance(status, str) and status.startswith('\x1b['):
3540 status = status[status.index('m')+1:-7]
3541 if 'arXiv' in status:
3542 if '[' in status:
3543 status = status.split('[',1)[0]
3544 else:
3545 status = status.split('arXiv',1)[0]
3546
3547 if update_results:
3548 self.results.update(status, level, makehtml=makehtml, error=error)
3549
3550
3552 """Ask the question when launching generate_events/multi_run"""
3553
3554 check_card = ['pythia_card.dat', 'pgs_card.dat','delphes_card.dat',
3555 'delphes_trigger.dat', 'madspin_card.dat', 'shower_card.dat',
3556 'reweight_card.dat','pythia8_card.dat',
3557 'madanalysis5_parton_card.dat','madanalysis5_hadron_card.dat',
3558 'plot_card.dat']
3559
3560 cards_path = pjoin(self.me_dir,'Cards')
3561 for card in check_card:
3562 if card in ignore or (ignore == ['*'] and card not in need_card):
3563 continue
3564 if card not in need_card:
3565 if os.path.exists(pjoin(cards_path, card)):
3566 files.mv(pjoin(cards_path, card), pjoin(cards_path, '.%s' % card))
3567 else:
3568 if not os.path.exists(pjoin(cards_path, card)):
3569 if os.path.exists(pjoin(cards_path, '.%s' % card)):
3570 files.mv(pjoin(cards_path, '.%s' % card), pjoin(cards_path, card))
3571 else:
3572 default = card.replace('.dat', '_default.dat')
3573 files.cp(pjoin(cards_path, default),pjoin(cards_path, card))
3574
3575
3576 - def set_configuration(self, config_path=None, final=True, initdir=None, amcatnlo=False):
3577 """ assign all configuration variable from file
3578 ./Cards/mg5_configuration.txt. assign to default if not define """
3579
3580 if not hasattr(self, 'options') or not self.options:
3581 self.options = dict(self.options_configuration)
3582 self.options.update(self.options_madgraph)
3583 self.options.update(self.options_madevent)
3584
3585 if not config_path:
3586 if 'MADGRAPH_BASE' in os.environ:
3587 config_path = pjoin(os.environ['MADGRAPH_BASE'],'mg5_configuration.txt')
3588 self.set_configuration(config_path=config_path, final=False)
3589 if 'HOME' in os.environ:
3590 config_path = pjoin(os.environ['HOME'],'.mg5',
3591 'mg5_configuration.txt')
3592 if os.path.exists(config_path):
3593 self.set_configuration(config_path=config_path, final=False)
3594 if amcatnlo:
3595 me5_config = pjoin(self.me_dir, 'Cards', 'amcatnlo_configuration.txt')
3596 else:
3597 me5_config = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
3598 self.set_configuration(config_path=me5_config, final=False, initdir=self.me_dir)
3599
3600 if 'mg5_path' in self.options and self.options['mg5_path']:
3601 MG5DIR = self.options['mg5_path']
3602 config_file = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
3603 self.set_configuration(config_path=config_file, final=False,initdir=MG5DIR)
3604 else:
3605 self.options['mg5_path'] = None
3606 return self.set_configuration(config_path=me5_config, final=final,initdir=self.me_dir)
3607
3608 config_file = open(config_path)
3609
3610
3611 logger.info('load configuration from %s ' % config_file.name)
3612 for line in config_file:
3613
3614 if '#' in line:
3615 line = line.split('#',1)[0]
3616 line = line.replace('\n','').replace('\r\n','')
3617 try:
3618 name, value = line.split('=')
3619 except ValueError:
3620 pass
3621 else:
3622 name = name.strip()
3623 value = value.strip()
3624 if name.endswith('_path') and not name.startswith('cluster'):
3625 path = value
3626 if os.path.isdir(path):
3627 self.options[name] = os.path.realpath(path)
3628 continue
3629 if not initdir:
3630 continue
3631 path = pjoin(initdir, value)
3632 if os.path.isdir(path):
3633 self.options[name] = os.path.realpath(path)
3634 continue
3635 else:
3636 self.options[name] = value
3637 if value.lower() == "none":
3638 self.options[name] = None
3639
3640 if not final:
3641 return self.options
3642
3643
3644
3645 for key in self.options:
3646
3647 if key.endswith('path') and not key.startswith("cluster"):
3648 path = self.options[key]
3649 if path is None:
3650 continue
3651 if os.path.isdir(path):
3652 self.options[key] = os.path.realpath(path)
3653 continue
3654 path = pjoin(self.me_dir, self.options[key])
3655 if os.path.isdir(path):
3656 self.options[key] = os.path.realpath(path)
3657 continue
3658 elif 'mg5_path' in self.options and self.options['mg5_path']:
3659 path = pjoin(self.options['mg5_path'], self.options[key])
3660 if os.path.isdir(path):
3661 self.options[key] = os.path.realpath(path)
3662 continue
3663 self.options[key] = None
3664 elif key.startswith('cluster') and key != 'cluster_status_update':
3665 if key in ('cluster_nb_retry','cluster_wait_retry'):
3666 self.options[key] = int(self.options[key])
3667 if hasattr(self,'cluster'):
3668 del self.cluster
3669 pass
3670 elif key == 'automatic_html_opening':
3671 if self.options[key] in ['False', 'True']:
3672 self.options[key] =ast.literal_eval(self.options[key])
3673 elif key == "notification_center":
3674 if self.options[key] in ['False', 'True']:
3675 self.allow_notification_center =ast.literal_eval(self.options[key])
3676 self.options[key] =ast.literal_eval(self.options[key])
3677 elif key not in ['text_editor','eps_viewer','web_browser','stdout_level',
3678 'complex_mass_scheme', 'gauge', 'group_subprocesses']:
3679
3680 try:
3681 self.do_set("%s %s --no_save" % (key, self.options[key]), log=False)
3682 except self.InvalidCmd:
3683 logger.warning("Option %s from config file not understood" \
3684 % key)
3685
3686
3687 misc.open_file.configure(self.options)
3688
3689
3690 if MADEVENT and 'mg5_path' in self.options and self.options['mg5_path']:
3691 mg5dir = self.options['mg5_path']
3692 if mg5dir not in sys.path:
3693 sys.path.append(mg5dir)
3694 if pjoin(mg5dir, 'PLUGIN') not in self.plugin_path:
3695 self.plugin_path.append(pjoin(mg5dir,'PLUGIN'))
3696
3697 self.configure_run_mode(self.options['run_mode'])
3698 return self.options
3699
3700 @staticmethod
3702 """ find a valid run_name for the current job """
3703
3704 name = 'run_%02d'
3705 data = [int(s[4:j]) for s in os.listdir(pjoin(me_dir,'Events')) for
3706 j in range(4,len(s)+1) if \
3707 s.startswith('run_') and s[4:j].isdigit()]
3708 return name % (max(data+[0])+1)
3709
3710
3711
3713 """Require MG5 directory: decay events with spin correlations
3714 """
3715
3716 if '-from_cards' in line and not os.path.exists(pjoin(self.me_dir, 'Cards', 'madspin_card.dat')):
3717 return
3718
3719
3720
3721 if MADEVENT and not self.options['mg5_path']:
3722 raise self.InvalidCmd('''The module decay_events requires that MG5 is installed on the system.
3723 You can install it and set its path in ./Cards/me5_configuration.txt''')
3724 elif MADEVENT:
3725 sys.path.append(self.options['mg5_path'])
3726 try:
3727 import MadSpin.decay as decay
3728 import MadSpin.interface_madspin as interface_madspin
3729 except ImportError:
3730 if __debug__:
3731 raise
3732 else:
3733 raise self.ConfigurationError('''Can\'t load MadSpin
3734 The variable mg5_path might not be correctly configured.''')
3735
3736 self.update_status('Running MadSpin', level='madspin')
3737 if not '-from_cards' in line and '-f' not in line:
3738 self.keep_cards(['madspin_card.dat'], ignore=['*'])
3739 self.ask_edit_cards(['madspin_card.dat'], 'fixed', plot=False)
3740 self.help_decay_events(skip_syntax=True)
3741
3742
3743 args = self.split_arg(line)
3744 self.check_decay_events(args)
3745
3746 madspin_cmd = interface_madspin.MadSpinInterface(args[0])
3747
3748 madspin_cmd.mg5cmd.options.update(self.options)
3749 for key, value in self.options.items():
3750 if isinstance(value, str):
3751 madspin_cmd.mg5cmd.exec_cmd( 'set %s %s --no_save' %(key,value), errorhandling=False, printcmd=False, precmd=False, postcmd=True)
3752 madspin_cmd.cluster = self.cluster
3753 madspin_cmd.mother = self
3754
3755 madspin_cmd.update_status = lambda *x,**opt: self.update_status(*x, level='madspin',**opt)
3756
3757 path = pjoin(self.me_dir, 'Cards', 'madspin_card.dat')
3758
3759 madspin_cmd.import_command_file(path)
3760
3761
3762 if not madspin_cmd.me_run_name:
3763
3764 i = 1
3765 while os.path.exists(pjoin(self.me_dir,'Events', '%s_decayed_%i' % (self.run_name,i))):
3766 i+=1
3767 new_run = '%s_decayed_%i' % (self.run_name,i)
3768 else:
3769 new_run = madspin_cmd.me_run_name
3770 if os.path.exists(pjoin(self.me_dir,'Events', new_run)):
3771 i = 1
3772 while os.path.exists(pjoin(self.me_dir,'Events', '%s_%i' % (new_run,i))):
3773 i+=1
3774 new_run = '%s_%i' % (new_run,i)
3775
3776 evt_dir = pjoin(self.me_dir, 'Events')
3777
3778 os.mkdir(pjoin(evt_dir, new_run))
3779 current_file = args[0].replace('.lhe', '_decayed.lhe')
3780 new_file = pjoin(evt_dir, new_run, os.path.basename(args[0]))
3781 if not os.path.exists(current_file):
3782 if os.path.exists(current_file+'.gz'):
3783 current_file += '.gz'
3784 new_file += '.gz'
3785 elif current_file.endswith('.gz') and os.path.exists(current_file[:-3]):
3786 current_file = current_file[:-3]
3787 new_file = new_file[:-3]
3788 else:
3789 logger.error('MadSpin fails to create any decayed file.')
3790 return
3791
3792 files.mv(current_file, new_file)
3793 logger.info("The decayed event file has been moved to the following location: ")
3794 logger.info(new_file)
3795
3796 if hasattr(self, 'results'):
3797 current = self.results.current
3798 nb_event = self.results.current['nb_event']
3799 if not nb_event:
3800 current = self.results[self.run_name][0]
3801 nb_event = current['nb_event']
3802
3803 cross = current['cross']
3804 error = current['error']
3805 self.results.add_run( new_run, self.run_card)
3806 self.results.add_detail('nb_event', int(nb_event*madspin_cmd.efficiency))
3807 self.results.add_detail('cross', madspin_cmd.cross)
3808 self.results.add_detail('error', madspin_cmd.error+ cross * madspin_cmd.err_branching_ratio)
3809 self.results.add_detail('run_mode', current['run_mode'])
3810 self.to_store.append("event")
3811
3812 self.run_name = new_run
3813 self.banner = madspin_cmd.banner
3814 self.banner.add(path)
3815 self.banner.write(pjoin(self.me_dir,'Events',self.run_name, '%s_%s_banner.txt' %
3816 (self.run_name, self.run_tag)))
3817 self.update_status('MadSpin Done', level='parton', makehtml=False)
3818 if 'unweighted' in os.path.basename(args[0]):
3819 self.create_plot('parton')
3820
3827
3829 "Complete the print results command"
3830 args = self.split_arg(line[0:begidx], error=False)
3831 if len(args) == 1:
3832
3833 data = misc.glob(pjoin('*','unweighted_events.lhe.gz'),
3834 pjoin(self.me_dir, 'Events'))
3835
3836 data = [n.rsplit('/',2)[1] for n in data]
3837 tmp1 = self.list_completion(text, data)
3838 return tmp1
3839 else:
3840 data = misc.glob('*_pythia_events.hep.gz', pjoin(self.me_dir, 'Events', args[0]))
3841 data = [os.path.basename(p).rsplit('_',1)[0] for p in data]
3842 data += ["--mode=a", "--mode=w", "--path=", "--format=short"]
3843 tmp1 = self.list_completion(text, data)
3844 return tmp1
3845
3847 logger.info("syntax: print_result [RUN] [TAG] [options]")
3848 logger.info("-- show in text format the status of the run (cross-section/nb-event/...)")
3849 logger.info("--path= defines the path of the output file.")
3850 logger.info("--mode=a allow to add the information at the end of the file.")
3851 logger.info("--format=short (only if --path is define)")
3852 logger.info(" allows to have a multi-column output easy to parse")
3853
3854
3855
3857 """ return the model name """
3858 if hasattr(self, 'model_name'):
3859 return self.model_name
3860
3861 def join_line(old, to_add):
3862 if old.endswith('\\'):
3863 newline = old[:-1] + to_add
3864 else:
3865 newline = old + line
3866 return newline
3867
3868
3869
3870 model = 'sm'
3871 proc = []
3872 continuation_line = None
3873 for line in open(os.path.join(self.me_dir,'Cards','proc_card_mg5.dat')):
3874 line = line.split('#')[0]
3875 if continuation_line:
3876 line = line.strip()
3877 if continuation_line == 'model':
3878 model = join_line(model, line)
3879 elif continuation_line == 'proc':
3880 proc = join_line(proc, line)
3881 if not line.endswith('\\'):
3882 continuation_line = None
3883 continue
3884
3885 if line.startswith('import') and 'model' in line:
3886 model = line.split()[2]
3887 proc = []
3888 if model.endswith('\\'):
3889 continuation_line = 'model'
3890 elif line.startswith('generate'):
3891 proc.append(line.split(None,1)[1])
3892 if proc[-1].endswith('\\'):
3893 continuation_line = 'proc'
3894 elif line.startswith('add process'):
3895 proc.append(line.split(None,2)[2])
3896 if proc[-1].endswith('\\'):
3897 continuation_line = 'proc'
3898 self.model = model
3899 self.process = proc
3900 return model
3901
3902
3903
3929
3930
3932 args = self.split_arg(line[0:begidx], error=False)
3933
3934 if len(args) == 1 and os.path.sep not in text:
3935
3936 data = misc.glob(pjoin('*','*events.lhe*'), pjoin(self.me_dir, 'Events'))
3937 data = [n.rsplit('/',2)[1] for n in data]
3938 return self.list_completion(text, data, line)
3939 else:
3940 return self.path_completion(text,
3941 os.path.join('.',*[a for a in args \
3942 if a.endswith(os.path.sep)]))
3943
3945 "Complete the pythia command"
3946 args = self.split_arg(line[0:begidx], error=False)
3947
3948
3949 data = misc.glob(pjoin('*','*events.lhe*'), pjoin(self.me_dir, 'Events'))
3950 data = list(set([n.rsplit('/',2)[1] for n in data]))
3951 if not '-f' in args:
3952 data.append('-f')
3953 tmp1 = self.list_completion(text, data)
3954 return tmp1
3955
3956
3957
3959 "Complete the compute_widths command"
3960
3961 args = self.split_arg(line[0:begidx])
3962
3963 if args[-1] in ['--path=', '--output=']:
3964 completion = {'path': self.path_completion(text)}
3965 elif line[begidx-1] == os.path.sep:
3966 current_dir = pjoin(*[a for a in args if a.endswith(os.path.sep)])
3967 if current_dir.startswith('--path='):
3968 current_dir = current_dir[7:]
3969 if current_dir.startswith('--output='):
3970 current_dir = current_dir[9:]
3971 completion = {'path': self.path_completion(text, current_dir)}
3972 else:
3973 completion = {}
3974 completion['options'] = self.list_completion(text,
3975 ['--path=', '--output=', '--min_br=0.\$', '--nlo',
3976 '--precision_channel=0.\$', '--body_decay='])
3977
3978 return self.deal_multiple_categories(completion, formatting)
3979
3980
3982 """update the make_opts file writing the environmental variables
3983 stored in make_opts_var"""
3984 make_opts = os.path.join(self.me_dir, 'Source', 'make_opts')
3985
3986
3987 if not hasattr(self,'options') or not 'pythia8_path' in self.options or \
3988 not self.options['pythia8_path'] or \
3989 not os.path.isfile(pjoin(self.options['pythia8_path'],'bin','pythia8-config')):
3990 self.make_opts_var['PYTHIA8_PATH']='NotInstalled'
3991 else:
3992 self.make_opts_var['PYTHIA8_PATH']=self.options['pythia8_path']
3993
3994 self.make_opts_var['MG5AMC_VERSION'] = misc.get_pkg_info()['version']
3995
3996 if run_card and run_card.LO:
3997 if __debug__ and 'global_flag' not in run_card.user_set:
3998 self.make_opts_var['GLOBAL_FLAG'] = "-O -fbounds-check"
3999 else:
4000 self.make_opts_var['GLOBAL_FLAG'] = run_card['global_flag']
4001 self.make_opts_var['ALOHA_FLAG'] = run_card['aloha_flag']
4002 self.make_opts_var['MATRIX_FLAG'] = run_card['matrix_flag']
4003
4004 return self.update_make_opts_full(make_opts, self.make_opts_var)
4005
4006 @staticmethod
4008 """update the make_opts file writing the environmental variables
4009 of def_variables.
4010 if a value of the dictionary is None then it is not written.
4011 """
4012 make_opts = path
4013 pattern = re.compile(r'^(\w+)\s*=\s*(.*)$',re.DOTALL)
4014 diff = False
4015
4016
4017 tag = '#end_of_make_opts_variables\n'
4018 make_opts_variable = True
4019 content = []
4020 variables = dict(def_variables)
4021 need_keys = list(variables.keys())
4022 for line in open(make_opts):
4023 line = line.strip()
4024 if make_opts_variable:
4025 if line.startswith('#') or not line:
4026 if line.startswith('#end_of_make_opts_variables'):
4027 make_opts_variable = False
4028 continue
4029 elif pattern.search(line):
4030 key, value = pattern.search(line).groups()
4031 if key not in variables:
4032 variables[key] = value
4033 elif value != variables[key]:
4034 diff=True
4035 else:
4036 need_keys.remove(key)
4037 else:
4038 make_opts_variable = False
4039 content.append(line)
4040 else:
4041 content.append(line)
4042
4043 if need_keys:
4044 diff=True
4045
4046 content_variables = '\n'.join('%s=%s' % (k,v) for k, v in variables.items() if v is not None)
4047 content_variables += '\n%s' % tag
4048
4049 if diff:
4050 with open(make_opts, 'w') as fsock:
4051 fsock.write(content_variables + '\n'.join(content))
4052 return
4053
4054
4055
4057 """links lhapdf into libdir"""
4058
4059 lhapdf_version = self.get_lhapdf_version()
4060 logger.info('Using LHAPDF v%s interface for PDFs' % lhapdf_version)
4061 lhalibdir = subprocess.Popen([self.options['lhapdf'], '--libdir'],
4062 stdout = subprocess.PIPE).stdout.read().decode(errors='ignore').strip()
4063
4064 if lhapdf_version.startswith('5.'):
4065 pdfsetsdir = subprocess.Popen([self.options['lhapdf'], '--pdfsets-path'],
4066 stdout = subprocess.PIPE).stdout.read().decode(errors='ignore').strip()
4067 else:
4068 pdfsetsdir = subprocess.Popen([self.options['lhapdf'], '--datadir'],
4069 stdout = subprocess.PIPE).stdout.read().decode(errors='ignore').strip()
4070
4071 self.lhapdf_pdfsets = self.get_lhapdf_pdfsets_list(pdfsetsdir)
4072
4073 lhalib = 'libLHAPDF.a'
4074
4075 if os.path.exists(pjoin(libdir, lhalib)):
4076 files.rm(pjoin(libdir, lhalib))
4077 files.ln(pjoin(lhalibdir, lhalib), libdir)
4078
4079 if not os.path.isdir(pjoin(libdir, 'PDFsets')):
4080 os.mkdir(pjoin(libdir, 'PDFsets'))
4081 self.make_opts_var['lhapdf'] = self.options['lhapdf']
4082 self.make_opts_var['lhapdfversion'] = lhapdf_version[0]
4083 self.make_opts_var['lhapdfsubversion'] = lhapdf_version.split('.',2)[1]
4084 self.make_opts_var['lhapdf_config'] = self.options['lhapdf']
4085
4086
4088 """reads the proc_characteristics file and initialises the correspondant
4089 dictionary"""
4090
4091 if not path:
4092 path = os.path.join(self.me_dir, 'SubProcesses', 'proc_characteristics')
4093
4094 self.proc_characteristics = banner_mod.ProcCharacteristic(path)
4095 return self.proc_characteristics
4096
4097
4099 """copy (if needed) the lhapdf set corresponding to the lhaid in lhaid_list
4100 into lib/PDFsets.
4101 if require_local is False, just ensure that the pdf is in pdfsets_dir
4102 """
4103
4104 if not hasattr(self, 'lhapdf_pdfsets'):
4105 self.lhapdf_pdfsets = self.get_lhapdf_pdfsets_list(pdfsets_dir)
4106
4107 pdfsetname=set()
4108 for lhaid in lhaid_list:
4109 if isinstance(lhaid, str) and lhaid.isdigit():
4110 lhaid = int(lhaid)
4111 if isinstance(lhaid, (int,float)):
4112 try:
4113 if lhaid in self.lhapdf_pdfsets:
4114 pdfsetname.add(self.lhapdf_pdfsets[lhaid]['filename'])
4115 else:
4116 raise MadGraph5Error('lhaid %s not valid input number for the current lhapdf' % lhaid )
4117 except KeyError:
4118 if self.lhapdf_version.startswith('5'):
4119 raise MadGraph5Error(\
4120 ('invalid lhaid set in th run_card: %d .\nPlease note that some sets' % lhaid) + \
4121 '(eg MSTW 90%CL error sets) \nare not available in aMC@NLO + LHAPDF 5.x.x')
4122 else:
4123 logger.debug('%d not found in pdfsets.index' % lhaid)
4124 else:
4125 pdfsetname.add(lhaid)
4126
4127
4128
4129
4130 if not os.path.isdir(pdfsets_dir):
4131 try:
4132 os.mkdir(pdfsets_dir)
4133 except OSError:
4134 pdfsets_dir = pjoin(self.me_dir, 'lib', 'PDFsets')
4135 elif os.path.exists(pjoin(self.me_dir, 'lib', 'PDFsets')):
4136
4137 for name in os.listdir(pjoin(self.me_dir, 'lib', 'PDFsets')):
4138 if name not in pdfsetname:
4139 try:
4140 if os.path.isdir(pjoin(self.me_dir, 'lib', 'PDFsets', name)):
4141 shutil.rmtree(pjoin(self.me_dir, 'lib', 'PDFsets', name))
4142 else:
4143 os.remove(pjoin(self.me_dir, 'lib', 'PDFsets', name))
4144 except Exception as error:
4145 logger.debug('%s', error)
4146
4147 if self.options["cluster_local_path"]:
4148 lhapdf_cluster_possibilities = [self.options["cluster_local_path"],
4149 pjoin(self.options["cluster_local_path"], "lhapdf"),
4150 pjoin(self.options["cluster_local_path"], "lhapdf", "pdfsets"),
4151 pjoin(self.options["cluster_local_path"], "..", "lhapdf"),
4152 pjoin(self.options["cluster_local_path"], "..", "lhapdf", "pdfsets"),
4153 pjoin(self.options["cluster_local_path"], "..", "lhapdf","pdfsets", "6.1")
4154 ]
4155 else:
4156 lhapdf_cluster_possibilities = []
4157
4158 for pdfset in pdfsetname:
4159
4160 if self.options["cluster_local_path"] and self.options["run_mode"] == 1 and \
4161 any((os.path.exists(pjoin(d, pdfset)) for d in lhapdf_cluster_possibilities)):
4162
4163 os.environ["LHAPATH"] = [d for d in lhapdf_cluster_possibilities if os.path.exists(pjoin(d, pdfset))][0]
4164 os.environ["CLUSTER_LHAPATH"] = os.environ["LHAPATH"]
4165
4166 if os.path.exists(pjoin(pdfsets_dir, pdfset)):
4167 try:
4168 if os.path.isdir(pjoin(pdfsets_dir, name)):
4169 shutil.rmtree(pjoin(pdfsets_dir, name))
4170 else:
4171 os.remove(pjoin(pdfsets_dir, name))
4172 except Exception as error:
4173 logger.debug('%s', error)
4174 if not require_local and (os.path.exists(pjoin(pdfsets_dir, pdfset)) or \
4175 os.path.isdir(pjoin(pdfsets_dir, pdfset))):
4176 continue
4177 if not require_local:
4178 if 'LHAPDF_DATA_PATH' in os.environ:
4179 found = False
4180 for path in os.environ['LHAPDF_DATA_PATH'].split(":"):
4181 if (os.path.exists(pjoin(path, pdfset)) or \
4182 os.path.isdir(pjoin(path, pdfset))):
4183 found =True
4184 break
4185 if found:
4186 continue
4187
4188
4189
4190 elif not os.path.exists(pjoin(self.me_dir, 'lib', 'PDFsets', pdfset)) and \
4191 not os.path.isdir(pjoin(self.me_dir, 'lib', 'PDFsets', pdfset)):
4192
4193 if pdfset and not os.path.exists(pjoin(pdfsets_dir, pdfset)):
4194 self.install_lhapdf_pdfset(pdfsets_dir, pdfset)
4195
4196 if os.path.exists(pjoin(pdfsets_dir, pdfset)):
4197 files.cp(pjoin(pdfsets_dir, pdfset), pjoin(self.me_dir, 'lib', 'PDFsets'))
4198 elif os.path.exists(pjoin(os.path.dirname(pdfsets_dir), pdfset)):
4199 files.cp(pjoin(os.path.dirname(pdfsets_dir), pdfset), pjoin(self.me_dir, 'lib', 'PDFsets'))
4200
4202 """idownloads and install the pdfset filename in the pdfsets_dir"""
4203 lhapdf_version = self.get_lhapdf_version()
4204 local_path = pjoin(self.me_dir, 'lib', 'PDFsets')
4205 return self.install_lhapdf_pdfset_static(self.options['lhapdf'],
4206 pdfsets_dir, filename,
4207 lhapdf_version=lhapdf_version,
4208 alternate_path=local_path)
4209
4210
4211 @staticmethod
4214 """idownloads and install the pdfset filename in the pdfsets_dir.
4215 Version which can be used independently of the class.
4216 local path is used if the global installation fails.
4217 """
4218
4219 if not lhapdf_version:
4220 lhapdf_version = CommonRunCmd.get_lhapdf_version_static(lhapdf_config)
4221
4222 if not pdfsets_dir:
4223 pdfsets_dir = CommonRunCmd.get_lhapdf_pdfsetsdir_static(lhapdf_config, lhapdf_version)
4224
4225 if isinstance(filename, int):
4226 pdf_info = CommonRunCmd.get_lhapdf_pdfsets_list_static(pdfsets_dir, lhapdf_version)
4227 filename = pdf_info[filename]['filename']
4228
4229 if os.path.exists(pjoin(pdfsets_dir, filename)):
4230 logger.debug('%s is already present in %s', filename, pdfsets_dir)
4231 return
4232
4233 logger.info('Trying to download %s' % filename)
4234
4235
4236 if lhapdf_version.startswith('5.'):
4237
4238
4239
4240 getdata = lhapdf_config.replace('lhapdf-config', ('lhapdf-getdata'))
4241 misc.call([getdata, filename], cwd = pdfsets_dir)
4242
4243 elif lhapdf_version.startswith('6.'):
4244
4245
4246 getdata = lhapdf_config.replace('lhapdf-config', ('lhapdf'))
4247
4248 if lhapdf_version.startswith('6.1'):
4249 misc.call([getdata, 'install', filename], cwd = pdfsets_dir)
4250 else:
4251
4252 lhapdf = misc.import_python_lhapdf(lhapdf_config)
4253 if lhapdf:
4254 if 'PYTHONPATH' in os.environ:
4255 os.environ['PYTHONPATH']+= ':' + os.path.dirname(lhapdf.__file__)
4256 else:
4257 os.environ['PYTHONPATH'] = ':'.join(sys.path) + ':' + os.path.dirname(lhapdf.__file__)
4258 else:
4259 logger.warning('lhapdf 6.2.1 requires python integration in order to download pdf set. Trying anyway')
4260 misc.call([getdata, 'install', filename], cwd = pdfsets_dir)
4261
4262 else:
4263 raise MadGraph5Error('Not valid LHAPDF version: %s' % lhapdf_version)
4264
4265
4266 if os.path.exists(pjoin(pdfsets_dir, filename)) or \
4267 os.path.isdir(pjoin(pdfsets_dir, filename)):
4268 logger.info('%s successfully downloaded and stored in %s' \
4269 % (filename, pdfsets_dir))
4270
4271
4272 elif lhapdf_version.startswith('5.'):
4273 logger.warning('Could not download %s into %s. Trying to save it locally' \
4274 % (filename, pdfsets_dir))
4275 CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, alternate_path, filename,
4276 lhapdf_version=lhapdf_version)
4277 elif lhapdf_version.startswith('6.') and '.LHgrid' in filename:
4278 logger.info('Could not download %s: Try %s', filename, filename.replace('.LHgrid',''))
4279 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, pdfsets_dir,
4280 filename.replace('.LHgrid',''),
4281 lhapdf_version, alternate_path)
4282 elif lhapdf_version.startswith('6.'):
4283
4284 wwwpath = "http://lhapdfsets.web.cern.ch/lhapdfsets/current/%s.tar.gz" % filename
4285 misc.wget(wwwpath, pjoin(pdfsets_dir, '%s.tar.gz' %filename))
4286 misc.call(['tar', '-xzpvf', '%s.tar.gz' %filename],
4287 cwd=pdfsets_dir)
4288
4289 if os.path.exists(pjoin(pdfsets_dir, filename)) or \
4290 os.path.isdir(pjoin(pdfsets_dir, filename)):
4291 logger.info('%s successfully downloaded and stored in %s' \
4292 % (filename, pdfsets_dir))
4293 elif 'LHAPDF_DATA_PATH' in os.environ and os.environ['LHAPDF_DATA_PATH']:
4294
4295 if pdfsets_dir in os.environ['LHAPDF_DATA_PATH'].split(':'):
4296 lhapath = os.environ['LHAPDF_DATA_PATH'].split(':')
4297 lhapath = [p for p in lhapath if os.path.exists(p)]
4298 lhapath.remove(pdfsets_dir)
4299 os.environ['LHAPDF_DATA_PATH'] = ':'.join(lhapath)
4300 if lhapath:
4301 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4302 filename,
4303 lhapdf_version, alternate_path)
4304 elif 'LHAPATH' in os.environ and os.environ['LHAPATH']:
4305 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4306 filename,
4307 lhapdf_version, alternate_path)
4308 else:
4309 raise MadGraph5Error( \
4310 'Could not download %s into %s. Please try to install it manually.' \
4311 % (filename, pdfsets_dir))
4312 else:
4313 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4314 filename,
4315 lhapdf_version, alternate_path)
4316 elif 'LHAPATH' in os.environ and os.environ['LHAPATH']:
4317 if pdfsets_dir in os.environ['LHAPATH'].split(':'):
4318 lhapath = os.environ['LHAPATH'].split(':')
4319 lhapath = [p for p in lhapath if os.path.exists(p)]
4320 lhapath.remove(pdfsets_dir)
4321 os.environ['LHAPATH'] = ':'.join(lhapath)
4322 if lhapath:
4323 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4324 filename,
4325 lhapdf_version, alternate_path)
4326 else:
4327 raise MadGraph5Error('Could not download %s into %s. Please try to install it manually.' \
4328 % (filename, pdfsets_dir))
4329 else:
4330 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4331 filename,
4332 lhapdf_version, alternate_path)
4333 else:
4334 raise MadGraph5Error('Could not download %s into %s. Please try to install it manually.' \
4335 % (filename, pdfsets_dir))
4336
4337 else:
4338 raise MadGraph5Error('Could not download %s into %s. Please try to install it manually.' \
4339 % (filename, pdfsets_dir))
4340
4341
4342
4344 """read the PDFsets.index file, which should be located in the same
4345 place as pdfsets_dir, and return a list of dictionaries with the information
4346 about each pdf set"""
4347 lhapdf_version = self.get_lhapdf_version()
4348 return self.get_lhapdf_pdfsets_list_static(pdfsets_dir, lhapdf_version)
4349
4350 @staticmethod
4352
4353 if lhapdf_version.startswith('5.'):
4354 if os.path.exists('%s.index' % pdfsets_dir):
4355 indexfile = '%s.index' % pdfsets_dir
4356 else:
4357 raise MadGraph5Error('index of lhapdf file not found')
4358 pdfsets_lines = \
4359 [l for l in open(indexfile).read().split('\n') if l.strip() and \
4360 not '90cl' in l]
4361 lhapdf_pdfsets = dict( (int(l.split()[0]), {'lhaid': int(l.split()[0]),
4362 'pdflib_ntype': int(l.split()[1]),
4363 'pdflib_ngroup': int(l.split()[2]),
4364 'pdflib_nset': int(l.split()[3]),
4365 'filename': l.split()[4],
4366 'lhapdf_nmem': int(l.split()[5]),
4367 'q2min': float(l.split()[6]),
4368 'q2max': float(l.split()[7]),
4369 'xmin': float(l.split()[8]),
4370 'xmax': float(l.split()[9]),
4371 'description': l.split()[10]}) \
4372 for l in pdfsets_lines)
4373
4374 elif lhapdf_version.startswith('6.'):
4375 pdfsets_lines = \
4376 [l for l in open(pjoin(pdfsets_dir, 'pdfsets.index'),'r').read().split('\n') if l.strip()]
4377 lhapdf_pdfsets = dict( (int(l.split()[0]),
4378 {'lhaid': int(l.split()[0]),
4379 'filename': l.split()[1]}) \
4380 for l in pdfsets_lines)
4381
4382 else:
4383 raise MadGraph5Error('Not valid LHAPDF version: %s' % lhapdf_version)
4384
4385 return lhapdf_pdfsets
4386
4387 @staticmethod
4389 """returns the lhapdf version number"""
4390
4391 try:
4392 lhapdf_version = \
4393 subprocess.Popen([lhapdf_config, '--version'],
4394 stdout = subprocess.PIPE).stdout.read().decode(errors='ignore').strip()
4395 except OSError as error:
4396 if error.errno == 2:
4397 raise Exception( 'lhapdf executable (%s) is not found on your system. Please install it and/or indicate the path to the correct executable in input/mg5_configuration.txt' % lhapdf_config)
4398 else:
4399 raise
4400
4401
4402 if lhapdf_version.startswith('6.0'):
4403 raise MadGraph5Error('LHAPDF 6.0.x not supported. Please use v6.1 or later')
4404 return lhapdf_version
4405
4406
4408 """returns the lhapdf version number"""
4409 if not hasattr(self, 'lhapdfversion'):
4410 self.lhapdf_version = self.get_lhapdf_version_static(self.options['lhapdf'])
4411 return self.lhapdf_version
4412
4413 @staticmethod
4415 """ """
4416 if not lhapdf_version:
4417 lhapdf_version = CommonRunCmd.get_lhapdf_version_static(lhapdf_config)
4418
4419
4420 if 'LHAPDF_DATA_PATH' in list(os.environ.keys()) and os.environ['LHAPDF_DATA_PATH']:
4421 datadir = os.environ['LHAPDF_DATA_PATH']
4422 elif lhapdf_version.startswith('5.'):
4423 datadir = subprocess.Popen([lhapdf_config, '--pdfsets-path'],
4424 stdout = subprocess.PIPE).stdout.read().decode(errors='ignore').strip()
4425
4426 elif lhapdf_version.startswith('6.'):
4427 datadir = subprocess.Popen([lhapdf_config, '--datadir'],
4428 stdout = subprocess.PIPE).stdout.read().decode(errors='ignore').strip()
4429
4430 if ':' in datadir:
4431 for totry in datadir.split(':'):
4432 if os.path.exists(pjoin(totry, 'pdfsets.index')):
4433 return totry
4434 else:
4435 return None
4436
4437 return datadir
4438
4443
4444
4446 """get the list of Pdirectory if not yet saved."""
4447
4448 if hasattr(self, "Pdirs"):
4449 if self.me_dir in self.Pdirs[0]:
4450 return self.Pdirs
4451 self.Pdirs = [pjoin(self.me_dir, 'SubProcesses', l.strip())
4452 for l in open(pjoin(self.me_dir,'SubProcesses', 'subproc.mg'))]
4453 return self.Pdirs
4454
4456
4457 if 'LHAPATH' in os.environ:
4458 for d in os.environ['LHAPATH'].split(':'):
4459 if os.path.isdir(d):
4460 return d
4461
4462
4463 lhapdf_version = self.get_lhapdf_version()
4464
4465 if lhapdf_version.startswith('5.'):
4466 libdir = subprocess.Popen([self.options['lhapdf-config'], '--libdir'],
4467 stdout = subprocess.PIPE).stdout.read().decode(errors='ignore').strip()
4468
4469 elif lhapdf_version.startswith('6.'):
4470 libdir = subprocess.Popen([self.options['lhapdf'], '--libs'],
4471 stdout = subprocess.PIPE).stdout.read().decode(errors='ignore').strip()
4472
4473 return libdir
4474
4476 """A class for asking a question where in addition you can have the
4477 set command define and modifying the param_card/run_card correctly
4478
4479 special action can be trigger via trigger_XXXX when the user start a line
4480 with XXXX. the output of such function should be new line that can be handle.
4481 (return False to repeat the question)
4482 """
4483
4484 all_card_name = ['param_card', 'run_card', 'pythia_card', 'pythia8_card',
4485 'madweight_card', 'MadLoopParams', 'shower_card']
4486 to_init_card = ['param', 'run', 'madweight', 'madloop',
4487 'shower', 'pythia8','delphes','madspin']
4488 special_shortcut = {}
4489 special_shortcut_help = {}
4490
4491 integer_bias = 1
4492
4493 PY8Card_class = banner_mod.PY8Card
4494
4496 """ define all default variable. No load of card here.
4497 This allow to subclass this class and just change init and still have
4498 all variables defined."""
4499
4500 if not hasattr(self, 'me_dir'):
4501 self.me_dir = None
4502 self.param_card = None
4503 self.run_card = {}
4504 self.pname2block = {}
4505 self.conflict = []
4506 self.restricted_value = {}
4507 self.mode = ''
4508 self.cards = []
4509 self.run_set = []
4510 self.has_mw = False
4511 self.has_ml = False
4512 self.has_shower = False
4513 self.has_PY8 = False
4514 self.has_delphes = False
4515 self.paths = {}
4516 self.update_block = []
4517
4518
4520
4521 if 'pwd' in opt:
4522 self.me_dir = opt['pwd']
4523 elif 'mother_interface' in opt:
4524 self.mother_interface = opt['mother_interface']
4525 if not hasattr(self, 'me_dir') or not self.me_dir:
4526 self.me_dir = self.mother_interface.me_dir
4527
4528
4529 self.paths['param'] = pjoin(self.me_dir,'Cards','param_card.dat')
4530 self.paths['param_default'] = pjoin(self.me_dir,'Cards','param_card_default.dat')
4531 self.paths['run'] = pjoin(self.me_dir,'Cards','run_card.dat')
4532 self.paths['run_default'] = pjoin(self.me_dir,'Cards','run_card_default.dat')
4533 self.paths['transfer'] =pjoin(self.me_dir,'Cards','transfer_card.dat')
4534 self.paths['MadWeight'] =pjoin(self.me_dir,'Cards','MadWeight_card.dat')
4535 self.paths['MadWeight_default'] =pjoin(self.me_dir,'Cards','MadWeight_card_default.dat')
4536 self.paths['ML'] =pjoin(self.me_dir,'Cards','MadLoopParams.dat')
4537 self.paths['shower'] = pjoin(self.me_dir,'Cards','shower_card.dat')
4538 self.paths['shower_default'] = pjoin(self.me_dir,'Cards','shower_card_default.dat')
4539 self.paths['FO_analyse'] = pjoin(self.me_dir,'Cards','FO_analyse_card.dat')
4540 self.paths['FO_analyse_default'] = pjoin(self.me_dir,'Cards','FO_analyse_card_default.dat')
4541 self.paths['pythia'] =pjoin(self.me_dir, 'Cards','pythia_card.dat')
4542 self.paths['pythia8'] = pjoin(self.me_dir, 'Cards','pythia8_card.dat')
4543 self.paths['pythia8_default'] = pjoin(self.me_dir, 'Cards','pythia8_card_default.dat')
4544 self.paths['madspin_default'] = pjoin(self.me_dir,'Cards/madspin_card_default.dat')
4545 self.paths['madspin'] = pjoin(self.me_dir,'Cards/madspin_card.dat')
4546 self.paths['reweight'] = pjoin(self.me_dir,'Cards','reweight_card.dat')
4547 self.paths['delphes'] = pjoin(self.me_dir,'Cards','delphes_card.dat')
4548 self.paths['plot'] = pjoin(self.me_dir,'Cards','plot_card.dat')
4549 self.paths['plot_default'] = pjoin(self.me_dir,'Cards','plot_card_default.dat')
4550 self.paths['madanalysis5_parton'] = pjoin(self.me_dir,'Cards','madanalysis5_parton_card.dat')
4551 self.paths['madanalysis5_hadron'] = pjoin(self.me_dir,'Cards','madanalysis5_hadron_card.dat')
4552 self.paths['madanalysis5_parton_default'] = pjoin(self.me_dir,'Cards','madanalysis5_parton_card_default.dat')
4553 self.paths['madanalysis5_hadron_default'] = pjoin(self.me_dir,'Cards','madanalysis5_hadron_card_default.dat')
4554 self.paths['FO_analyse'] = pjoin(self.me_dir,'Cards', 'FO_analyse_card.dat')
4555
4556
4557
4558
4559 - def __init__(self, question, cards=[], from_banner=None, banner=None, mode='auto', *args, **opt):
4560
4561
4562 self.load_default()
4563 self.define_paths(**opt)
4564 self.last_editline_pos = 0
4565
4566 if 'allow_arg' not in opt or not opt['allow_arg']:
4567
4568 opt['allow_arg'] = list(range(self.integer_bias, self.integer_bias+len(cards)))
4569
4570 self.param_consistency = True
4571 if 'param_consistency' in opt:
4572 self.param_consistency = opt['param_consistency']
4573
4574 cmd.OneLinePathCompletion.__init__(self, question, *args, **opt)
4575
4576 self.conflict = set()
4577 self.mode = mode
4578 self.cards = cards
4579 self.all_vars = set()
4580 self.modified_card = set()
4581
4582 self.init_from_banner(from_banner, banner)
4583 self.writting_card = True
4584 if 'write_file' in opt:
4585 if not opt['write_file']:
4586 self.writting_card = False
4587 self.param_consistency = False
4588
4589
4590 for card in cards:
4591 if os.path.exists(card) and os.path.sep in cards:
4592 card_name = CommonRunCmd.detect_card_type(card)
4593 card_name = card_name.split('_',1)[0]
4594 self.paths[card_name] = card
4595
4596
4597 for name in self.to_init_card:
4598 new_vars = set(getattr(self, 'init_%s' % name)(cards))
4599 new_conflict = self.all_vars.intersection(new_vars)
4600 self.conflict.union(new_conflict)
4601 self.all_vars.union(new_vars)
4602
4603
4605 """ defined card that need to be initialized from the banner file
4606 from_banner should be a list of card to load from the banner object
4607 """
4608
4609 if from_banner is None:
4610 self.from_banner = {}
4611 return
4612
4613 self.from_banner = {}
4614 try:
4615 for card in from_banner:
4616 self.from_banner[card] = banner.charge_card(card)
4617 except KeyError:
4618 if from_banner == ['param', 'run'] and list(banner.keys()) == ['mgversion']:
4619 if self.mother_interface:
4620 results = self.mother_interface.results
4621 run_name = self.mother_interface.run_name
4622 run_tag = self.mother_interface.run_tag
4623 banner = banner_mod.recover_banner(results, 'parton', run_name, run_tag)
4624 self.mother_interface.banner = banner
4625 return self.init_from_banner(from_banner, banner)
4626 else:
4627 raise
4628
4629 return self.from_banner
4630
4631
4633 """initialise the path if requested"""
4634
4635 defname = '%s_default' % name
4636
4637 if name in self.from_banner:
4638 return self.from_banner[name]
4639
4640 if isinstance(cards, list):
4641 if name in cards:
4642 return True
4643 elif '%s_card.dat' % name in cards:
4644 return True
4645 elif name in self.paths and self.paths[name] in cards:
4646 return True
4647 else:
4648 cardnames = [os.path.basename(p) for p in cards]
4649 if '%s_card.dat' % name in cardnames:
4650 return True
4651 else:
4652 return False
4653
4654 elif isinstance(cards, dict) and name in cards:
4655 self.paths[name]= cards[name]
4656 if defname in cards:
4657 self.paths[defname] = cards[defname]
4658 elif os.path.isfile(cards[name].replace('.dat', '_default.dat')):
4659 self.paths[defname] = cards[name].replace('.dat', '_default.dat')
4660 else:
4661 self.paths[defname] = self.paths[name]
4662
4663 return True
4664 else:
4665 return False
4666
4668 """check if we need to load the param_card"""
4669
4670 self.pname2block = {}
4671 self.restricted_value = {}
4672 self.param_card = {}
4673
4674 is_valid_path = self.get_path('param', cards)
4675 if not is_valid_path:
4676 self.param_consistency = False
4677 return []
4678 if isinstance(is_valid_path, param_card_mod.ParamCard):
4679 self.param_card = is_valid_path
4680 self.param_consistency = False
4681 return []
4682
4683 try:
4684 self.param_card = param_card_mod.ParamCard(self.paths['param'])
4685 except (param_card_mod.InvalidParamCard, ValueError) as e:
4686 logger.error('Current param_card is not valid. We are going to use the default one.')
4687 logger.error('problem detected: %s' % e)
4688 files.cp(self.paths['param_default'], self.paths['param'])
4689 self.param_card = param_card_mod.ParamCard(self.paths['param'])
4690
4691
4692
4693
4694 if os.path.exists(self.paths['param_default']):
4695 default_param = param_card_mod.ParamCard(self.paths['param_default'])
4696 else:
4697 default_param = param_card_mod.ParamCard(self.param_card)
4698 self.pname2block, self.restricted_value = default_param.analyze_param_card()
4699 self.param_card_default = default_param
4700 return list(self.pname2block.keys())
4701
4703
4704 self.run_set = []
4705 is_valid_path = self.get_path('run', cards)
4706 if not is_valid_path:
4707 return []
4708 if isinstance(is_valid_path, banner_mod.RunCard):
4709 self.run_card = is_valid_path
4710 return []
4711
4712
4713 try:
4714 self.run_card = banner_mod.RunCard(self.paths['run'], consistency='warning')
4715 except IOError:
4716 self.run_card = {}
4717 try:
4718 run_card_def = banner_mod.RunCard(self.paths['run_default'])
4719 except IOError:
4720 run_card_def = {}
4721
4722
4723 if run_card_def:
4724 if self.run_card:
4725 self.run_set = list(run_card_def.keys()) + self.run_card.hidden_param
4726 else:
4727 self.run_set = list(run_card_def.keys()) + run_card_def.hidden_param
4728 elif self.run_card:
4729 self.run_set = list(self.run_card.keys())
4730 else:
4731 self.run_set = []
4732
4733 if self.run_set:
4734 self.special_shortcut.update(
4735 {'ebeam':([float],['run_card ebeam1 %(0)s', 'run_card ebeam2 %(0)s']),
4736 'lpp': ([int],['run_card lpp1 %(0)s', 'run_card lpp2 %(0)s' ]),
4737 'lhc': ([int],['run_card lpp1 1', 'run_card lpp2 1', 'run_card ebeam1 %(0)s*1000/2', 'run_card ebeam2 %(0)s*1000/2']),
4738 'lep': ([int],['run_card lpp1 0', 'run_card lpp2 0', 'run_card ebeam1 %(0)s/2', 'run_card ebeam2 %(0)s/2']),
4739 'ilc': ([int],['run_card lpp1 0', 'run_card lpp2 0', 'run_card ebeam1 %(0)s/2', 'run_card ebeam2 %(0)s/2']),
4740 'lcc': ([int],['run_card lpp1 1', 'run_card lpp2 1', 'run_card ebeam1 %(0)s*1000/2', 'run_card ebeam2 %(0)s*1000/2']),
4741 'fixed_scale': ([float],['run_card fixed_fac_scale T', 'run_card fixed_ren_scale T', 'run_card scale %(0)s', 'run_card dsqrt_q2fact1 %(0)s' ,'run_card dsqrt_q2fact2 %(0)s']),
4742 'no_parton_cut':([],['run_card nocut T']),
4743 'cm_velocity':([float], [lambda self :self.set_CM_velocity]),
4744 'pbp':([],['run_card lpp1 1', 'run_card lpp2 1','run_card nb_proton1 82', 'run_card nb_neutron1 126', 'run_card mass_ion1 195.0820996698','run_card nb_proton2 1', 'run_card nb_neutron2 0', 'run_card mass_ion1 -1']),
4745 'pbpb':([],['run_card lpp1 1', 'run_card lpp2 1','run_card nb_proton1 82', 'run_card nb_neutron1 126', 'run_card mass_ion1 195.0820996698', 'run_card nb_proton2 82', 'run_card nb_neutron2 126', 'run_card mass_ion2 195.0820996698' ]),
4746 'pp': ([],['run_card lpp1 1', 'run_card lpp2 1','run_card nb_proton1 1', 'run_card nb_neutron1 0', 'run_card mass_ion1 -1', 'run_card nb_proton2 1', 'run_card nb_neutron2 0', 'run_card mass_ion2 -1']),
4747 })
4748
4749 self.special_shortcut_help.update({
4750 'ebeam' : 'syntax: set ebeam VALUE:\n This parameter sets the energy to both beam to the value in GeV',
4751 'lpp' : 'syntax: set ebeam VALUE:\n'+\
4752 ' Set the type of beam to a given value for both beam\n'+\
4753 ' 0 : means no PDF\n'+\
4754 ' 1 : means proton PDF\n'+\
4755 ' -1 : means antiproton PDF\n'+\
4756 ' 2 : means PDF for elastic photon emited from a proton\n'+\
4757 ' 3 : means PDF for elastic photon emited from an electron',
4758 'lhc' : 'syntax: set lhc VALUE:\n Set for a proton-proton collision with that given center of mass energy (in TeV)',
4759 'lep' : 'syntax: set lep VALUE:\n Set for a electron-positron collision with that given center of mass energy (in GeV)',
4760 'fixed_scale' : 'syntax: set fixed_scale VALUE:\n Set all scales to the give value (in GeV)',
4761 'no_parton_cut': 'remove all cut (but BW_cutoff)',
4762 'cm_velocity': 'set sqrts to have the above velocity for the incoming particles',
4763 'pbpb': 'setup heavy ion configuration for lead-lead collision',
4764 'pbp': 'setup heavy ion configuration for lead-proton collision',
4765 'pp': 'remove setup of heavy ion configuration to set proton-proton collision',
4766 })
4767
4768 self.update_block += [b.name for b in self.run_card.blocks]
4769
4770 return self.run_set
4771
4773
4774 self.has_mw = False
4775 if not self.get_path('madweight', cards):
4776 return []
4777
4778
4779 self.do_change_tf = self.mother_interface.do_define_transfer_fct
4780 self.complete_change_tf = self.mother_interface.complete_define_transfer_fct
4781 self.help_change_tf = self.mother_interface.help_define_transfer_fct
4782 if not os.path.exists(self.paths['transfer']):
4783 logger.warning('No transfer function currently define. Please use the change_tf command to define one.')
4784
4785 self.has_mw = True
4786 try:
4787 import madgraph.madweight.Cards as mwcards
4788 except:
4789 import internal.madweight.Cards as mwcards
4790 self.mw_card = mwcards.Card(self.paths['MadWeight'])
4791 self.mw_card = self.mw_card.info
4792 self.mw_vars = []
4793 for key in self.mw_card:
4794 if key == 'comment':
4795 continue
4796 for key2 in self.mw_card.info[key]:
4797 if isinstance(key2, str) and not key2.isdigit():
4798 self.mw_vars.append(key2)
4799 return self.mw_vars
4800
4802
4803 if isinstance(cards, dict):
4804 for key in ['ML', 'madloop','MadLoop']:
4805 if key in cards:
4806 self.paths['ML'] = cards[key]
4807
4808 self.has_ml = False
4809 if os.path.isfile(self.paths['ML']):
4810 self.has_ml = True
4811 self.MLcard = banner_mod.MadLoopParam(self.paths['ML'])
4812 self.MLcardDefault = banner_mod.MadLoopParam()
4813 self.ml_vars = [k.lower() for k in self.MLcard.keys()]
4814 return self.ml_vars
4815 return []
4816
4818
4819 self.has_shower = False
4820 if not self.get_path('shower', cards):
4821 return []
4822 self.has_shower = True
4823 self.shower_card = shower_card_mod.ShowerCard(self.paths['shower'])
4824 self.shower_vars = list(self.shower_card.keys())
4825 return self.shower_vars
4826
4828
4829 self.has_PY8 = False
4830 if not self.get_path('pythia8', cards):
4831 return []
4832
4833 self.has_PY8 = True
4834 self.PY8Card = self.PY8Card_class(self.paths['pythia8'])
4835 self.PY8CardDefault = self.PY8Card_class()
4836
4837 self.py8_vars = [k.lower() for k in self.PY8Card.keys()]
4838
4839 self.special_shortcut.update({
4840 'simplepy8':([],['pythia8_card hadronlevel:all False',
4841 'pythia8_card partonlevel:mpi False',
4842 'pythia8_card BeamRemnants:primordialKT False',
4843 'pythia8_card PartonLevel:Remnants False',
4844 'pythia8_card Check:event False',
4845 'pythia8_card TimeShower:QEDshowerByQ False',
4846 'pythia8_card TimeShower:QEDshowerByL False',
4847 'pythia8_card SpaceShower:QEDshowerByQ False',
4848 'pythia8_card SpaceShower:QEDshowerByL False',
4849 'pythia8_card PartonLevel:FSRinResonances False',
4850 'pythia8_card ProcessLevel:resonanceDecays False',
4851 ]),
4852 'mpi':([bool],['pythia8_card partonlevel:mpi %(0)s']),
4853 })
4854 self.special_shortcut_help.update({
4855 'simplepy8' : 'Turn off non-perturbative slow features of Pythia8.',
4856 'mpi' : 'syntax: set mpi value: allow to turn mpi in Pythia8 on/off',
4857 })
4858 return []
4859
4861
4862 if not self.get_path('madspin', cards):
4863 return []
4864
4865 self.special_shortcut.update({
4866 'spinmode':([str], ['add madspin_card --before_line="launch" set spinmode %(0)s']),
4867 'nodecay':([], ['edit madspin_card --comment_line="decay"'])
4868 })
4869 self.special_shortcut_help.update({
4870 'spinmode' : 'full|none|onshell. Choose the mode of madspin.\n - full: spin-correlation and off-shell effect\n - onshell: only spin-correlation,]\n - none: no spin-correlation and not offshell effects.',
4871 'nodecay': 'remove all decay previously defined in madspin',
4872 })
4873 return []
4874
4876
4877 self.has_delphes = False
4878 if not self.get_path('pythia8', cards):
4879 return []
4880 self.has_delphes = True
4881 return []
4882
4883
4885 """compute sqrts from the velocity in the center of mass frame"""
4886
4887 v = banner_mod.ConfigFile.format_variable(line, float, 'velocity')
4888
4889 self.mother_interface.get_characteristics()
4890 proc_info = self.mother_interface.proc_characteristics
4891 if 'pdg_initial1' not in proc_info:
4892 logger.warning('command not supported')
4893
4894 if len(proc_info['pdg_initial1']) == 1 == len(proc_info['pdg_initial2']) and\
4895 abs(proc_info['pdg_initial1'][0]) == abs(proc_info['pdg_initial2'][0]):
4896
4897 m = self.param_card.get_value('mass', abs(proc_info['pdg_initial1'][0]))
4898 sqrts = 2*m/ math.sqrt(1-v**2)
4899 self.do_set('run_card ebeam1 %s' % (sqrts/2.0))
4900 self.do_set('run_card ebeam2 %s' % (sqrts/2.0))
4901 self.do_set('run_card lpp 0')
4902 else:
4903 logger.warning('This is only possible for a single particle in the initial state')
4904
4905
4906
4907 - def do_help(self, line, conflict_raise=False, banner=True):
4908
4909
4910
4911 if banner:
4912 logger.info('*** HELP MESSAGE ***', '$MG:BOLD')
4913
4914 args = self.split_arg(line)
4915
4916 if len(args)==0 or (len(args) == 1 and hasattr(self, 'do_%s' % args[0])):
4917 out = cmd.BasicCmd.do_help(self, line)
4918 if len(args)==0:
4919 print('Allowed Argument')
4920 print('================')
4921 print('\t'.join(self.allow_arg))
4922 print()
4923 print('Special shortcut: (type help <name>)')
4924 print('====================================')
4925 print(' syntax: set <name> <value>')
4926 print('\t'.join(self.special_shortcut))
4927 print()
4928 if banner:
4929 logger.info('*** END HELP ***', '$MG:BOLD')
4930 return out
4931
4932
4933 if args[0] in self.special_shortcut:
4934 if args[0] in self.special_shortcut_help:
4935 print(self.special_shortcut_help[args[0]])
4936 if banner:
4937 logger.info('*** END HELP ***', '$MG:BOLD')
4938 return
4939
4940 start = 0
4941 card = ''
4942 if args[0]+'_card' in self.all_card_name+ self.cards:
4943 args[0] += '_card'
4944 elif args[0]+'.dat' in self.all_card_name+ self.cards:
4945 args[0] += '.dat'
4946 elif args[0]+'_card.dat' in self.all_card_name+ self.cards:
4947 args[0] += '_card.dat'
4948 if args[0] in self.all_card_name + self.cards:
4949 start += 1
4950 card = args[0]
4951 if len(args) == 1:
4952 if args[0] == 'pythia8_card':
4953 args[0] = 'PY8Card'
4954 if args[0] == 'param_card':
4955 logger.info("Param_card information: ", '$MG:color:BLUE')
4956 print("File to define the various model parameter")
4957 logger.info("List of the Block defined:",'$MG:color:BLUE')
4958 print("\t".join(list(self.param_card.keys())))
4959 elif args[0].startswith('madanalysis5'):
4960 print('This card allow to make plot with the madanalysis5 package')
4961 print('An example card is provided. For more information about the ')
4962 print('syntax please refer to: https://madanalysis.irmp.ucl.ac.be/')
4963 print('or to the user manual [arXiv:1206.1599]')
4964 if args[0].startswith('madanalysis5_hadron'):
4965 print()
4966 print('This card also allow to make recasting analysis')
4967 print('For more detail, see: arXiv:1407.3278')
4968 elif hasattr(self, args[0]):
4969 logger.info("%s information: " % args[0], '$MG:color:BLUE')
4970 print((eval('self.%s' % args[0]).__doc__))
4971 logger.info("List of parameter associated", '$MG:color:BLUE')
4972 print("\t".join(list(eval('self.%s' % args[0]).keys())))
4973 if banner:
4974 logger.info('*** END HELP ***', '$MG:BOLD')
4975 return card
4976
4977
4978 if args[start] in [l.lower() for l in self.run_card.keys()] and card in ['', 'run_card']:
4979 if args[start] not in self.run_set:
4980 args[start] = [l for l in self.run_set if l.lower() == args[start]][0]
4981
4982 if args[start] in self.conflict and not conflict_raise:
4983 conflict_raise = True
4984 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
4985 if card == '':
4986 logger.info('** If not explicitely speficy this parameter will modif the run_card file', '$MG:BOLD')
4987
4988 self.run_card.do_help(args[start])
4989
4990 elif (args[start] in self.param_card or args[start] == 'width') \
4991 and card in ['','param_card']:
4992 if args[start] in self.conflict and not conflict_raise:
4993 conflict_raise = True
4994 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
4995 if card == '':
4996 logger.info('** If not explicitely speficy this parameter will modif the param_card file', '$MG:BOLD')
4997
4998 if args[start] == 'width':
4999 args[start] = 'decay'
5000
5001 if len(args) == start+1:
5002 self.param_card.do_help(args[start], tuple())
5003 key = None
5004 elif args[start+1] in self.pname2block:
5005 all_var = self.pname2block[args[start+1]]
5006 key = None
5007 for bname, lhaid in all_var:
5008 if bname == args[start]:
5009 key = lhaid
5010 break
5011 else:
5012 logger.warning('%s is not part of block "%s" but "%s". please correct.' %
5013 (args[start+1], args[start], bname))
5014 else:
5015 try:
5016 key = tuple([int(i) for i in args[start+1:]])
5017 except ValueError:
5018 logger.warning('Failed to identify LHA information')
5019 return card
5020
5021 if key in self.param_card[args[start]].param_dict:
5022 self.param_card.do_help(args[start], key, default=self.param_card_default)
5023 elif key:
5024 logger.warning('invalid information: %s not defined in the param_card' % (key,))
5025
5026 elif args[start] in self.pname2block and card in ['','param_card']:
5027 if args[start] in self.conflict and not conflict_raise:
5028 conflict_raise = True
5029 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
5030 if card == '':
5031 logger.info('** If not explicitely speficy this parameter will modif the param_card file', '$MG:BOLD')
5032
5033 all_var = self.pname2block[args[start]]
5034 for bname, lhaid in all_var:
5035 new_line = 'param_card %s %s %s' % (bname,
5036 ' '.join([ str(i) for i in lhaid]), ' '.join(args[start+1:]))
5037 self.do_help(new_line, conflict_raise=True, banner=False)
5038
5039
5040 elif self.has_ml and args[start] in self.ml_vars \
5041 and card in ['', 'MadLoop_card']:
5042
5043 if args[start] in self.conflict and not conflict_raise:
5044 conflict_raise = True
5045 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
5046 if card == '':
5047 logger.info('** If not explicitely speficy this parameter will modif the madloop_card file', '$MG:BOLD')
5048
5049 self.MLcard.do_help(args[start])
5050
5051
5052 elif self.has_PY8 and args[start] in self.PY8Card:
5053 if args[start] in self.conflict and not conflict_raise:
5054 conflict_raise = True
5055 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
5056 if card == '':
5057 logger.info('** If not explicitely speficy this parameter will modif the pythia8_card file', '$MG:BOLD')
5058
5059 self.PY8Card.do_help(args[start])
5060 elif card.startswith('madanalysis5'):
5061 print('MA5')
5062
5063
5064 elif banner:
5065 print("no help available")
5066
5067 if banner:
5068 logger.info('*** END HELP ***', '$MG:BOLD')
5069
5070 return card
5071
5072
5073
5074
5075
5076
5078 prev_timer = signal.alarm(0)
5079 if prev_timer:
5080 nb_back = len(line)
5081 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
5082 self.stdout.write(line)
5083 self.stdout.flush()
5084
5085 possibilities = self.complete_set(text, line, begidx, endidx,formatting=False)
5086 if line[:begidx].strip() == 'help':
5087 possibilities['Defined command'] = cmd.BasicCmd.completenames(self, text, line)
5088 possibilities.update(self.complete_add(text, line, begidx, endidx,formatting=False))
5089 return self.deal_multiple_categories(possibilities)
5090
5091
5092
5093
5094
5096 prev_timer = signal.alarm(0)
5097 if prev_timer:
5098 nb_back = len(line)
5099 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
5100 self.stdout.write(line)
5101 self.stdout.flush()
5102
5103 valid = ['dependent', 'missing', 'to_slha1', 'to_slha2', 'to_full']
5104 valid += self.update_block
5105
5106 arg = line[:begidx].split()
5107 if len(arg) <=1:
5108 return self.list_completion(text, valid, line)
5109 elif arg[0] == 'to_full':
5110 return self.list_completion(text, self.cards , line)
5111
5112 - def complete_set(self, text, line, begidx, endidx, formatting=True):
5113 """ Complete the set command"""
5114
5115 prev_timer = signal.alarm(0)
5116 if prev_timer:
5117 nb_back = len(line)
5118 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
5119 self.stdout.write(line)
5120 self.stdout.flush()
5121
5122 possibilities = {}
5123 allowed = {}
5124 args = self.split_arg(line[0:begidx])
5125 if args[-1] in ['Auto', 'default']:
5126 return
5127
5128 if len(args) == 1:
5129 allowed = {'category':'', 'run_card':'', 'block':'all', 'param_card':'','shortcut':''}
5130 if self.has_mw:
5131 allowed['madweight_card'] = ''
5132 allowed['mw_block'] = 'all'
5133 if self.has_shower:
5134 allowed['shower_card'] = ''
5135 if self.has_ml:
5136 allowed['madloop_card'] = ''
5137 if self.has_PY8:
5138 allowed['pythia8_card'] = ''
5139 if self.has_delphes:
5140 allowed['delphes_card'] = ''
5141
5142 elif len(args) == 2:
5143 if args[1] == 'run_card':
5144 allowed = {'run_card':'default'}
5145 elif args[1] == 'param_card':
5146 allowed = {'block':'all', 'param_card':'default'}
5147 elif self.param_card and args[1] in list(self.param_card.keys()):
5148 allowed = {'block':args[1]}
5149 elif args[1] == 'width':
5150 allowed = {'block': 'decay'}
5151 elif args[1] == 'MadWeight_card':
5152 allowed = {'madweight_card':'default', 'mw_block': 'all'}
5153 elif args[1] == 'MadLoop_card':
5154 allowed = {'madloop_card':'default'}
5155 elif args[1] == 'pythia8_card':
5156 allowed = {'pythia8_card':'default'}
5157 elif self.has_mw and args[1] in list(self.mw_card.keys()):
5158 allowed = {'mw_block':args[1]}
5159 elif args[1] == 'shower_card':
5160 allowed = {'shower_card':'default'}
5161 elif args[1] == 'delphes_card':
5162 allowed = {'delphes_card':'default'}
5163 else:
5164 allowed = {'value':''}
5165
5166 else:
5167 start = 1
5168 if args[1] in ['run_card', 'param_card', 'MadWeight_card', 'shower_card',
5169 'MadLoop_card','pythia8_card','delphes_card','plot_card',
5170 'madanalysis5_parton_card','madanalysis5_hadron_card']:
5171 start = 2
5172
5173 if args[-1] in list(self.pname2block.keys()):
5174 allowed['value'] = 'default'
5175 elif args[start] in list(self.param_card.keys()) or args[start] == 'width':
5176 if args[start] == 'width':
5177 args[start] = 'decay'
5178
5179 if args[start+1:]:
5180 allowed = {'block':(args[start], args[start+1:])}
5181 else:
5182 allowed = {'block':args[start]}
5183 elif self.has_mw and args[start] in list(self.mw_card.keys()):
5184 if args[start+1:]:
5185 allowed = {'mw_block':(args[start], args[start+1:])}
5186 else:
5187 allowed = {'mw_block':args[start]}
5188
5189
5190 else:
5191 allowed['value'] = ''
5192
5193 if 'category' in list(allowed.keys()):
5194 categories = ['run_card', 'param_card']
5195 if self.has_mw:
5196 categories.append('MadWeight_card')
5197 if self.has_shower:
5198 categories.append('shower_card')
5199 if self.has_ml:
5200 categories.append('MadLoop_card')
5201 if self.has_PY8:
5202 categories.append('pythia8_card')
5203 if self.has_delphes:
5204 categories.append('delphes_card')
5205
5206 possibilities['category of parameter (optional)'] = \
5207 self.list_completion(text, categories)
5208
5209 if 'shortcut' in list(allowed.keys()):
5210 possibilities['special values'] = self.list_completion(text, list(self.special_shortcut.keys())+['qcut', 'showerkt'])
5211
5212 if 'run_card' in list(allowed.keys()):
5213 opts = self.run_set
5214 if allowed['run_card'] == 'default':
5215 opts.append('default')
5216
5217
5218 possibilities['Run Card'] = self.list_completion(text, opts)
5219
5220 if 'param_card' in list(allowed.keys()):
5221 opts = list(self.pname2block.keys())
5222 if allowed['param_card'] == 'default':
5223 opts.append('default')
5224 possibilities['Param Card'] = self.list_completion(text, opts)
5225
5226 if 'madweight_card' in list(allowed.keys()):
5227 opts = self.mw_vars + [k for k in self.mw_card.keys() if k !='comment']
5228 if allowed['madweight_card'] == 'default':
5229 opts.append('default')
5230 possibilities['MadWeight Card'] = self.list_completion(text, opts)
5231
5232 if 'madloop_card' in list(allowed.keys()):
5233 opts = self.ml_vars
5234 if allowed['madloop_card'] == 'default':
5235 opts.append('default')
5236 possibilities['MadLoop Parameter'] = self.list_completion(text, opts)
5237
5238 if 'pythia8_card' in list(allowed.keys()):
5239 opts = self.py8_vars
5240 if allowed['pythia8_card'] == 'default':
5241 opts.append('default')
5242 possibilities['Pythia8 Parameter'] = self.list_completion(text, opts)
5243
5244 if 'shower_card' in list(allowed.keys()):
5245 opts = self.shower_vars + [k for k in self.shower_card.keys() if k !='comment']
5246 if allowed['shower_card'] == 'default':
5247 opts.append('default')
5248 possibilities['Shower Card'] = self.list_completion(text, opts)
5249
5250 if 'delphes_card' in allowed:
5251 if allowed['delphes_card'] == 'default':
5252 opts = ['default', 'atlas', 'cms']
5253 possibilities['Delphes Card'] = self.list_completion(text, opts)
5254
5255 if 'value' in list(allowed.keys()):
5256 opts = ['default']
5257 if 'decay' in args:
5258 opts.append('Auto')
5259 opts.append('Auto@NLO')
5260 elif args[-1] in self.pname2block and self.pname2block[args[-1]][0][0] == 'decay':
5261 opts.append('Auto')
5262 opts.append('Auto@NLO')
5263 if args[-1] in self.run_set:
5264 allowed_for_run = []
5265 if args[-1].lower() in self.run_card.allowed_value:
5266 allowed_for_run = self.run_card.allowed_value[args[-1].lower()]
5267 if '*' in allowed_for_run:
5268 allowed_for_run.remove('*')
5269 elif isinstance(self.run_card[args[-1]], bool):
5270 allowed_for_run = ['True', 'False']
5271 opts += [str(i) for i in allowed_for_run]
5272
5273
5274 possibilities['Special Value'] = self.list_completion(text, opts)
5275
5276 if 'block' in list(allowed.keys()) and self.param_card:
5277 if allowed['block'] == 'all' and self.param_card:
5278 allowed_block = [i for i in self.param_card.keys() if 'qnumbers' not in i]
5279 allowed_block.append('width')
5280 possibilities['Param Card Block' ] = \
5281 self.list_completion(text, allowed_block)
5282
5283 elif isinstance(allowed['block'], six.string_types):
5284 block = self.param_card[allowed['block']].param_dict
5285 ids = [str(i[0]) for i in block
5286 if (allowed['block'], i) not in self.restricted_value]
5287 possibilities['Param Card id' ] = self.list_completion(text, ids)
5288 varname = [name for name, all_var in self.pname2block.items()
5289 if any((bname == allowed['block']
5290 for bname,lhaid in all_var))]
5291 possibilities['Param card variable'] = self.list_completion(text,
5292 varname)
5293 else:
5294 block = self.param_card[allowed['block'][0]].param_dict
5295 nb = len(allowed['block'][1])
5296 ids = [str(i[nb]) for i in block if len(i) > nb and \
5297 [str(a) for a in i[:nb]] == allowed['block'][1]]
5298
5299 if not ids:
5300 if tuple([int(i) for i in allowed['block'][1]]) in block:
5301 opts = ['default']
5302 if allowed['block'][0] == 'decay':
5303 opts.append('Auto')
5304 opts.append('Auto@NLO')
5305 possibilities['Special value'] = self.list_completion(text, opts)
5306 possibilities['Param Card id' ] = self.list_completion(text, ids)
5307
5308 if 'mw_block' in list(allowed.keys()):
5309 if allowed['mw_block'] == 'all':
5310 allowed_block = [i for i in self.mw_card.keys() if 'comment' not in i]
5311 possibilities['MadWeight Block' ] = \
5312 self.list_completion(text, allowed_block)
5313 elif isinstance(allowed['mw_block'], six.string_types):
5314 block = self.mw_card[allowed['mw_block']]
5315 ids = [str(i[0]) if isinstance(i, tuple) else str(i) for i in block]
5316 possibilities['MadWeight Card id' ] = self.list_completion(text, ids)
5317 else:
5318 block = self.mw_card[allowed['mw_block'][0]]
5319 nb = len(allowed['mw_block'][1])
5320 ids = [str(i[nb]) for i in block if isinstance(i, tuple) and\
5321 len(i) > nb and \
5322 [str(a) for a in i[:nb]] == allowed['mw_block'][1]]
5323
5324 if not ids:
5325 if tuple([i for i in allowed['mw_block'][1]]) in block or \
5326 allowed['mw_block'][1][0] in list(block.keys()):
5327 opts = ['default']
5328 possibilities['Special value'] = self.list_completion(text, opts)
5329 possibilities['MadWeight Card id' ] = self.list_completion(text, ids)
5330
5331 return self.deal_multiple_categories(possibilities, formatting)
5332
5334 """ edit the value of one parameter in the card"""
5335
5336
5337 args = self.split_arg(line)
5338
5339
5340 if len(args) == 0:
5341 logger.warning("No argument. For help type 'help set'.")
5342
5343 if len(args)==1 and '=' in args[-1]:
5344 arg1, arg2 = args.pop(-1).split('=',1)
5345 args += [arg1, arg2]
5346 if '=' in args:
5347 args.remove('=')
5348
5349 args[:-1] = [ a.lower() for a in args[:-1]]
5350 if len(args) == 1:
5351 args = [args[0].lower()]
5352
5353 if args[0] in self.special_shortcut:
5354 targettypes , cmd = self.special_shortcut[args[0]]
5355 if len(args) != len(targettypes) +1:
5356 logger.warning('shortcut %s requires %s argument' % (args[0], len(targettypes)))
5357 if len(args) < len(targettypes) +1:
5358 return
5359 else:
5360 logger.warning('additional argument will be ignored')
5361 values ={}
5362 for i, argtype in enumerate(targettypes):
5363 try:
5364 values = {str(i): banner_mod.ConfigFile.format_variable(args[i+1], argtype, args[0])}
5365 except ValueError as e:
5366 logger.warning("Wrong argument: The entry #%s should be of type %s.", i+1, argtype)
5367 return
5368 except InvalidCmd as e:
5369 logger.warning(str(e))
5370 return
5371
5372
5373
5374 for arg in cmd:
5375 if isinstance(arg, str):
5376 try:
5377 text = arg % values
5378 except KeyError:
5379 logger.warning("This command requires one argument")
5380 return
5381 except Exception as e:
5382 logger.warning(str(e))
5383 return
5384 else:
5385 split = text.split()
5386 if hasattr(self, 'do_%s' % split[0]):
5387 getattr(self, 'do_%s' % split[0])(' '.join(split[1:]))
5388 else:
5389 self.do_set(text)
5390
5391 else:
5392 val = [values[str(i)] for i in range(len(values))]
5393 try:
5394 arg(self)(*val)
5395 except Exception as e:
5396 logger.warning(str(e))
5397 return
5398
5399 start = 0
5400 if len(args) < 2:
5401 logger.warning('Invalid set command %s (need two arguments)' % line)
5402 return
5403
5404
5405 if args[0].lower() == 'qcut':
5406 pythia_path = self.paths['pythia']
5407 if os.path.exists(pythia_path):
5408 logger.info('add line QCUT = %s in pythia_card.dat' % args[1])
5409 p_card = open(pythia_path,'r').read()
5410 p_card, n = re.subn('''^\s*QCUT\s*=\s*[\de\+\-\.]*\s*$''',
5411 ''' QCUT = %s ''' % args[1], \
5412 p_card, flags=(re.M+re.I))
5413 if n==0:
5414 p_card = '%s \n QCUT= %s' % (p_card, args[1])
5415 with open(pythia_path, 'w') as fsock:
5416 fsock.write(p_card)
5417 return
5418
5419 if args[0].lower() == 'showerkt':
5420 pythia_path = self.paths['pythia']
5421 if os.path.exists(pythia_path):
5422 logger.info('add line SHOWERKT = %s in pythia_card.dat' % args[1].upper())
5423 p_card = open(pythia_path,'r').read()
5424 p_card, n = re.subn('''^\s*SHOWERKT\s*=\s*[default\de\+\-\.]*\s*$''',
5425 ''' SHOWERKT = %s ''' % args[1].upper(), \
5426 p_card, flags=(re.M+re.I))
5427 if n==0:
5428 p_card = '%s \n SHOWERKT= %s' % (p_card, args[1].upper())
5429 with open(pythia_path, 'w') as fsock:
5430 fsock.write(p_card)
5431 return
5432
5433 card = ''
5434 if args[0] == 'madweight_card':
5435 if not self.mw_card:
5436 logger.warning('Invalid Command: No MadWeight card defined.')
5437 return
5438 args[0] = 'MadWeight_card'
5439
5440 if args[0] == 'shower_card':
5441 if not self.shower_card:
5442 logger.warning('Invalid Command: No Shower card defined.')
5443 return
5444 args[0] = 'shower_card'
5445
5446 if args[0] == "madloop_card":
5447 if not self.has_ml:
5448 logger.warning('Invalid Command: No MadLoopParam card defined.')
5449 return
5450 args[0] = 'MadLoop_card'
5451
5452 if args[0] == "pythia8_card":
5453 if not self.has_PY8:
5454 logger.warning('Invalid Command: No Pythia8 card defined.')
5455 return
5456 args[0] = 'pythia8_card'
5457
5458 if args[0] == 'delphes_card':
5459 if not self.has_delphes:
5460 logger.warning('Invalid Command: No Delphes card defined.')
5461 return
5462 if args[1] == 'atlas':
5463 logger.info("set default ATLAS configuration for Delphes", '$MG:BOLD')
5464 files.cp(pjoin(self.me_dir,'Cards', 'delphes_card_ATLAS.dat'),
5465 pjoin(self.me_dir,'Cards', 'delphes_card.dat'))
5466 return
5467 elif args[1] == 'cms':
5468 logger.info("set default CMS configuration for Delphes",'$MG:BOLD')
5469 files.cp(pjoin(self.me_dir,'Cards', 'delphes_card_CMS.dat'),
5470 pjoin(self.me_dir,'Cards', 'delphes_card.dat'))
5471 return
5472
5473 if args[0] in ['run_card', 'param_card', 'MadWeight_card', 'shower_card',
5474 'delphes_card','madanalysis5_hadron_card','madanalysis5_parton_card']:
5475
5476 if args[1] == 'default':
5477 logger.info('replace %s by the default card' % args[0],'$MG:BOLD')
5478 files.cp(self.paths['%s_default' %args[0][:-5]], self.paths[args[0][:-5]])
5479 if args[0] == 'param_card':
5480 self.param_card = param_card_mod.ParamCard(self.paths['param'])
5481 elif args[0] == 'run_card':
5482 self.run_card = banner_mod.RunCard(self.paths['run'])
5483 elif args[0] == 'shower_card':
5484 self.shower_card = shower_card_mod.ShowerCard(self.paths['shower'])
5485 return
5486 else:
5487 card = args[0]
5488 start=1
5489 if len(args) < 3:
5490 logger.warning('Invalid set command: %s (not enough arguments)' % line)
5491 return
5492
5493 elif args[0] in ['MadLoop_card']:
5494 if args[1] == 'default':
5495 logger.info('replace MadLoopParams.dat by the default card','$MG:BOLD')
5496 self.MLcard = banner_mod.MadLoopParam(self.MLcardDefault)
5497 self.MLcard.write(self.paths['ML'],
5498 commentdefault=True)
5499 return
5500 else:
5501 card = args[0]
5502 start=1
5503 if len(args) < 3:
5504 logger.warning('Invalid set command: %s (not enough arguments)' % line)
5505 return
5506 elif args[0] in ['pythia8_card']:
5507 if args[1] == 'default':
5508 logger.info('replace pythia8_card.dat by the default card','$MG:BOLD')
5509 self.PY8Card = self.PY8Card_class(self.PY8CardDefault)
5510 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'),
5511 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'),
5512 print_only_visible=True)
5513 return
5514 else:
5515 card = args[0]
5516 start=1
5517 if len(args) < 3:
5518 logger.warning('Invalid set command: %s (not enough arguments)' % line)
5519 return
5520 elif args[0] in ['madspin_card']:
5521 if args[1] == 'default':
5522 logger.info('replace madspin_card.dat by the default card','$MG:BOLD')
5523 files.cp(self.paths['MS_default'], self.paths['madspin'])
5524 return
5525 else:
5526 logger.warning("""Command set not allowed for modifying the madspin_card.
5527 Check the command \"decay\" instead.""")
5528 return
5529
5530
5531 if args[start] in [l.lower() for l in self.run_card.keys()] and card in ['', 'run_card']:
5532
5533 if args[start] not in self.run_set:
5534 if card in self.from_banner or 'run' in self.from_banner:
5535 raise Exception("change not allowed for this card: event already generated!")
5536 args[start] = [l for l in self.run_set if l.lower() == args[start]][0]
5537
5538 if args[start] in self.conflict and card == '':
5539 text = 'Ambiguous name (present in more than one card). Will assume it to be referred to run_card.\n'
5540 text += 'If this is not intended, please reset it in the run_card and specify the relevant card to \n'
5541 text += 'edit, in the format < set card parameter value >'
5542 logger.warning(text)
5543
5544 if args[start+1] == 'default':
5545 default = banner_mod.RunCard(self.paths['run_default'])
5546 if args[start] in list(default.keys()):
5547 self.setR(args[start],default[args[start]])
5548 else:
5549 logger.info('remove information %s from the run_card' % args[start],'$MG:BOLD')
5550 del self.run_card[args[start]]
5551 else:
5552 lower_name = args[0].lower()
5553 if lower_name.startswith('sys_') or \
5554 lower_name in self.run_card.list_parameter or \
5555 lower_name in self.run_card.dict_parameter:
5556 val = ' '.join(args[start+1:])
5557 val = val.split('#')[0]
5558 else:
5559 val = ' '.join(args[start+1:])
5560 self.setR(args[start], val)
5561 self.modified_card.add('run')
5562
5563 elif card == 'run_card' and args[start] in ['nocut', 'no_cut']:
5564 logger.info("Going to remove all cuts from the run_card", '$MG:BOLD')
5565 self.run_card.remove_all_cut()
5566 self.modified_card.add('run')
5567
5568 elif self.param_card and (args[start] in self.param_card or args[start] == 'width') \
5569 and card in ['','param_card']:
5570
5571 if any(t.startswith('scan') for t in args):
5572 index = [i for i,t in enumerate(args) if t.startswith('scan')][0]
5573 args = args[:index] + [' '.join(args[index:])]
5574
5575 if args[start] in self.conflict and card == '':
5576 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5577 text += ' in the format < set card parameter value>'
5578 logger.warning(text)
5579 return
5580
5581 if args[start] == 'width':
5582 args[start] = 'decay'
5583
5584 if args[start+1] in self.pname2block:
5585 all_var = self.pname2block[args[start+1]]
5586 key = None
5587 for bname, lhaid in all_var:
5588 if bname == args[start]:
5589 key = lhaid
5590 break
5591 else:
5592 logger.warning('%s is not part of block "%s" but "%s". please correct.' %
5593 (args[start+1], args[start], bname))
5594 return
5595 else:
5596 try:
5597 key = tuple([int(i) for i in args[start+1:-1]])
5598 except ValueError:
5599 if args[start+1:-1] == ['all']:
5600 for key in self.param_card[args[start]].param_dict:
5601 if (args[start], key) in self.restricted_value:
5602 continue
5603 else:
5604 self.setP(args[start], key, args[-1])
5605 self.modified_card.add('param')
5606 return
5607 logger.warning('invalid set command %s (failed to identify LHA information)' % line)
5608 return
5609
5610 if key in self.param_card[args[start]].param_dict:
5611 if (args[start], key) in self.restricted_value:
5612 text = "Note that this parameter seems to be ignore by MG.\n"
5613 text += "MG will use instead the expression: %s\n" % \
5614 self.restricted_value[(args[start], key)]
5615 text += "You need to match this expression for external program (such pythia)."
5616 logger.warning(text)
5617
5618 if args[-1].lower() in ['default', 'auto', 'auto@nlo'] or args[-1].startswith('scan'):
5619 self.setP(args[start], key, args[-1])
5620 else:
5621 try:
5622 value = float(args[-1])
5623 except Exception:
5624 logger.warning('Invalid input: Expected number and not \'%s\'' \
5625 % args[-1])
5626 return
5627 self.setP(args[start], key, value)
5628 else:
5629 logger.warning('invalid set command %s' % line)
5630 return
5631 self.modified_card.add('param')
5632
5633
5634 elif args[start] in self.pname2block and card in ['','param_card']:
5635 if args[start] in self.conflict and card == '':
5636 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5637 text += ' in the format < set card parameter value>'
5638 logger.warning(text)
5639 return
5640
5641 all_var = self.pname2block[args[start]]
5642 for bname, lhaid in all_var:
5643 new_line = 'param_card %s %s %s' % (bname,
5644 ' '.join([ str(i) for i in lhaid]), ' '.join(args[start+1:]))
5645 self.do_set(new_line)
5646 if len(all_var) > 1:
5647 logger.warning('This variable correspond to more than one parameter in the param_card.')
5648 for bname, lhaid in all_var:
5649 logger.warning(' %s %s' % (bname, ' '.join([str(i) for i in lhaid])))
5650 logger.warning('all listed variables have been modified')
5651
5652
5653 elif self.has_mw and (args[start] in self.mw_card and args[start] != 'comment') \
5654 and card in ['','MadWeight_card']:
5655
5656 if args[start] in self.conflict and card == '':
5657 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5658 text += ' in the format < set card parameter value>'
5659 logger.warning(text)
5660 return
5661
5662 block = args[start]
5663 name = args[start+1]
5664 value = args[start+2:]
5665 self.setM(block, name, value)
5666 self.mw_card.write(self.paths['MadWeight'])
5667
5668
5669 elif self.has_mw and args[start] in self.mw_vars \
5670 and card in ['', 'MadWeight_card']:
5671
5672 if args[start] in self.conflict and card == '':
5673 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5674 text += ' in the format < set card parameter value>'
5675 logger.warning(text)
5676 return
5677
5678 block = [b for b, data in self.mw_card.items() if args[start] in data]
5679 if len(block) > 1:
5680 logger.warning('%s is define in more than one block: %s.Please specify.'
5681 % (args[start], ','.join(block)))
5682 return
5683
5684 block = block[0]
5685 name = args[start]
5686 value = args[start+1:]
5687 self.setM(block, name, value)
5688 self.mw_card.write(self.paths['MadWeight'])
5689
5690
5691 elif self.has_mw and args[start].startswith('mw_') and len(args[start:]) == 3\
5692 and card == 'MadWeight_card':
5693 block = args[start]
5694 name = args[start+1]
5695 value = args[start+2]
5696 self.setM(block, name, value)
5697 self.mw_card.write(self.paths['MadWeight'])
5698
5699
5700 elif self.has_shower and args[start].lower() in [l.lower() for l in \
5701 self.shower_card.keys()] and card in ['', 'shower_card']:
5702 if args[start] not in self.shower_card:
5703 args[start] = [l for l in self.shower_card if l.lower() == args[start].lower()][0]
5704
5705 if args[start] in self.conflict and card == '':
5706 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5707 text += ' in the format < set card parameter value>'
5708 logger.warning(text)
5709 return
5710
5711 if args[start+1].lower() == 'default':
5712 default = shower_card_mod.ShowerCard(self.paths['shower_default'])
5713 if args[start] in list(default.keys()):
5714 self.shower_card.set_param(args[start],default[args[start]], self.paths['shower'])
5715 else:
5716 logger.info('remove information %s from the shower_card' % args[start],'$MG:BOLD')
5717 del self.shower_card[args[start]]
5718 elif args[start+1].lower() in ['t','.true.','true']:
5719 self.shower_card.set_param(args[start],'.true.',self.paths['shower'])
5720 elif args[start+1].lower() in ['f','.false.','false']:
5721 self.shower_card.set_param(args[start],'.false.',self.paths['shower'])
5722 elif args[start] in ['analyse', 'extralibs', 'extrapaths', 'includepaths'] or\
5723 args[start].startswith('dm_'):
5724
5725 args = line.split()
5726 args_str = ' '.join(str(a) for a in args[start+1:len(args)])
5727 self.shower_card.set_param(args[start],args_str,pjoin(self.me_dir,'Cards','shower_card.dat'))
5728 else:
5729 args_str = ' '.join(str(a) for a in args[start+1:len(args)])
5730 self.shower_card.set_param(args[start],args_str,self.paths['shower'])
5731
5732
5733 elif self.has_ml and args[start] in self.ml_vars \
5734 and card in ['', 'MadLoop_card']:
5735
5736 if args[start] in self.conflict and card == '':
5737 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5738 logger.warning(text)
5739 return
5740
5741 if args[start+1] == 'default':
5742 value = self.MLcardDefault[args[start]]
5743 default = True
5744 else:
5745 value = args[start+1]
5746 default = False
5747 self.setML(args[start], value, default=default)
5748 self.MLcard.write(self.paths['ML'],
5749 commentdefault=True)
5750
5751
5752 elif self.has_PY8 and (card == 'pythia8_card' or (card == '' and \
5753 args[start] in self.PY8Card)):
5754
5755 if args[start] in self.conflict and card == '':
5756 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5757 logger.warning(text)
5758 return
5759
5760 if args[start+1] == 'default':
5761 value = self.PY8CardDefault[args[start]]
5762 default = True
5763 else:
5764 value = ' '.join(args[start+1:])
5765 default = False
5766 self.setPY8(args[start], value, default=default)
5767 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'),
5768 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'),
5769 print_only_visible=True)
5770
5771
5772 else:
5773 logger.warning('invalid set command %s ' % line)
5774 arg = args[start].lower()
5775 if self.has_PY8:
5776 close_opts = [name for name in self.PY8Card if name.lower().startswith(arg[:3]) or arg in name.lower()]
5777 if close_opts:
5778 logger.info('Did you mean one of the following PY8 options:\n%s' % '\t'.join(close_opts))
5779 if self.run_card:
5780 close_opts = [name for name in self.run_card if name.lower().startswith(arg[:3]) or arg in name.lower()]
5781 if close_opts:
5782 logger.info('Did you mean one of the following run_card options:\n%s' % '\t'.join(close_opts))
5783
5784 return
5785
5786 - def setM(self, block, name, value):
5787
5788 if isinstance(value, list) and len(value) == 1:
5789 value = value[0]
5790
5791 if block not in self.mw_card:
5792 logger.warning('block %s was not present in the current MadWeight card. We are adding it' % block)
5793 self.mw_card[block] = {}
5794 elif name not in self.mw_card[block]:
5795 logger.info('name %s was not present in the block %s for the current MadWeight card. We are adding it' % (name,block),'$MG:BOLD')
5796 if value == 'default':
5797 import madgraph.madweight.Cards as mwcards
5798 mw_default = mwcards.Card(self.paths['MadWeight_default'])
5799 try:
5800 value = mw_default[block][name]
5801 except KeyError:
5802 logger.info('removing id "%s" from Block "%s" '% (name, block),'$MG:BOLD')
5803 if name in self.mw_card[block]:
5804 del self.mw_card[block][name]
5805 return
5806 if value:
5807 logger.info('modify madweight_card information BLOCK "%s" with id "%s" set to %s',
5808 block, name, value, '$MG:BOLD')
5809 else:
5810 logger.warning("Invalid command: No value. To set default value. Use \"default\" as value")
5811 return
5812
5813 self.mw_card[block][name] = value
5814
5815 - def setR(self, name, value):
5816
5817 if self.mother_interface.inputfile:
5818 self.run_card.set(name, value, user=True, raiseerror=True)
5819 else:
5820 self.run_card.set(name, value, user=True)
5821 new_value = self.run_card.get(name)
5822 logger.info('modify parameter %s of the run_card.dat to %s' % (name, new_value),'$MG:BOLD')
5823
5824
5825 - def setML(self, name, value, default=False):
5826
5827 try:
5828 self.MLcard.set(name, value, user=True)
5829 except Exception as error:
5830 logger.warning("Fail to change parameter. Please Retry. Reason: %s." % error)
5831 return
5832 logger.info('modify parameter %s of the MadLoopParam.dat to %s' % (name, value),'$MG:BOLD')
5833 if default and name.lower() in self.MLcard.user_set:
5834 self.MLcard.user_set.remove(name.lower())
5835
5836 - def setPY8(self, name, value, default=False):
5845
5846 - def setP(self, block, lhaid, value):
5847 if isinstance(value, str):
5848 value = value.lower()
5849 if value == 'default':
5850 default = param_card_mod.ParamCard(self.paths['param_default'])
5851 value = default[block].param_dict[lhaid].value
5852
5853 elif value in ['auto', 'auto@nlo']:
5854 if 'nlo' in value:
5855 value = 'Auto@NLO'
5856 else:
5857 value = 'Auto'
5858 if block != 'decay':
5859 logger.warning('Invalid input: \'Auto\' value only valid for DECAY')
5860 return
5861 elif value.startswith('scan'):
5862 if ':' not in value:
5863 logger.warning('Invalid input: \'scan\' mode requires a \':\' before the definition.')
5864 return
5865 tag = value.split(':')[0]
5866 tag = tag[4:].strip()
5867 if tag and not tag.isdigit():
5868 logger.warning('Invalid input: scan tag need to be integer and not "%s"' % tag)
5869 return
5870
5871
5872 pass
5873 else:
5874 try:
5875 value = float(value)
5876 except ValueError:
5877 logger.warning('Invalid input: \'%s\' not valid intput.'% value)
5878
5879 logger.info('modify param_card information BLOCK %s with id %s set to %s' %\
5880 (block, lhaid, value), '$MG:BOLD')
5881 self.param_card[block].param_dict[lhaid].value = value
5882
5884 """This is run on quitting the class. Apply here all the self-consistency
5885 rule that you want. Do the modification via the set command."""
5886
5887
5888
5889
5890 if isinstance(self.run_card,banner_mod.RunCardLO):
5891
5892 proc_charac = self.mother_interface.proc_characteristics
5893 if proc_charac['grouped_matrix'] and \
5894 abs(self.run_card['lpp1']) == 1 == abs(self.run_card['lpp2']) and \
5895 (self.run_card['nb_proton1'] != self.run_card['nb_proton2'] or
5896 self.run_card['nb_neutron1'] != self.run_card['nb_neutron2'] or
5897 self.run_card['mass_ion1'] != self.run_card['mass_ion2']):
5898 raise Exception("Heavy ion profile for both beam are different but the symmetry used forbids it. \n Please generate your process with \"set group_subprocesses False\".")
5899
5900
5901 for param in self.param_card['decay']:
5902 width = param.value
5903 if width == 0 or isinstance(width,str):
5904 continue
5905 try:
5906 mass = self.param_card['mass'].get(param.lhacode).value
5907 except Exception:
5908 continue
5909 if isinstance(mass,str):
5910 continue
5911
5912 if mass:
5913 to_sleep = True
5914 if abs(width/mass) < self.run_card['small_width_treatment']:
5915 logger.warning("Particle %s with small width detected (%s): See https://answers.launchpad.net/mg5amcnlo/+faq/3053 to learn the special handling of that case",
5916 param.lhacode[0], width)
5917 elif abs(width/mass) < 1e-12:
5918 logger.error('The width of particle %s is too small for an s-channel resonance (%s). If you have this particle in an s-channel, this is likely to create numerical instabilities .', param.lhacode[0], width)
5919 else:
5920 to_sleep = False
5921 if CommonRunCmd.sleep_for_error and to_sleep:
5922 time.sleep(5)
5923 CommonRunCmd.sleep_for_error = False
5924
5925
5926 if 'pythia_card.dat' in self.cards and 'run' in self.allow_arg:
5927 if self.run_card['event_norm'] != 'sum':
5928 logger.info('Pythia6 needs a specific normalisation of the events. We will change it accordingly.', '$MG:BOLD' )
5929 self.do_set('run_card event_norm sum')
5930
5931 elif 'pythia8_card.dat' in self.cards:
5932 if self.run_card['event_norm'] == 'sum':
5933 logger.info('Pythia8 needs a specific normalisation of the events. We will change it accordingly.', '$MG:BOLD' )
5934 self.do_set('run_card event_norm average')
5935
5936 if 'MLM' in proc_charac['limitations']:
5937 if self.run_card['dynamical_scale_choice'] == -1:
5938 raise InvalidCmd("Your model is identified as not fully supported within MG5aMC.\n" +\
5939 "As your process seems to be impacted by the issue,\n"+\
5940 "You can NOT run with CKKW dynamical scale for this model. Please choose another one.")
5941 if self.run_card['ickkw']:
5942 raise InvalidCmd("Your model is identified as not fully supported within MG5aMC.\n" +\
5943 "As your process seems to be impacted by the issue,\n" +\
5944 "You can NOT run with MLM matching/merging. Please check if merging outside MG5aMC are suitable or refrain to use merging with this model")
5945
5946
5947 if not 'sde_strategy' in self.run_card.user_set:
5948 if proc_charac['single_color']:
5949 self.run_card['SDE_strategy'] = 2
5950 else:
5951 self.run_card['SDE_strategy'] = 1
5952 logger.debug("set SDE to %s", self.run_card['SDE_strategy'])
5953 else:
5954 logger.debug("keep SDE to %s", self.run_card['SDE_strategy'])
5955
5956
5957
5958
5959
5960
5961 if isinstance(self.run_card,banner_mod.RunCardNLO):
5962
5963 try:
5964 proc_charac = self.mother_interface.proc_characteristics
5965 except:
5966 proc_charac = None
5967
5968 if proc_charac and 'MLM' in proc_charac['limitations']:
5969 if self.run_card['ickkw']:
5970 raise Exception( "Your model is identified as not fully supported within MG5aMC.\n" +\
5971 "You can NOT run with FxFx/UnLOPS matching/merging. Please check if merging outside MG5aMC are suitable or refrain to use merging with this model")
5972
5973 for pdg in set(list(self.run_card['pt_min_pdg'].keys())+list(self.run_card['pt_max_pdg'].keys())+
5974 list(self.run_card['mxx_min_pdg'].keys())):
5975
5976 if int(pdg)<0:
5977 raise Exception("For PDG specific cuts, always use positive PDG codes: the cuts are applied to both particles and anti-particles")
5978 if self.param_card.get_value('mass', int(pdg), default=0) ==0:
5979 raise Exception("For NLO runs, you can use PDG specific cuts only for massive particles: (failed for %s)" % pdg)
5980
5981
5982 if 'reweight' in self.allow_arg and 'run' in self.allow_arg and \
5983 not self.run_card['store_rwgt_info']:
5984
5985 re_pattern = re.compile(r'''^\s*change\s*mode\s* (LO\+NLO|LO|NLO|NLO_tree)\s*(?:#|$)''', re.M+re.I)
5986 text = open(self.paths['reweight']).read()
5987 options = re_pattern.findall(text)
5988 if any(o in ['NLO', 'LO+NLO'] for o in options):
5989 logger.info('NLO reweighting is on ON. Automatically set store_rwgt_info to True', '$MG:BOLD' )
5990 self.do_set('run_card store_rwgt_info True')
5991
5992
5993
5994 if 'run' in self.allow_arg and \
5995 self.run_card['systematics_program'] == 'systematics' and \
5996 not self.run_card['store_rwgt_info']:
5997 logger.warning('To be able to run systematics program, we set store_rwgt_info to True')
5998 self.do_set('run_card store_rwgt_info True')
5999
6000
6001 if 'run' in self.allow_arg and self.run_card['ickkw'] == 3 :
6002 if 'shower' in self.allow_arg:
6003 if self.shower_card['qcut'] == -1:
6004 self.do_set('shower_card qcut %f' % (2*self.run_card['ptj']))
6005 elif self.shower_card['qcut'] < self.run_card['ptj']*2:
6006 logger.error("ptj cut [in run_card: %s] is more than half the value of QCUT [shower_card: %s] This is not recommended:\n see http://amcatnlo.web.cern.ch/amcatnlo/FxFx_merging.htm ",
6007 self.run_card['ptj'], self.shower_card['qcut'])
6008
6009 if self.shower_card['njmax'] == -1:
6010 if not proc_charac:
6011 raise Exception( "Impossible to setup njmax automatically. Please setup that value manually.")
6012 njmax = proc_charac['max_n_matched_jets']
6013 self.do_set('shower_card njmax %i' % njmax)
6014 if self.shower_card['njmax'] == 0:
6015 raise Exception("Invalid njmax parameter. Can not be set to 0")
6016
6017
6018
6019
6020
6021 if self.has_shower and isinstance(self.run_card, banner_mod.RunCardNLO):
6022 modify_extralibs, modify_extrapaths = False,False
6023 extralibs = self.shower_card['extralibs'].split()
6024 extrapaths = self.shower_card['extrapaths'].split()
6025
6026 if self.run_card['parton_shower'] in ['PYTHIA8', 'HERWIGPP', 'HW7']:
6027 if 'stdhep' in self.shower_card['extralibs']:
6028 extralibs.remove('stdhep')
6029 modify_extralibs = True
6030 if 'Fmcfio' in self.shower_card['extralibs']:
6031 extralibs.remove('Fmcfio')
6032 modify_extralibs = True
6033 if self.run_card['parton_shower'] == 'PYTHIA8':
6034
6035 if not self.mother_interface.options['pythia8_path']:
6036 raise self.mother_interface.InvalidCmd('Pythia8 is not correctly specified to MadGraph5_aMC@NLO')
6037 executable = pjoin(self.mother_interface.options['pythia8_path'], 'bin', 'pythia8-config')
6038 if not os.path.exists(executable):
6039 raise self.mother.InvalidCmd('Pythia8 is not correctly specified to MadGraph5_aMC@NLO')
6040
6041
6042 libs , paths = [], []
6043 p = misc.subprocess.Popen([executable, '--libs'], stdout=subprocess.PIPE)
6044 stdout, _ = p. communicate()
6045 libs = [x[2:] for x in stdout.decode(errors='ignore').split() if x.startswith('-l') or paths.append(x[2:])]
6046
6047
6048 p = misc.subprocess.Popen([executable, '--config'], stdout=subprocess.PIPE)
6049 stdout, _ = p. communicate()
6050 for lib in ['-ldl','-lstdc++','-lc++']:
6051 if lib in stdout.decode(errors='ignore'):
6052 libs.append(lib[2:])
6053
6054
6055
6056 supports_HEPMCHACK = '-DHEPMC2HACK' in stdout.decode(errors='ignore')
6057
6058
6059 for L in paths:
6060 if L not in extrapaths:
6061 modify_extrapaths = True
6062 extrapaths.append(L)
6063 for l in libs:
6064 if l == 'boost_iostreams':
6065
6066 for L in paths + extrapaths:
6067 if misc.glob('*boost_iostreams*', L):
6068 break
6069 else:
6070 continue
6071 if l not in extralibs:
6072 modify_extralibs = True
6073 extralibs.append(l)
6074
6075 if modify_extralibs:
6076 if extralibs:
6077 self.do_set('shower_card extralibs %s ' % ' '.join(extralibs))
6078 else:
6079 self.do_set('shower_card extralibs None ')
6080 if modify_extrapaths:
6081 if extrapaths:
6082 self.do_set('shower_card extrapaths %s ' % ' '.join(extrapaths))
6083 else:
6084 self.do_set('shower_card extrapaths None ')
6085
6086
6087 if self.writting_card:
6088 for key in list(self.modified_card):
6089 self.write_card(key)
6090
6091
6092 - def reask(self, *args, **opt):
6093
6094 cmd.OneLinePathCompletion.reask(self,*args, **opt)
6095 if self.has_mw and not os.path.exists(pjoin(self.me_dir,'Cards','transfer_card.dat')):
6096 logger.warning('No transfer function currently define. Please use the change_tf command to define one.')
6097
6098 fail_due_to_format = 0
6099 - def postcmd(self, stop, line):
6100
6101 if line not in [None, '0', 'done', '']:
6102 ending_question = cmd.OneLinePathCompletion.postcmd(self,stop,line)
6103 else:
6104 ending_question = True
6105
6106 if ending_question:
6107 self.check_card_consistency()
6108 if self.param_consistency:
6109 try:
6110 self.do_update('dependent', timer=20)
6111 except MadGraph5Error as error:
6112 if 'Missing block:' in str(error):
6113 self.fail_due_to_format +=1
6114 if self.fail_due_to_format == 10:
6115 missing, unknow = str(error).split('\n')[-2:]
6116 logger.warning("Invalid param_card:\n%s\n%s\n" % (missing, unknow))
6117 logger.info("Type \"update missing\" to use default value.\n ", '$MG:BOLD')
6118 self.value = False
6119 return self.reask(True)
6120 else:
6121 raise
6122
6123 return ending_question
6124
6125
6126
6127
6128
6130 """ syntax: update dependent: Change the mass/width of particles which are not free parameter for the model.
6131 update missing: add to the current param_card missing blocks/parameters.
6132 update to_slha1: pass SLHA2 card to SLHA1 convention. (beta)
6133 update to_slha2: pass SLHA1 card to SLHA2 convention. (beta)
6134 update to_full [run_card]
6135 update XXX [where XXX correspond to a hidden block of the run_card]
6136 """
6137 args = self.split_arg(line)
6138 if len(args)==0:
6139 logger.warning('miss an argument (dependent or missing). Please retry')
6140 return
6141
6142 if args[0] == 'dependent':
6143 if not self.mother_interface:
6144 logger.warning('Failed to update dependent parameter. This might create trouble for external program (like MadSpin/shower/...)')
6145
6146 pattern_width = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I)
6147 pattern_scan = re.compile(r'''^(decay)?[\s\d]*scan''', re.I+re.M)
6148 param_text= open(self.paths['param']).read()
6149
6150 if pattern_scan.search(param_text):
6151
6152
6153
6154 return
6155 elif pattern_width.search(param_text):
6156 self.do_compute_widths('')
6157 self.param_card = param_card_mod.ParamCard(self.paths['param'])
6158
6159
6160 self.update_dependent(self.mother_interface, self.me_dir, self.param_card,
6161 self.paths['param'], timer)
6162
6163 elif args[0] == 'missing':
6164 self.update_missing()
6165 return
6166
6167 elif args[0] == 'to_slha2':
6168 try:
6169 param_card_mod.convert_to_mg5card(self.paths['param'])
6170 logger.info('card updated')
6171 except Exception as error:
6172 logger.warning('failed to update to slha2 due to %s' % error)
6173 self.param_card = param_card_mod.ParamCard(self.paths['param'])
6174 elif args[0] == 'to_slha1':
6175 try:
6176 param_card_mod.convert_to_slha1(self.paths['param'])
6177 logger.info('card updated')
6178 except Exception as error:
6179 logger.warning('failed to update to slha1 due to %s' % error)
6180 self.param_card = param_card_mod.ParamCard(self.paths['param'])
6181 elif args[0] == 'to_full':
6182 return self.update_to_full(args[1:])
6183 elif args[0] in self.update_block:
6184 self.run_card.display_block.append(args[0].lower())
6185 self.modified_card.add('run')
6186 logger.info('add optional block %s to the run_card', args[0])
6187 else:
6188 self.help_update()
6189 logger.warning('unvalid options for update command. Please retry')
6190
6191
6193 """ trigger via update to_full LINE"""
6194
6195 logger.info("update the run_card by including all the hidden parameter")
6196 self.run_card.write(self.paths['run'], self.paths['run_default'], write_hidden=True)
6197 if 'run' in self.modified_card:
6198 self.modified_card.remove('run')
6199
6201 """proxy on how to write any card"""
6202
6203 if hasattr(self, 'write_card_%s' % name):
6204 getattr(self, 'write_card_%s' % name)()
6205 if name in self.modified_card:
6206 self.modified_card.remove(name)
6207 else:
6208 raise Exception("Need to add the associate writter proxy for %s" % name)
6209
6211 """ write the run_card """
6212 self.run_card.write(self.paths['run'], self.paths['run_default'])
6213
6215 """ write the param_card """
6216
6217 self.param_card.write(self.paths['param'])
6218
6219 @staticmethod
6221 """static method which can also be called from outside the class
6222 usefull in presence of scan.
6223 return if the param_card was updated or not
6224 """
6225
6226 if not param_card:
6227 return False
6228
6229 logger.info('Update the dependent parameter of the param_card.dat')
6230 modify = True
6231 class TimeOutError(Exception):
6232 pass
6233 def handle_alarm(signum, frame):
6234 raise TimeOutError
6235 signal.signal(signal.SIGALRM, handle_alarm)
6236 if timer:
6237 signal.alarm(timer)
6238 log_level=30
6239 else:
6240 log_level=20
6241
6242 try:
6243 model = mecmd.get_model()
6244 signal.alarm(0)
6245 except TimeOutError:
6246 logger.warning('The model takes too long to load so we bypass the updating of dependent parameter.\n'+\
6247 'This might create trouble for external program (like MadSpin/shower/...)\n'+\
6248 'The update can be forced without timer by typing \'update dependent\' at the time of the card edition')
6249 modify =False
6250 except Exception as error:
6251 logger.debug(str(error))
6252 logger.warning('Failed to update dependent parameter. This might create trouble for external program (like MadSpin/shower/...)')
6253 signal.alarm(0)
6254 else:
6255 restrict_card = pjoin(me_dir,'Source','MODEL','param_card_rule.dat')
6256 if not os.path.exists(restrict_card):
6257 restrict_card = None
6258
6259 if model:
6260 modify = param_card.update_dependent(model, restrict_card, log_level)
6261 if modify and path:
6262 param_card.write(path)
6263 else:
6264 logger.warning('missing MG5aMC code. Fail to update dependent parameter. This might create trouble for program like MadSpin/shower/...')
6265
6266 if log_level==20:
6267 logger.info('param_card up to date.')
6268
6269 return modify
6270
6271
6272
6274
6275 def check_block(self, blockname):
6276 add_entry = 0
6277 if blockname.lower() not in self.param_card_default:
6278 logger.info('unknow block %s: block will be ignored', blockname)
6279 return add_entry
6280 block = self.param_card_default[blockname]
6281 for key in block.keys():
6282 if key not in input_in_block:
6283 param = block.get(key)
6284 if blockname != 'decay':
6285 text.append('\t%s\t%s # %s\n' % (' \t'.join([repr(i) for i in param.lhacode]), param.value, param.comment))
6286 else:
6287 text.append('DECAY \t%s\t%s # %s\n' % (' \t'.join([repr(i) for i in param.lhacode]), param.value, param.comment))
6288 add_entry += 1
6289 if add_entry:
6290 text.append('\n')
6291 if add_entry:
6292 logger.info("Adding %s parameter(s) to block %s", add_entry, blockname)
6293 return add_entry
6294
6295
6296 current_block = ''
6297 input_in_block = set()
6298 defined_blocks = set()
6299 decay = set()
6300 text = []
6301 add_entry = 0
6302 for line in open(self.paths['param']):
6303
6304 new_block = re.findall(r'^\s*(block|decay)\s*(\w*)', line, re.I)
6305 if new_block:
6306 new_block = new_block[0]
6307 defined_blocks.add(new_block[1].lower())
6308 if current_block:
6309 add_entry += check_block(self, current_block)
6310
6311 current_block= new_block[1]
6312 input_in_block = set()
6313 if new_block[0].lower() == 'decay':
6314 decay.add((int(new_block[1]),))
6315 current_block = ''
6316 if new_block[1].lower() == 'qnumbers':
6317 current_block = ''
6318
6319 text.append(line)
6320 if not current_block:
6321 continue
6322
6323
6324
6325 line = line.split('#',1)[0]
6326 split = line.split()
6327 if not split:
6328 continue
6329 else:
6330 try:
6331 lhacode = [int(i) for i in split[:-1]]
6332 except:
6333 continue
6334 input_in_block.add(tuple(lhacode))
6335
6336 if current_block:
6337 add_entry += check_block(self, current_block)
6338
6339
6340 for block in self.param_card_default:
6341
6342 if block.startswith(('qnumbers', 'decay')):
6343 continue
6344
6345 if block not in defined_blocks:
6346 nb_entry = len(self.param_card_default[block])
6347 logger.info("Block %s was missing. Adding the %s associated parameter(s)", block,nb_entry)
6348 add_entry += nb_entry
6349 text.append(str(self.param_card_default[block]))
6350
6351
6352 input_in_block = decay
6353 add_entry += check_block(self, 'decay')
6354
6355 if add_entry:
6356 logger.info('write new param_card with %s new parameter(s).', add_entry, '$MG:BOLD')
6357 open(self.paths['param'],'w').write(''.join(text))
6358 self.reload_card(self.paths['param'])
6359 else:
6360 logger.info('No missing parameter detected.', '$MG:BOLD')
6361
6362
6367
6395
6397
6398 line = line.strip()
6399 args = line.split()
6400
6401 if not args:
6402 return line
6403 if not hasattr(self, 'trigger_%s' % args[0]):
6404 return line
6405
6406 triggerfct = getattr(self, 'trigger_%s' % args[0])
6407
6408
6409 outline = triggerfct(' '.join(args[1:]))
6410 if not outline:
6411 return 'repeat'
6412 return outline
6413
6415 """Default action if line is not recognized"""
6416
6417
6418 line = self.trigger(line)
6419
6420
6421 line = line.strip()
6422 args = line.split()
6423 if line == '' and self.default_value is not None:
6424 self.value = self.default_value
6425
6426 elif hasattr(self, 'do_%s' % args[0]):
6427 self.do_set(' '.join(args[1:]))
6428 elif line.strip() != '0' and line.strip() != 'done' and \
6429 str(line) != 'EOF' and line.strip() in self.allow_arg:
6430 self.open_file(line)
6431 self.value = 'repeat'
6432 elif os.path.isfile(line):
6433 self.copy_file(line)
6434 self.value = 'repeat'
6435 elif self.me_dir and os.path.exists(pjoin(self.me_dir, line)):
6436 self.copy_file(pjoin(self.me_dir,line))
6437 self.value = 'repeat'
6438 elif line.strip().startswith(('http:','www', 'https')):
6439 self.value = 'repeat'
6440 import tempfile
6441 fsock, path = tempfile.mkstemp()
6442 try:
6443 text = six.moves.urllib.request.urlopen(line.strip())
6444 url = line.strip()
6445 except Exception:
6446 logger.error('fail to load the file')
6447 else:
6448 for line in text:
6449 os.write(fsock, line)
6450 os.close(fsock)
6451 self.copy_file(path, pathname=url)
6452 os.remove(path)
6453
6454
6455 else:
6456 self.value = line
6457
6458 return line
6459
6460
6462 """edit the madspin_card to define the decay of the associate particle"""
6463 signal.alarm(0)
6464 path = self.paths['madspin']
6465
6466 if 'madspin_card.dat' not in self.cards or not os.path.exists(path):
6467 logger.warning("Command decay not valid. Since MadSpin is not available.")
6468 return
6469
6470 if ">" not in line:
6471 logger.warning("invalid command for decay. Line ignored")
6472 return
6473
6474 if "-add" in line:
6475
6476 particle = line.split('>')[0].strip()
6477 text = open(path).read()
6478 line = line.replace('--add', '').replace('-add','')
6479 logger.info("change madspin_card to add one decay to %s: %s" %(particle, line.strip()), '$MG:BOLD')
6480 if 'launch' in text:
6481 text = text.replace('launch', "\ndecay %s\nlaunch\n" % line,1)
6482 else:
6483 text += '\ndecay %s\n launch \n' % line
6484 else:
6485
6486
6487 particle = line.split('>')[0].strip()
6488 logger.info("change madspin_card to define the decay of %s: %s" %(particle, line.strip()), '$MG:BOLD')
6489 particle = particle.replace('+','\+').replace('-','\-')
6490 decay_pattern = re.compile(r"^\s*decay\s+%s\s*>[\s\w+-~]*?$" % particle, re.I+re.M)
6491 text= open(path).read()
6492 text = decay_pattern.sub('', text)
6493 if 'launch' in text:
6494 text = text.replace('launch', "\ndecay %s\nlaunch\n" % line,1)
6495 else:
6496 text += '\ndecay %s\n launch \n' % line
6497
6498 with open(path,'w') as fsock:
6499 fsock.write(text)
6500 self.reload_card(path)
6501
6502
6503
6505 signal.alarm(0)
6506
6507
6508 if 'param' in self.modified_card:
6509 self.write_card('param')
6510 self.modified_card.discard('param')
6511
6512 path = self.paths['param']
6513 pattern = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I)
6514 text = open(path).read()
6515 pdg_info = pattern.findall(text)
6516 has_nlo = any("@nlo"==nlo.lower() for _, nlo in pdg_info)
6517 pdg = [p for p,_ in pdg_info]
6518
6519
6520 line = '%s %s' % (line, ' '.join(pdg))
6521 if not '--path' in line:
6522 line += ' --path=%s' % path
6523 if has_nlo:
6524 line += ' --nlo'
6525
6526 try:
6527 out = self.mother_interface.do_compute_widths(line)
6528 except InvalidCmd as error:
6529 logger.error("Invalid command: %s " % error)
6530 else:
6531 self.reload_card(path)
6532 if hasattr(self, 'run_card'):
6533 for pid, info in out.items():
6534 total = 0
6535 for key, partial in info:
6536 total += partial
6537 mass = self.param_card.get_value('mass', pid)
6538 try:
6539 small_width_treatment = self.run_card['small_width_treatment']
6540 except Exception:
6541 small_width_treatment = 0
6542
6543 if total and total/mass < small_width_treatment:
6544 text = "Particle %s with very small width (%g): Learn about special handling here: https://answers.launchpad.net/mg5amcnlo/+faq/3053"
6545 logger.warning(text,pid,total)
6546 elif total and total/mass < 1e-11:
6547 text = "Particle %s with very small width (%g): Numerical inaccuracies can occur if that particle is in a s-channel"
6548 logger.critical(text,pid,total)
6549
6550
6551 return out
6552
6553
6557
6559 """help for command decay which modifies MadSpin_card"""
6560
6561 signal.alarm(0)
6562 print('--syntax: decay PROC [--add]')
6563 print(' ')
6564 print(' modify the madspin_card to modify the decay of the associate particle.')
6565 print(' and define it to PROC.')
6566 print(' if --add is present, just add a new decay for the associate particle.')
6567
6569 prev_timer = signal.alarm(0)
6570 if prev_timer:
6571 nb_back = len(line)
6572 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
6573 self.stdout.write(line)
6574 self.stdout.flush()
6575 return self.mother_interface.complete_compute_widths(text, line, begidx, endidx,**opts)
6576
6577
6579 """help for add command"""
6580
6581 logger.info('********************* HELP ADD ***************************')
6582 logger.info( '-- syntax: add pythia8_card NAME VALUE')
6583 logger.info( " add a definition of name in the pythia8_card with the given value")
6584 logger.info( " Do not work for the param_card" )
6585 logger.info('')
6586 return self.help_edit(prefix=False)
6587
6589 """help for edit command"""
6590
6591 if prefix: logger.info('********************* HELP ADD|EDIT ***************************')
6592 logger.info( '-- syntax: add filename [OPTION] LINE')
6593 logger.info( '-- syntax: edit filename [OPTION] LINE')
6594 logger.info( ' add the given LINE to the end of the associate file (all file supported).')
6595 logger.info( '')
6596 logger.info( ' OPTION parameter allows to change the position where to write in the file')
6597 logger.info( ' --after_line=banner : write the line at the end of the banner')
6598 logger.info( ' --line_position=X : insert the line before line X (starts at 0)')
6599 logger.info( ' --line_position=afterlast : insert the line after the latest inserted/modified line.')
6600 logger.info( ' --after_line="<regular-expression>" write the line after the first line matching the regular expression')
6601 logger.info( ' --before_line="<regular-expression>" write the line before the first line matching the regular expression')
6602 logger.info( ' --replace_line="<regular-expression>" replace the line matching the regular expression')
6603 logger.info( ' --clean remove all previously existing line in the file')
6604 logger.info( ' --comment_line="<regular-expression>" comment all lines matching the regular expression')
6605 logger.info('')
6606 logger.info(' Note: all regular-expression will be prefixed by ^\s*')
6607 logger.info('')
6608 logger.info( ' example: edit reweight --after_line="change mode\b" change model heft')
6609 logger.info( ' edit madspin --after_line="banner" change model XXXX')
6610 logger.info('********************* HELP ADD|EDIT ***************************')
6611
6612
6613 - def complete_add(self, text, line, begidx, endidx, formatting=True):
6614 """ auto-completion for add command"""
6615
6616 prev_timer = signal.alarm(0)
6617 if prev_timer:
6618 nb_back = len(line)
6619 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
6620 self.stdout.write(line)
6621 self.stdout.flush()
6622
6623 split = line[:begidx].split()
6624 if len(split)==1:
6625 possibilities = {}
6626 cards = [c.rsplit('.',1)[0] for c in self.cards]
6627 possibilities['category of parameter (optional)'] = \
6628 self.list_completion(text, cards)
6629 elif len(split) == 2:
6630 possibilities = {}
6631 options = ['--line_position=','--line_position=afterlast','--after_line=banner', '--after_line="','--before_line="']
6632 possibilities['category of parameter (optional)'] = \
6633 self.list_completion(text, options, line)
6634 else:
6635 return
6636 return self.deal_multiple_categories(possibilities, formatting)
6637
6639 """ syntax: add filename NAME VALUE
6640 syntax: add filename LINE"""
6641
6642 args = self.split_arg(line)
6643 if len(args) == 3 and args[0] in ['pythia8_card', 'pythia8_card.dat'] and self.has_PY8:
6644 name= args[1]
6645 value = args[2]
6646 self.PY8Card.userSet(name, value)
6647 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'),
6648 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'),
6649 print_only_visible=True)
6650 logger.info("add in the pythia8_card the parameter \"%s\" with value \"%s\"" % (name, value), '$MG:BOLD')
6651 elif len(args) > 0:
6652 if args[0] in self.cards:
6653 card = args[0]
6654 elif "%s.dat" % args[0] in self.cards:
6655 card = "%s.dat" % args[0]
6656 elif "%s_card.dat" % args[0] in self.cards:
6657 card = "%s_card.dat" % args[0]
6658 elif self.has_ml and args[0].lower() == "madloop":
6659 card = "MadLoopParams.dat"
6660 else:
6661 logger.error("unknow card %s. Please retry." % args[0])
6662 return
6663
6664 if card in self.modified_card:
6665 self.write_card(card)
6666 self.modified_card.discard(card)
6667
6668 if card in self.paths:
6669 path = self.paths[card]
6670 elif os.path.exists(card):
6671 path = card
6672 elif os.path.exists(pjoin(self.me_dir,'Cards',card)):
6673 path = pjoin(self.me_dir,'Cards',card)
6674 else:
6675 raise Exception('unknow path')
6676
6677
6678 if args[1] == '--clean':
6679 ff = open(path,'w')
6680 ff.write("# %s \n" % card)
6681 ff.write("%s \n" % line.split(None,2)[2])
6682 ff.close()
6683 logger.info("writing the line in %s (empty file) the line: \"%s\"" %(card, line.split(None,2)[2] ),'$MG:BOLD')
6684 elif args[1].startswith('--line_position=afterlast'):
6685
6686 text = open(path).read()
6687 split = text.split('\n')
6688 if self.last_editline_pos > 0:
6689 pos = self.last_editline_pos +1
6690 newline = line.split(None,2)[2]
6691 split.insert(pos, newline)
6692 ff = open(path,'w')
6693 ff.write('\n'.join(split))
6694 logger.info("writting at line %d of the file %s the line: \"%s\"" %(pos, card, line.split(None,2)[2] ),'$MG:BOLD')
6695 self.last_editline_pos = pos
6696 elif args[1].startswith('--line_position='):
6697
6698 text = open(path).read()
6699 split = text.split('\n')
6700 pos = int(args[1].split('=',1)[1])
6701 newline = line.split(None,2)[2]
6702 split.insert(pos, newline)
6703 ff = open(path,'w')
6704 ff.write('\n'.join(split))
6705 logger.info("writting at line %d of the file %s the line: \"%s\"" %(pos, card, line.split(None,2)[2] ),'$MG:BOLD')
6706 self.last_editline_pos = pos
6707
6708 elif args[1].startswith(('--after_line=banner','--after_line=\'banner\'','--after_line=\"banner\"')):
6709
6710 text = open(path).read()
6711 split = text.split('\n')
6712 for posline,l in enumerate(split):
6713 if not l.startswith('#'):
6714 break
6715 split.insert(posline, line.split(None,2)[2])
6716 ff = open(path,'w')
6717 ff.write('\n'.join(split))
6718 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline, card, line.split(None,2)[2] ),'$MG:BOLD')
6719 self.last_editline_pos = posline
6720
6721 elif args[1].startswith('--replace_line='):
6722
6723
6724 text = open(path).read()
6725 split = text.split('\n')
6726 search_pattern=r'''replace_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6727 pattern = '^\s*' + re.search(search_pattern, line).group()[14:-1]
6728 for posline,l in enumerate(split):
6729 if re.search(pattern, l):
6730 break
6731 else:
6732 new_line = re.split(search_pattern,line)[-1].strip()
6733 if new_line.startswith(('--before_line=','--after_line')):
6734 return self.do_add('%s %s' % (args[0], new_line))
6735 raise Exception('invalid regular expression: not found in file')
6736
6737
6738 new_line = re.split(search_pattern,line)[-1].strip()
6739 if new_line.startswith(('--before_line=','--after_line')):
6740 search_pattern=r'''(?:before|after)_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6741 new_line = re.split(search_pattern,new_line)[-1]
6742
6743 old_line = split[posline]
6744 split[posline] = new_line
6745 ff = open(path,'w')
6746 ff.write('\n'.join(split))
6747 logger.info("Replacing the line \"%s\" [line %d of %s] by \"%s\"" %
6748 (old_line, posline, card, new_line ),'$MG:BOLD')
6749 self.last_editline_pos = posline
6750
6751 elif args[1].startswith('--comment_line='):
6752
6753
6754 text = open(path).read()
6755 split = text.split('\n')
6756 search_pattern=r'''comment_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6757 pattern = '^\s*' + re.search(search_pattern, line).group()[14:-1]
6758 nb_mod = 0
6759 for posline,l in enumerate(split):
6760 if re.search(pattern, l):
6761 split[posline] = '#%s' % l
6762 nb_mod +=1
6763 logger.info("Commenting line \"%s\" [line %d of %s]" %
6764 (l, posline, card ),'$MG:BOLD')
6765
6766 if not nb_mod:
6767 logger.warning('no line commented (no line matching)')
6768 ff = open(path,'w')
6769 ff.write('\n'.join(split))
6770
6771 self.last_editline_pos = posline
6772
6773
6774 elif args[1].startswith('--before_line='):
6775
6776 text = open(path).read()
6777 split = text.split('\n')
6778 search_pattern=r'''before_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6779 pattern = '^\s*' + re.search(search_pattern, line).group()[13:-1]
6780 for posline,l in enumerate(split):
6781 if re.search(pattern, l):
6782 break
6783 else:
6784 raise Exception('invalid regular expression: not found in file')
6785 split.insert(posline, re.split(search_pattern,line)[-1])
6786 ff = open(path,'w')
6787 ff.write('\n'.join(split))
6788 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline, card, line.split(None,2)[2] ),'$MG:BOLD')
6789 self.last_editline_pos = posline
6790
6791 elif args[1].startswith('--after_line='):
6792
6793 text = open(path).read()
6794 split = text.split('\n')
6795 search_pattern = r'''after_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6796 pattern = '^\s*' + re.search(search_pattern, line).group()[12:-1]
6797 for posline,l in enumerate(split):
6798 if re.search(pattern, l):
6799 break
6800 else:
6801 posline=len(split)
6802 split.insert(posline+1, re.split(search_pattern,line)[-1])
6803 ff = open(path,'w')
6804 ff.write('\n'.join(split))
6805
6806 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline+1, card, line.split(None,2)[2] ),'$MG:BOLD')
6807 self.last_editline_pos = posline+1
6808
6809 else:
6810 ff = open(path,'a')
6811 ff.write("%s \n" % line.split(None,1)[1])
6812 ff.close()
6813 logger.info("adding at the end of the file %s the line: \"%s\"" %(card, line.split(None,1)[1] ),'$MG:BOLD')
6814 self.last_editline_pos = -1
6815
6816 self.reload_card(path)
6817
6818 do_edit = do_add
6819 complete_edit = complete_add
6820
6822 """Help associated to the asperge command"""
6823 signal.alarm(0)
6824
6825 print('-- syntax: asperge [options]')
6826 print(' Call ASperGe to diagonalize all mass matrices in the model.')
6827 print(' This works only if the ASperGE module is part of the UFO model (a subdirectory).')
6828 print(' If you specify some names after the command (i.e. asperge m1 m2) then ASperGe will only')
6829 print(' diagonalize the associate mass matrices (here m1 and m2).')
6830
6832 prev_timer = signal.alarm(0)
6833 if prev_timer:
6834 nb_back = len(line)
6835 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
6836 self.stdout.write(line)
6837 self.stdout.flush()
6838 blockname = list(self.pname2block.keys())
6839
6840 wrong = ['decay', 'mass', 'sminput']
6841 valid = [k for k in blockname if 'mix' in k]
6842 potential = [k for k in blockname if k not in valid+wrong]
6843 output = {'Mixing matrices': self.list_completion(text, valid, line),
6844 'Other potential valid input': self.list_completion(text, potential, line)}
6845
6846 return self.deal_multiple_categories(output, formatting)
6847
6848
6850 """Running ASperGe"""
6851 signal.alarm(0)
6852
6853
6854 if 'param' in self.modified_card:
6855 self.write_card('param')
6856 self.modified_card.discard('param')
6857
6858
6859 path = pjoin(self.me_dir,'bin','internal','ufomodel','ASperGE')
6860 if not os.path.exists(path):
6861 logger.error('ASperge has not been detected in the current model, therefore it will not be run.')
6862 return
6863 elif not os.path.exists(pjoin(path,'ASperGe')):
6864 logger.info('ASperGe has been detected but is not compiled. Running the compilation now.')
6865 try:
6866 misc.compile(cwd=path,shell=True)
6867 except MadGraph5Error as error:
6868 logger.error('''ASperGe failed to compile. Note that gsl is needed
6869 for this compilation to go trough. More information on how to install this package on
6870 http://www.gnu.org/software/gsl/
6871 Full compilation log is available at %s''' % pjoin(self.me_dir, 'ASperge_compilation.log'))
6872 open(pjoin(self.me_dir, 'ASperge_compilation.log'),'w').write(str(error))
6873 return
6874
6875 opts = line.split()
6876 card = self.paths['param']
6877 logger.info('running ASperGE')
6878 returncode = misc.call([pjoin(path,'ASperGe'), card, '%s.new' % card] + opts)
6879 if returncode:
6880 logger.error('ASperGE fails with status %s' % returncode)
6881 else:
6882 logger.info('AsPerGe creates the file succesfully')
6883 files.mv(card, '%s.beforeasperge' % card)
6884 files.mv('%s.new' % card, card)
6885 self.reload_card(card)
6886
6887
6888
6890 """detect the type of the file and overwritte the current file"""
6891
6892 if not pathname:
6893 pathname = path
6894
6895 if path.endswith('.lhco'):
6896
6897
6898 self.do_set('mw_run inputfile %s' % os.path.relpath(path, self.mother_interface.me_dir))
6899 return
6900 elif path.endswith('.lhco.gz'):
6901
6902
6903 self.do_set('mw_run inputfile %s' % os.path.relpath(path, self.mother_interface.me_dir))
6904 return
6905 else:
6906 card_name = self.detect_card_type(path)
6907
6908 if card_name == 'unknown':
6909 logger.warning('Fail to determine the type of the file. Not copied')
6910 if card_name != 'banner':
6911 logger.info('copy %s as %s' % (pathname, card_name))
6912 files.cp(path, self.paths[card_name.rsplit('_',1)[0]])
6913 self.reload_card(self.paths[card_name.rsplit('_',1)[0]])
6914 elif card_name == 'banner':
6915 banner_mod.split_banner(path, self.mother_interface.me_dir, proc_card=False)
6916 logger.info('Splitting the banner in it\'s component')
6917 if not self.mode == 'auto':
6918 self.mother_interface.keep_cards(self.cards)
6919 for card_name in self.cards:
6920 self.reload_card(pjoin(self.me_dir, 'Cards', card_name))
6921
6926
6928 """open the file"""
6929
6930 try:
6931 me_dir = self.mother_interface.me_dir
6932 except:
6933 me_dir = None
6934
6935 if answer.isdigit():
6936 if answer == '9':
6937 answer = 'plot'
6938 else:
6939 answer = self.cards[int(answer)-self.integer_bias]
6940
6941 if 'madweight' in answer:
6942 answer = answer.replace('madweight', 'MadWeight')
6943 elif 'MadLoopParams' in answer:
6944 answer = self.paths['ML']
6945 elif 'pythia8_card' in answer:
6946 answer = self.paths['pythia8']
6947 if os.path.exists(answer):
6948 path = answer
6949 else:
6950 if not '.dat' in answer and not '.lhco' in answer:
6951 if answer != 'trigger':
6952 path = self.paths[answer]
6953 else:
6954 path = self.paths['delphes']
6955 elif not '.lhco' in answer:
6956 if '_' in answer:
6957 path = self.paths['_'.join(answer.split('_')[:-1])]
6958 else:
6959 path = pjoin(me_dir, 'Cards', answer)
6960 else:
6961 path = pjoin(me_dir, self.mw_card['mw_run']['inputfile'])
6962 if not os.path.exists(path):
6963 logger.info('Path in MW_card not existing')
6964 path = pjoin(me_dir, 'Events', answer)
6965
6966 path = path.replace('_card_card','_card')
6967
6968 if answer in self.modified_card:
6969 self.write_card(answer)
6970 elif os.path.basename(answer.replace('_card.dat','')) in self.modified_card:
6971 self.write_card(os.path.basename(answer.replace('_card.dat','')))
6972
6973 try:
6974 self.mother_interface.exec_cmd('open %s' % path)
6975 except InvalidCmd as error:
6976 if str(error) != 'No default path for this file':
6977 raise
6978 if answer == 'transfer_card.dat':
6979 logger.warning('You have to specify a transfer function first!')
6980 elif answer == 'input.lhco':
6981 path = pjoin(me_dir,'Events', 'input.lhco')
6982 ff = open(path,'w')
6983 ff.write('''No LHCO information imported at current time.
6984 To import a lhco file: Close this file and type the path of your file.
6985 You can also copy/paste, your event file here.''')
6986 ff.close()
6987 self.open_file(path)
6988 else:
6989 raise
6990 self.reload_card(path)
6991
6993 """reload object to have it in sync"""
6994
6995 if path == self.paths['param']:
6996 try:
6997 self.param_card = param_card_mod.ParamCard(path)
6998 except (param_card_mod.InvalidParamCard, ValueError) as e:
6999 logger.error('Current param_card is not valid. We are going to use the default one.')
7000 logger.error('problem detected: %s' % e)
7001 logger.error('Please re-open the file and fix the problem.')
7002 logger.warning('using the \'set\' command without opening the file will discard all your manual change')
7003 elif path == self.paths['run']:
7004 self.run_card = banner_mod.RunCard(path)
7005 elif path == self.paths['shower']:
7006 self.shower_card = shower_card_mod.ShowerCard(path)
7007 elif path == self.paths['ML']:
7008 self.MLcard = banner_mod.MadLoopParam(path)
7009 elif path == self.paths['pythia8']:
7010
7011
7012 if not self.PY8Card:
7013 self.PY8Card = self.PY8Card_class(self.paths['pythia8_default'])
7014
7015 self.PY8Card.read(self.paths['pythia8'], setter='user')
7016 self.py8_vars = [k.lower() for k in self.PY8Card.keys()]
7017 elif path == self.paths['MadWeight']:
7018 try:
7019 import madgraph.madweight.Cards as mwcards
7020 except:
7021 import internal.madweight.Cards as mwcards
7022 self.mw_card = mwcards.Card(path)
7023 else:
7024 logger.debug('not keep in sync: %s', path)
7025 return path
7026
7027
7028
7029 -def scanparamcardhandling(input_path=lambda obj: pjoin(obj.me_dir, 'Cards', 'param_card.dat'),
7030 store_for_scan=lambda obj: obj.store_scan_result,
7031 get_run_name=lambda obj: obj.run_name,
7032 set_run_name=lambda obj: obj.set_run_name,
7033 result_path=lambda obj: pjoin(obj.me_dir, 'Events', 'scan_%s.txt' ),
7034 ignoreerror=ZeroResult,
7035 iteratorclass=param_card_mod.ParamCardIterator,
7036 summaryorder=lambda obj: lambda:None,
7037 check_card=lambda obj: CommonRunCmd.static_check_param_card,
7038 ):
7039 """ This is a decorator for customizing/using scan over the param_card (or technically other)
7040 This should be use like this:
7041
7042 @scanparamcardhandling(arguments)
7043 def run_launch(self, *args, **opts)
7044
7045 possible arguments are listed above and should be function who takes a single
7046 argument the instance of intereset. those return
7047 input_path -> function that return the path of the card to read
7048 store_for_scan -> function that return a dict of entry to keep in memory
7049 get_run_name -> function that return the string with the current run_name
7050 set_run_name -> function that return the function that allow the set the next run_name
7051 result_path -> function that return the path of the summary result to write
7052 ignoreerror -> one class of error which are not for the error
7053 IteratorClass -> class to use for the iterator
7054 summaryorder -> function that return the function to call to get the order
7055
7056 advanced:
7057 check_card -> function that return the function to read the card and init stuff (compute auto-width/init self.iterator/...)
7058 This function should define the self.param_card_iterator if a scan exists
7059 and the one calling the auto-width functionalities/...
7060
7061 All the function are taking a single argument (an instance of the class on which the decorator is used)
7062 and they can either return themself a function or a string.
7063
7064 Note:
7065 1. the link to auto-width is not fully trivial due to the model handling
7066 a. If you inherit from CommonRunCmd (or if the self.mother is). Then
7067 everything should be automatic.
7068
7069 b. If you do not you can/should create the funtion self.get_model().
7070 Which returns the appropriate MG model (like the one from import_ufo.import_model)
7071
7072 c. You can also have full control by defining your own do_compute_widths(self, line)
7073 functions.
7074 """
7075 class restore_iterator(object):
7076 """ensure that the original card is always restore even for crash"""
7077 def __init__(self, iterator, path):
7078 self.iterator = iterator
7079 self.path = path
7080
7081 def __enter__(self):
7082 return self.iterator
7083
7084 def __exit__(self, ctype, value, traceback ):
7085 self.iterator.write(self.path)
7086
7087 def decorator(original_fct):
7088 def new_fct(obj, *args, **opts):
7089
7090 if isinstance(input_path, str):
7091 card_path = input_path
7092 else:
7093 card_path = input_path(obj)
7094
7095
7096
7097
7098
7099
7100
7101
7102 check_card(obj)(card_path, obj, iterator_class=iteratorclass)
7103
7104 param_card_iterator = None
7105 if obj.param_card_iterator:
7106 param_card_iterator = obj.param_card_iterator
7107 obj.param_card_iterator = []
7108
7109 if not param_card_iterator:
7110
7111 original_fct(obj, *args, **opts)
7112 return
7113
7114 with restore_iterator(param_card_iterator, card_path):
7115
7116
7117
7118 if not hasattr(obj, 'allow_notification_center'):
7119 obj.allow_notification_center = False
7120 with misc.TMP_variable(obj, 'allow_notification_center', False):
7121 orig_name = get_run_name(obj)
7122 next_name = orig_name
7123
7124 set_run_name(obj)(next_name)
7125
7126 original_fct(obj, *args, **opts)
7127 param_card_iterator.store_entry(next_name, store_for_scan(obj)(), param_card_path=card_path)
7128 for card in param_card_iterator:
7129 card.write(card_path)
7130
7131 check_card(obj)(card_path, obj, dependent=True)
7132 next_name = param_card_iterator.get_next_name(next_name)
7133 set_run_name(obj)(next_name)
7134 try:
7135 original_fct(obj, *args, **opts)
7136 except ignoreerror as error:
7137 param_card_iterator.store_entry(next_name, {'exception': error})
7138 else:
7139 param_card_iterator.store_entry(next_name, store_for_scan(obj)(), param_card_path=card_path)
7140
7141
7142 name = misc.get_scan_name(orig_name, next_name)
7143 path = result_path(obj) % name
7144 logger.info("write scan results in %s" % path ,'$MG:BOLD')
7145 order = summaryorder(obj)()
7146 param_card_iterator.write_summary(path, order=order)
7147 return new_fct
7148 return decorator
7149