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(['python', '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(self.options['nb_core'], nb_event//2500)
1803 elif self.options['run_mode'] ==1:
1804 nb_submit = min(self.options['cluster_size'], nb_event//25000)
1805 else:
1806 nb_submit =1
1807
1808 if MADEVENT:
1809 import internal.systematics as systematics
1810 else:
1811 import madgraph.various.systematics as systematics
1812
1813
1814 if nb_submit in [0,1]:
1815 systematics.call_systematics([input, output] + opts,
1816 log=lambda x: logger.info(str(x)),
1817 result=result_file
1818 )
1819
1820 elif self.options['run_mode'] in [1,2]:
1821 event_per_job = nb_event // nb_submit
1822 nb_job_with_plus_one = nb_event % nb_submit
1823 start_event, stop_event = 0,0
1824 if sys.version_info[1] == 6 and sys.version_info[0] == 2:
1825 if input.endswith('.gz'):
1826 misc.gunzip(input)
1827 input = input[:-3]
1828
1829 for i in range(nb_submit):
1830
1831 event_requested = event_per_job
1832 if i < nb_job_with_plus_one:
1833 event_requested += 1
1834 start_event = stop_event
1835 stop_event = start_event + event_requested
1836
1837 prog = sys.executable
1838 input_files = [os.path.basename(input)]
1839 output_files = ['./tmp_%s_%s' % (i, os.path.basename(output)),
1840 './log_sys_%s.txt' % (i)]
1841 argument = []
1842 if not __debug__:
1843 argument.append('-O')
1844 argument += [pjoin(self.me_dir, 'bin', 'internal', 'systematics.py'),
1845 input_files[0], output_files[0]] + opts +\
1846 ['--start_event=%i' % start_event,
1847 '--stop_event=%i' %stop_event,
1848 '--result=./log_sys_%s.txt' %i,
1849 '--lhapdf_config=%s' % self.options['lhapdf']]
1850 required_output = output_files
1851 self.cluster.cluster_submit(prog, argument,
1852 input_files=input_files,
1853 output_files=output_files,
1854 cwd=os.path.dirname(output),
1855 required_output=required_output,
1856 stdout='/dev/null'
1857 )
1858 starttime = time.time()
1859 update_status = lambda idle, run, finish: \
1860 self.update_status((idle, run, finish, 'running systematics'), level=None,
1861 force=False, starttime=starttime)
1862
1863 try:
1864 self.cluster.wait(os.path.dirname(output), update_status, update_first=update_status)
1865 except Exception:
1866 self.cluster.remove()
1867 old_run_mode = self.options['run_mode']
1868 self.options['run_mode'] =0
1869 try:
1870 out = self.do_systematics(line)
1871 finally:
1872 self.options['run_mode'] = old_run_mode
1873
1874 all_cross = []
1875 for i in range(nb_submit):
1876 pos=0
1877 for line in open(pjoin(os.path.dirname(output), 'log_sys_%s.txt'%i)):
1878 if line.startswith('#'):
1879 continue
1880 split = line.split()
1881 if len(split) in [0,1]:
1882 continue
1883 key = tuple(float(x) for x in split[:-1])
1884 cross= float(split[-1])
1885 if 'event_norm' in self.run_card and \
1886 self.run_card['event_norm'] in ['average', 'unity', 'bias']:
1887 cross *= (event_per_job+1 if i <nb_job_with_plus_one else event_per_job)
1888 if len(all_cross) > pos:
1889 all_cross[pos] += cross
1890 else:
1891 all_cross.append(cross)
1892 pos+=1
1893
1894 if 'event_norm' in self.run_card and \
1895 self.run_card['event_norm'] in ['unity']:
1896 all_cross= [cross/nb_event for cross in all_cross]
1897
1898 sys_obj = systematics.call_systematics([input, None] + opts,
1899 log=lambda x: logger.info(str(x)),
1900 result=result_file,
1901 running=False
1902 )
1903 sys_obj.print_cross_sections(all_cross, nb_event, result_file)
1904
1905
1906 subprocess.call(['cat']+\
1907 ['./tmp_%s_%s' % (i, os.path.basename(output)) for i in range(nb_submit)],
1908 stdout=open(output,'w'),
1909 cwd=os.path.dirname(output))
1910 for i in range(nb_submit):
1911 os.remove('%s/tmp_%s_%s' %(os.path.dirname(output),i,os.path.basename(output)))
1912
1913
1914
1915
1916
1917
1918 self.update_status('End of systematics computation', level='parton', makehtml=False)
1919
1920
1921
1923 """ syntax is "reweight RUN_NAME"
1924 Allow to reweight the events generated with a new choices of model
1925 parameter. Description of the methods are available here
1926 cp3.irmp.ucl.ac.be/projects/madgraph/wiki/Reweight
1927 """
1928
1929
1930
1931 def check_multicore(self):
1932 """ determine if the cards are save for multicore use"""
1933 card = pjoin(self.me_dir, 'Cards', 'reweight_card.dat')
1934
1935 multicore = True
1936 if self.options['run_mode'] in [0,1]:
1937 multicore = False
1938
1939 lines = [l.strip() for l in open(card) if not l.strip().startswith('#')]
1940 while lines and not lines[0].startswith('launch'):
1941 line = lines.pop(0)
1942
1943 if line.startswith('change') and line[6:].strip().startswith('output'):
1944 return False
1945 if line.startswith('change') and line[6:].strip().startswith('multicore'):
1946 split_line = line.split()
1947 if len(split_line) > 2:
1948 multicore = bool(split_line[2])
1949
1950
1951 lines = [line[6:].strip() for line in lines if line.startswith('change')]
1952 for line in lines:
1953 if line.startswith(('process','model','output', 'rwgt_dir')):
1954 return False
1955 elif line.startswith('multicore'):
1956 split_line = line.split()
1957 if len(split_line) > 1:
1958 multicore = bool(split_line[1])
1959
1960 return multicore
1961
1962
1963
1964 if '-from_cards' in line and not os.path.exists(pjoin(self.me_dir, 'Cards', 'reweight_card.dat')):
1965 return
1966
1967 if '--multicore=create' in line:
1968 multicore='create'
1969 elif '--multicore=wait' in line:
1970 multicore='wait'
1971 else:
1972 multicore=False
1973
1974
1975 plugin = False
1976 if '--plugin=' in line:
1977 plugin = [l.split('=',1)[1] for l in line.split() if '--plugin=' in l][0]
1978 elif hasattr(self, 'switch') and self.switch['reweight'] not in ['ON','OFF']:
1979 plugin=self.switch['reweight']
1980
1981
1982
1983
1984 if MADEVENT and not self.options['mg5_path']:
1985 raise self.InvalidCmd('''The module reweight requires that MG5 is installed on the system.
1986 You can install it and set its path in ./Cards/me5_configuration.txt''')
1987 elif MADEVENT:
1988 sys.path.append(self.options['mg5_path'])
1989 try:
1990 import madgraph.interface.reweight_interface as reweight_interface
1991 except ImportError:
1992 raise self.ConfigurationError('''Can\'t load Reweight module.
1993 The variable mg5_path might not be correctly configured.''')
1994
1995
1996
1997 if not '-from_cards' in line:
1998 self.keep_cards(['reweight_card.dat'], ignore=['*'])
1999 self.ask_edit_cards(['reweight_card.dat'], 'fixed', plot=False)
2000
2001
2002 args = self.split_arg(line)
2003 if plugin and '--plugin=' not in line:
2004 args.append('--plugin=%s' % plugin)
2005
2006
2007 if not self.force_run:
2008
2009 if self.run_name and self.results.current and self.results.current['cross'] == 0:
2010 self.results.delete_run(self.run_name, self.run_tag)
2011 self.results.save()
2012
2013 if not hasattr(self, 'run_card'):
2014 self.run_card = banner_mod.RunCard(pjoin(self.me_dir, 'Cards', 'run_card.dat'))
2015
2016
2017 command = [sys.executable]
2018 if os.path.exists(pjoin(self.me_dir, 'bin', 'madevent')):
2019 command.append(pjoin(self.me_dir, 'bin', 'internal','madevent_interface.py'))
2020 else:
2021 command.append(pjoin(self.me_dir, 'bin', 'internal', 'amcatnlo_run_interface.py'))
2022 if not isinstance(self, cmd.CmdShell):
2023 command.append('--web')
2024 command.append('reweight')
2025
2026
2027 if self.options['nb_core']==1 or self.run_card['nevents'] < 101 or not check_multicore(self):
2028 if self.run_name:
2029 command.append(self.run_name)
2030 else:
2031 command += args
2032 if '-from_cards' not in command:
2033 command.append('-from_cards')
2034 p = misc.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, cwd=os.getcwd())
2035 while p.poll() is None:
2036 line = p.stdout.readline().decode()
2037 if any(t in line for t in ['INFO:', 'WARNING:', 'CRITICAL:', 'ERROR:', 'root:','KEEP:']) and \
2038 not '***********' in line:
2039 print(line[:-1].replace('INFO', 'REWEIGHT').replace('KEEP:',''))
2040 elif __debug__ and line:
2041 logger.debug(line[:-1])
2042 if p.returncode !=0:
2043 logger.error("Reweighting failed")
2044 return
2045 self.results = self.load_results_db()
2046
2047 try:
2048 if self.results[self.run_name][-2]['cross']==0:
2049 self.results.delete_run(self.run_name,self.results[self.run_name][-2]['tag'])
2050 except:
2051 pass
2052 try:
2053 if self.results.current['cross'] == 0 and self.run_name:
2054 self.results.delete_run(self.run_name, self.run_tag)
2055 except:
2056 pass
2057
2058 try:
2059 self.results.def_current(self.run_name, self.run_tag)
2060 except Exception:
2061 pass
2062 return
2063
2064 else:
2065
2066 if not isinstance(self.cluster, cluster.MultiCore):
2067 mycluster = cluster.MultiCore(nb_core=self.options['nb_core'])
2068 else:
2069 mycluster = self.cluster
2070
2071 new_args=list(args)
2072 self.check_decay_events(new_args)
2073 try:
2074 os.remove(pjoin(self.me_dir,'rw_me','rwgt.pkl'))
2075 except Exception as error:
2076 pass
2077
2078 import madgraph.various.lhe_parser as lhe_parser
2079
2080 if 'nevt_job' in self.run_card and self.run_card['nevt_job'] !=-1:
2081 nevt_job = self.run_card['nevt_job']
2082 else:
2083 nevt_job = max(2500, self.run_card['nevents']/self.options['nb_core'])
2084 logger.info("split the event file in bunch of %s events" % nevt_job)
2085 nb_file = lhe_parser.EventFile(new_args[0]).split(nevt_job)
2086 starttime = time.time()
2087 update_status = lambda idle, run, finish: \
2088 self.update_status((idle, run, finish, 'reweight'), level=None,
2089 force=False, starttime=starttime)
2090
2091 all_lhe = []
2092
2093 to_zip=True
2094 if not os.path.exists(new_args[0]) and new_args[0].endswith('.gz') and\
2095 os.path.exists(new_args[0][:-3]):
2096 to_zip = False
2097 devnull= open(os.devnull)
2098
2099 for i in range(nb_file):
2100 new_command = list(command)
2101 if to_zip:
2102 new_command.append('%s_%s.lhe' % (new_args[0],i))
2103 all_lhe.append('%s_%s.lhe' % (new_args[0],i))
2104 else:
2105 new_command.append('%s_%s.lhe' % (new_args[0][:-3],i))
2106 all_lhe.append('%s_%s.lhe' % (new_args[0][:-3],i))
2107
2108 if '-from_cards' not in command:
2109 new_command.append('-from_cards')
2110 if plugin:
2111 new_command.append('--plugin=%s' % plugin)
2112 if i==0:
2113 if __debug__:
2114 stdout = None
2115 else:
2116 stdout = open(pjoin(self.me_dir,'Events', self.run_name, 'reweight.log'),'w')
2117 new_command.append('--multicore=create')
2118 else:
2119 stdout = devnull
2120 if six.PY3:
2121 stdout = subprocess.DEVNULL
2122
2123 new_command.append('--multicore=wait')
2124 mycluster.submit(prog=command[0], argument=new_command[1:], stdout=stdout, cwd=os.getcwd())
2125 mycluster.wait(self.me_dir,update_status)
2126 devnull.close()
2127 logger.info("Collect and combine the various output file.")
2128
2129 lhe = lhe_parser.MultiEventFile(all_lhe, parse=False)
2130 nb_event, cross_sections = lhe.write(new_args[0], get_info=True)
2131 if any(os.path.exists('%s_%s_debug.log' % (f, self.run_tag)) for f in all_lhe):
2132 for f in all_lhe:
2133 if os.path.exists('%s_%s_debug.log' % (f, self.run_tag)):
2134 raise Exception("Some of the run failed: Please read %s_%s_debug.log" % (f, self.run_tag))
2135
2136
2137 if 'event_norm' in self.run_card and self.run_card['event_norm'] in ['average','bias']:
2138 for key, value in cross_sections.items():
2139 cross_sections[key] = value / (nb_event+1)
2140 lhe.remove()
2141 for key in cross_sections:
2142 if key == 'orig' or key.isdigit():
2143 continue
2144 logger.info('%s : %s pb' % (key, cross_sections[key]))
2145 return
2146
2147
2148
2149 self.to_store.append('event')
2150
2151 if not self.force_run and self.results.current['cross'] == 0 and self.run_name:
2152 self.results.delete_run(self.run_name, self.run_tag)
2153
2154 self.check_decay_events(args)
2155
2156 rwgt_interface = reweight_interface.ReweightInterface
2157 if plugin:
2158 rwgt_interface = misc.from_plugin_import(self.plugin_path, 'new_reweight',
2159 plugin, warning=False,
2160 info="Will use re-weighting from pluging %(plug)s")
2161
2162 reweight_cmd = rwgt_interface(args[0], mother=self)
2163
2164
2165 wgt_names = reweight_cmd.get_weight_names()
2166 if wgt_names == [''] and reweight_cmd.has_nlo:
2167 self.update_status('Running Reweighting (LO approximate)', level='madspin')
2168 else:
2169 self.update_status('Running Reweighting', level='madspin')
2170
2171 path = pjoin(self.me_dir, 'Cards', 'reweight_card.dat')
2172 reweight_cmd.raw_input=False
2173 reweight_cmd.me_dir = self.me_dir
2174 reweight_cmd.multicore = multicore
2175 reweight_cmd.import_command_file(path)
2176 reweight_cmd.do_quit('')
2177
2178 logger.info("quit rwgt")
2179
2180
2181
2182
2183 try:
2184 self.results.def_current(self.run_name, self.run_tag)
2185 except Exception:
2186 pass
2187
2188
2190 """launch pgs"""
2191
2192 args = self.split_arg(line)
2193
2194 if '--no_default' in args:
2195 no_default = True
2196 args.remove('--no_default')
2197 else:
2198 no_default = False
2199
2200 if no_default and not os.path.exists(pjoin(self.me_dir, 'Cards', 'pgs_card.dat')):
2201 logger.info('No pgs_card detected, so not run pgs')
2202 return
2203
2204
2205
2206
2207
2208
2209 lock = self.check_pgs(args, no_default=no_default)
2210
2211
2212 if not os.path.exists(pjoin(self.me_dir, 'Cards', 'pgs_card.dat')):
2213 files.cp(pjoin(self.me_dir, 'Cards', 'pgs_card_default.dat'),
2214 pjoin(self.me_dir, 'Cards', 'pgs_card.dat'))
2215 logger.info('No pgs card found. Take the default one.')
2216
2217 if not (no_default or self.force):
2218 self.ask_edit_cards(['pgs_card.dat'])
2219
2220 self.update_status('prepare PGS run', level=None)
2221
2222 pgsdir = pjoin(self.options['pythia-pgs_path'], 'src')
2223 eradir = self.options['exrootanalysis_path']
2224 madir = self.options['madanalysis_path']
2225 td = self.options['td_path']
2226
2227
2228 if not misc.is_executable(pjoin(pgsdir, 'pgs')):
2229 logger.info('No PGS executable -- running make')
2230 misc.compile(cwd=pgsdir)
2231
2232 self.update_status('Running PGS', level='pgs')
2233
2234 tag = self.run_tag
2235
2236 banner_path = pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, self.run_tag))
2237 if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')):
2238 self.banner.add(pjoin(self.me_dir, 'Cards','pgs_card.dat'))
2239 self.banner.write(banner_path)
2240 else:
2241 open(banner_path, 'w').close()
2242
2243
2244
2245
2246 if lock:
2247 lock.wait()
2248
2249 ff = open(pjoin(self.me_dir, 'Events', 'pgs_events.lhco'), 'w')
2250 if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')):
2251 text = open(banner_path).read()
2252 text = '#%s' % text.replace('\n','\n#')
2253 dico = self.results[self.run_name].get_current_info()
2254 text +='\n## Integrated weight (pb) : %.4g' % dico['cross']
2255 text +='\n## Number of Event : %s\n' % dico['nb_event']
2256 ff.writelines(text)
2257 ff.close()
2258
2259 try:
2260 os.remove(pjoin(self.me_dir, 'Events', 'pgs.done'))
2261 except Exception:
2262 pass
2263
2264 pgs_log = pjoin(self.me_dir, 'Events', self.run_name, "%s_pgs.log" % tag)
2265 self.cluster.launch_and_wait('../bin/internal/run_pgs',
2266 argument=[pgsdir], cwd=pjoin(self.me_dir,'Events'),
2267 stdout=pgs_log, stderr=subprocess.STDOUT)
2268
2269 if not os.path.exists(pjoin(self.me_dir, 'Events', 'pgs.done')):
2270 logger.error('Fail to create LHCO events')
2271 return
2272 else:
2273 os.remove(pjoin(self.me_dir, 'Events', 'pgs.done'))
2274
2275 if os.path.getsize(banner_path) == os.path.getsize(pjoin(self.me_dir, 'Events','pgs_events.lhco')):
2276 misc.call(['cat pgs_uncleaned_events.lhco >> pgs_events.lhco'],
2277 cwd=pjoin(self.me_dir, 'Events'))
2278 os.remove(pjoin(self.me_dir, 'Events', 'pgs_uncleaned_events.lhco '))
2279
2280
2281 if eradir and misc.is_executable(pjoin(eradir, 'ExRootLHCOlympicsConverter')):
2282 self.update_status('Creating PGS Root File', level='pgs')
2283 try:
2284 misc.call([eradir+'/ExRootLHCOlympicsConverter',
2285 'pgs_events.lhco',pjoin('%s/%s_pgs_events.root' % (self.run_name, tag))],
2286 cwd=pjoin(self.me_dir, 'Events'))
2287 except Exception:
2288 logger.warning('fail to produce Root output [problem with ExRootAnalysis')
2289 if os.path.exists(pjoin(self.me_dir, 'Events', 'pgs_events.lhco')):
2290
2291 files.mv(pjoin(self.me_dir, 'Events', 'pgs_events.lhco'),
2292 pjoin(self.me_dir, 'Events', self.run_name, '%s_pgs_events.lhco' % tag))
2293 self.create_plot('PGS')
2294 misc.gzip(pjoin(self.me_dir, 'Events', self.run_name, '%s_pgs_events.lhco' % tag))
2295
2296 self.update_status('finish', level='pgs', makehtml=False)
2297
2298
2300 """Require MG5 directory: Compute automatically the widths of a set
2301 of particles"""
2302
2303 args = self.split_arg(line)
2304 opts = self.check_compute_widths(args)
2305
2306 from madgraph.interface.master_interface import MasterCmd
2307 cmd = MasterCmd()
2308 self.define_child_cmd_interface(cmd, interface=False)
2309 cmd.options.update(self.options)
2310 cmd.exec_cmd('set automatic_html_opening False --no_save')
2311 if not opts['path']:
2312 opts['path'] = pjoin(self.me_dir, 'Cards', 'param_card.dat')
2313 if not opts['force'] :
2314 self.ask_edit_cards(['param_card.dat'],[], plot=False)
2315
2316
2317 line = 'compute_widths %s %s' % \
2318 (' '.join([str(i) for i in opts['particles']]),
2319 ' '.join('--%s=%s' % (key,value) for (key,value) in opts.items()
2320 if key not in ['model', 'force', 'particles'] and value))
2321 out = cmd.exec_cmd(line, model=opts['model'])
2322
2323
2324 self.child = None
2325 del cmd
2326 return out
2327
2328
2329
2330
2332 """Not in help:Print the cross-section/ number of events for a given run"""
2333
2334 args = self.split_arg(line)
2335 options={'path':None, 'mode':'w', 'format':'full'}
2336 for arg in list(args):
2337 if arg.startswith('--') and '=' in arg:
2338 name,value=arg.split('=',1)
2339 name = name [2:]
2340 options[name] = value
2341 args.remove(arg)
2342
2343
2344 if len(args) > 0:
2345 run_name = args[0]
2346 else:
2347 for i, run_name in enumerate(self.results.order):
2348 for j, one_result in enumerate(self.results[run_name]):
2349 if i or j:
2350 options['mode'] = "a"
2351 if options['path']:
2352 self.print_results_in_file(one_result, options['path'], options['mode'], options['format'])
2353 else:
2354 self.print_results_in_shell(one_result)
2355 return
2356
2357 if run_name not in self.results:
2358 raise self.InvalidCmd('%s is not a valid run_name or it doesn\'t have any information' \
2359 % run_name)
2360
2361
2362 if len(args) == 2:
2363 tag = args[1]
2364 if tag.isdigit():
2365 tag = int(tag) - 1
2366 if len(self.results[run_name]) < tag:
2367 raise self.InvalidCmd('Only %s different tag available' % \
2368 len(self.results[run_name]))
2369 data = self.results[run_name][tag]
2370 else:
2371 data = self.results[run_name].return_tag(tag)
2372 else:
2373 data = self.results[run_name].return_tag(None)
2374
2375 if options['path']:
2376 self.print_results_in_file(data, options['path'], options['mode'], options['format'])
2377 else:
2378 self.print_results_in_shell(data)
2379
2384
2385
2386
2387
2388
2389 @staticmethod
2390 - def runMA5(MA5_interpreter, MA5_cmds, MA5_runtag, logfile_path, advertise_log=True):
2391 """ Run MA5 in a controlled environnment."""
2392 successfull_MA5_run = True
2393
2394 try:
2395
2396 MA5_logger = None
2397 MA5_logger = logging.getLogger('MA5')
2398 BackUp_MA5_handlers = MA5_logger.handlers
2399 for handler in BackUp_MA5_handlers:
2400 MA5_logger.removeHandler(handler)
2401 file_handler = logging.FileHandler(logfile_path)
2402 MA5_logger.addHandler(file_handler)
2403 if advertise_log:
2404 logger.info("Follow Madanalysis5 run with the following command in a separate terminal:")
2405 logger.info(' tail -f %s'%logfile_path)
2406
2407 with misc.stdchannel_redirected(sys.stdout, os.devnull):
2408 with misc.stdchannel_redirected(sys.stderr, os.devnull):
2409 MA5_interpreter.print_banner()
2410 MA5_interpreter.load(MA5_cmds)
2411 except Exception as e:
2412 logger.warning("MadAnalysis5 failed to run the commands for task "+
2413 "'%s'. Madanalys5 analysis will be skipped."%MA5_runtag)
2414 error=StringIO.StringIO()
2415 traceback.print_exc(file=error)
2416 logger.debug('MadAnalysis5 error was:')
2417 logger.debug('-'*60)
2418 logger.debug(error.getvalue()[:-1])
2419 logger.debug('-'*60)
2420 successfull_MA5_run = False
2421 finally:
2422 if not MA5_logger is None:
2423 for handler in MA5_logger.handlers:
2424 MA5_logger.removeHandler(handler)
2425 for handler in BackUp_MA5_handlers:
2426 MA5_logger.addHandler(handler)
2427
2428 return successfull_MA5_run
2429
2430
2431
2432
2433 @staticmethod
2437 """ Makes sure to correctly setup paths and constructs and return an MA5 path"""
2438
2439 MA5path = os.path.normpath(pjoin(mg5_path,ma5_path))
2440
2441 if MA5path is None or not os.path.isfile(pjoin(MA5path,'bin','ma5')):
2442 return None
2443 if MA5path not in sys.path:
2444 sys.path.insert(0, MA5path)
2445
2446 try:
2447
2448
2449 import readline
2450 old_completer = readline.get_completer()
2451 old_delims = readline.get_completer_delims()
2452 old_history = [readline.get_history_item(i) for i in range(1,readline.get_current_history_length()+1)]
2453 except ImportError:
2454 old_completer, old_delims, old_history = None, None, None
2455 try:
2456 from madanalysis.interpreter.ma5_interpreter import MA5Interpreter
2457 with misc.stdchannel_redirected(sys.stdout, os.devnull):
2458 with misc.stdchannel_redirected(sys.stderr, os.devnull):
2459 MA5_interpreter = MA5Interpreter(MA5path, LoggerLevel=loglevel,
2460 LoggerStream=logstream,forced=forced,
2461 no_compilation=not compilation)
2462 except Exception as e:
2463 if six.PY3 and not __debug__:
2464 logger.info('MadAnalysis5 instalation not python3 compatible')
2465 return None
2466 logger.warning('MadAnalysis5 failed to start so that MA5 analysis will be skipped.')
2467 error=StringIO.StringIO()
2468 traceback.print_exc(file=error)
2469 logger.debug('MadAnalysis5 error was:')
2470 logger.debug('-'*60)
2471 logger.debug(error.getvalue()[:-1])
2472 logger.debug('-'*60)
2473 MA5_interpreter = None
2474 finally:
2475
2476 if not old_history is None:
2477 readline.clear_history()
2478 for line in old_history:
2479 readline.add_history(line)
2480 if not old_completer is None:
2481 readline.set_completer(old_completer)
2482 if not old_delims is None:
2483 readline.set_completer_delims(old_delims)
2484
2485
2486 if not mg5_interface is None and any(not elem is None for elem in [old_completer, old_delims, old_history]):
2487 mg5_interface.set_readline_completion_display_matches_hook()
2488
2489 return MA5_interpreter
2490
2492 """Check the argument for the madanalysis5 command
2493 syntax: madanalysis5_parton [NAME]
2494 """
2495
2496 MA5_options = {'MA5_stdout_lvl':'default'}
2497
2498 stdout_level_tags = [a for a in args if a.startswith('--MA5_stdout_lvl=')]
2499 for slt in stdout_level_tags:
2500 lvl = slt.split('=')[1].strip()
2501 try:
2502
2503 MA5_options['MA5_stdout_lvl']=int(lvl)
2504 except ValueError:
2505 if lvl.startswith('logging.'):
2506 lvl = lvl[8:]
2507 try:
2508 MA5_options['MA5_stdout_lvl'] = getattr(logging, lvl)
2509 except:
2510 raise InvalidCmd("MA5 output level specification"+\
2511 " '%s' is incorrect." % str(lvl))
2512 args.remove(slt)
2513
2514 if mode=='parton':
2515
2516
2517 MA5_options['inputs'] = '*.lhe'
2518 elif mode=='hadron':
2519
2520
2521
2522 MA5_options['inputs'] = ['fromCard']
2523 else:
2524 raise MadGraph5Error('Mode %s not reckognized'%mode+
2525 ' in function check_madanalysis5.')
2526
2527 if not self.options['madanalysis5_path']:
2528 logger.info('Now trying to read the configuration file again'+
2529 ' to find MadAnalysis5 path')
2530 self.set_configuration()
2531
2532 if not self.options['madanalysis5_path'] or not \
2533 os.path.exists(pjoin(self.options['madanalysis5_path'],'bin','ma5')):
2534 error_msg = 'No valid MadAnalysis5 path set.\n'
2535 error_msg += 'Please use the set command to define the path and retry.\n'
2536 error_msg += 'You can also define it in the configuration file.\n'
2537 error_msg += 'Finally, it can be installed automatically using the'
2538 error_msg += ' install command.\n'
2539 raise self.InvalidCmd(error_msg)
2540
2541
2542 if not os.path.isfile(pjoin(self.me_dir,
2543 'Cards','madanalysis5_%s_card.dat'%mode)):
2544 raise self.InvalidCmd('Your installed version of MadAnalysis5 and/or'+\
2545 ' MadGraph5_aMCatNLO does not seem to support analysis at'+
2546 '%s level.'%mode)
2547
2548 tag = [a for a in args if a.startswith('--tag=')]
2549 if tag:
2550 args.remove(tag[0])
2551 tag = tag[0][6:]
2552
2553 if len(args) == 0 and not self.run_name:
2554 if self.results.lastrun:
2555 args.insert(0, self.results.lastrun)
2556 else:
2557 raise self.InvalidCmd('No run name currently defined. '+
2558 'Please add this information.')
2559
2560 if len(args) >= 1:
2561 if mode=='parton' and args[0] != self.run_name and \
2562 not os.path.exists(pjoin(self.me_dir,'Events',args[0],
2563 'unweighted_events.lhe.gz')) and not os.path.exists(
2564 pjoin(self.me_dir,'Events',args[0])):
2565 raise self.InvalidCmd('No events file in the %s run.'%args[0])
2566 self.set_run_name(args[0], tag, level='madanalysis5_%s'%mode)
2567 else:
2568 if tag:
2569 self.run_card['run_tag'] = args[0]
2570 self.set_run_name(self.run_name, tag, level='madanalysis5_%s'%mode)
2571
2572 if mode=='parton':
2573 if any(t for t in args if t.startswith('--input=')):
2574 raise InvalidCmd('The option --input=<input_file> is not'+
2575 ' available when running partonic MadAnalysis5 analysis. The'+
2576 ' .lhe output of the selected run is used automatically.')
2577 input_file = pjoin(self.me_dir,'Events',self.run_name, 'unweighted_events.lhe')
2578 MA5_options['inputs'] = '%s.gz'%input_file
2579 if not os.path.exists('%s.gz'%input_file):
2580 if os.path.exists(input_file):
2581 misc.gzip(input_file, stdout='%s.gz' % input_file)
2582 else:
2583 logger.warning("LHE event file not found in \n%s\ns"%input_file+
2584 "Parton-level MA5 analysis will be skipped.")
2585
2586 if mode=='hadron':
2587
2588
2589 self.store_result()
2590
2591 hadron_tag = [t for t in args if t.startswith('--input=')]
2592 if hadron_tag and hadron_tag[0][8:]:
2593 hadron_inputs = hadron_tag[0][8:].split(',')
2594
2595
2596 elif MA5_options['inputs'] == ['fromCard']:
2597 hadron_inputs = banner_mod.MadAnalysis5Card(pjoin(self.me_dir,
2598 'Cards','madanalysis5_hadron_card.dat'),mode='hadron')['inputs']
2599
2600
2601
2602 MA5_options['inputs'] = []
2603 special_source_tags = []
2604 for htag in hadron_inputs:
2605
2606 if htag in special_source_tags:
2607
2608 continue
2609
2610 if os.path.isfile(htag) or (os.path.exists(htag) and
2611 stat.S_ISFIFO(os.stat(htag).st_mode)):
2612 MA5_options['inputs'].append(htag)
2613 continue
2614
2615
2616
2617 file_candidates = misc.glob(htag, pjoin(self.me_dir,'Events',self.run_name))+\
2618 misc.glob('%s.gz'%htag, pjoin(self.me_dir,'Events',self.run_name))
2619 priority_files = [f for f in file_candidates if
2620 self.run_card['run_tag'] in os.path.basename(f)]
2621 priority_files = [f for f in priority_files if
2622 'EVENTS' in os.path.basename(f).upper()]
2623
2624 for f in file_candidates:
2625 if os.path.basename(f).startswith('unweighted_events.lhe'):
2626 priority_files.append(f)
2627 if priority_files:
2628 MA5_options['inputs'].append(priority_files[-1])
2629 continue
2630 if file_candidates:
2631 MA5_options['inputs'].append(file_candidates[-1])
2632 continue
2633
2634 return MA5_options
2635
2637 """Ask the question when launching madanalysis5.
2638 In the future we can ask here further question about the MA5 run, but
2639 for now we just edit the cards"""
2640
2641 cards = ['madanalysis5_%s_card.dat'%runtype]
2642 self.keep_cards(cards)
2643
2644 if self.force:
2645 return runtype
2646
2647
2648
2649 auto=False
2650 if mode=='auto':
2651 auto=True
2652 if auto:
2653 self.ask_edit_cards(cards, mode='auto', plot=False)
2654 else:
2655 self.ask_edit_cards(cards, plot=False)
2656
2657
2658
2659 mode = runtype
2660 return mode
2661
2663 "Complete the madanalysis5 command"
2664 args = self.split_arg(line[0:begidx], error=False)
2665 if len(args) == 1:
2666
2667 data = []
2668 for name in banner_mod.MadAnalysis5Card._default_hadron_inputs:
2669 data += misc.glob(pjoin('*','%s'%name), pjoin(self.me_dir, 'Events'))
2670 data += misc.glob(pjoin('*','%s.gz'%name), pjoin(self.me_dir, 'Events'))
2671 data = [n.rsplit('/',2)[1] for n in data]
2672 tmp1 = self.list_completion(text, data)
2673 if not self.run_name:
2674 return tmp1
2675 else:
2676 tmp2 = self.list_completion(text, ['-f',
2677 '--MA5_stdout_lvl=','--input=','--no_default', '--tag='], line)
2678 return tmp1 + tmp2
2679
2680 elif '--MA5_stdout_lvl=' in line and not any(arg.startswith(
2681 '--MA5_stdout_lvl=') for arg in args):
2682 return self.list_completion(text,
2683 ['--MA5_stdout_lvl=%s'%opt for opt in
2684 ['logging.INFO','logging.DEBUG','logging.WARNING',
2685 'logging.CRITICAL','90']], line)
2686 elif '--input=' in line and not any(arg.startswith(
2687 '--input=') for arg in args):
2688 return self.list_completion(text, ['--input=%s'%opt for opt in
2689 (banner_mod.MadAnalysis5Card._default_hadron_inputs +['path'])], line)
2690 else:
2691 return self.list_completion(text, ['-f',
2692 '--MA5_stdout_lvl=','--input=','--no_default', '--tag='], line)
2693
2695 """launch MadAnalysis5 at the hadron level."""
2696 return self.run_madanalysis5(line,mode='hadron')
2697
2699 """launch MadAnalysis5 at the parton level or at the hadron level with
2700 a specific command line."""
2701
2702
2703 args = self.split_arg(line)
2704
2705 if '--no_default' in args:
2706 no_default = True
2707 args.remove('--no_default')
2708 else:
2709 no_default = False
2710
2711 if no_default:
2712
2713 if mode=='parton' and not os.path.exists(pjoin(self.me_dir, 'Cards',
2714 'madanalysis5_parton_card.dat')):
2715 return
2716 if mode=='hadron' and not os.path.exists(pjoin(self.me_dir, 'Cards',
2717 'madanalysis5_hadron_card.dat')):
2718 return
2719 else:
2720
2721
2722 self.ask_madanalysis5_run_configuration(runtype=mode)
2723
2724 if not self.options['madanalysis5_path'] or \
2725 all(not os.path.exists(pjoin(self.me_dir, 'Cards',card)) for card in
2726 ['madanalysis5_parton_card.dat','madanalysis5_hadron_card.dat']):
2727 if no_default:
2728 return
2729 else:
2730 raise InvalidCmd('You must have MadAnalysis5 available to run'+
2731 " this command. Consider installing it with the 'install' function.")
2732
2733 if not self.run_name:
2734 MA5_opts = self.check_madanalysis5(args, mode=mode)
2735 self.configure_directory(html_opening =False)
2736 else:
2737
2738 self.configure_directory(html_opening =False)
2739 MA5_opts = self.check_madanalysis5(args, mode=mode)
2740
2741
2742 if MA5_opts['inputs']==[]:
2743 if no_default:
2744 logger.warning('No hadron level input found to run MadAnalysis5 on.'+
2745 ' Skipping its hadron-level analysis.')
2746 return
2747 else:
2748 raise self.InvalidCmd('\nNo input files specified or availabled for'+
2749 ' this MadAnalysis5 hadron-level run.\nPlease double-check the options of this'+
2750 ' MA5 command (or card) and which output files\nare currently in the chosen'+
2751 " run directory '%s'."%self.run_name)
2752
2753 MA5_card = banner_mod.MadAnalysis5Card(pjoin(self.me_dir, 'Cards',
2754 'madanalysis5_%s_card.dat'%mode), mode=mode)
2755
2756 if MA5_card._skip_analysis:
2757 logger.info('Madanalysis5 %s-level analysis was skipped following user request.'%mode)
2758 logger.info("To run the analysis, remove or comment the tag '%s skip_analysis' "
2759 %banner_mod.MadAnalysis5Card._MG5aMC_escape_tag+
2760 "in\n '%s'."%pjoin(self.me_dir, 'Cards','madanalysis5_%s_card.dat'%mode))
2761 return
2762
2763 MA5_cmds_list = MA5_card.get_MA5_cmds(MA5_opts['inputs'],
2764 pjoin(self.me_dir,'MA5_%s_ANALYSIS'%mode.upper()),
2765 run_dir_path = pjoin(self.me_dir,'Events', self.run_name),
2766 UFO_model_path=pjoin(self.me_dir,'bin','internal','ufomodel'),
2767 run_tag = self.run_tag)
2768
2769
2770
2771
2772
2773
2774
2775
2776 self.update_status('\033[92mRunning MadAnalysis5 [arXiv:1206.1599]\033[0m',
2777 level='madanalysis5_%s'%mode)
2778 if mode=='hadron':
2779 logger.info('Hadron input files considered:')
2780 for input in MA5_opts['inputs']:
2781 logger.info(' --> %s'%input)
2782 elif mode=='parton':
2783 logger.info('Parton input file considered:')
2784 logger.info(' --> %s'%MA5_opts['inputs'])
2785
2786
2787
2788
2789 if MA5_opts['MA5_stdout_lvl']=='default':
2790 if MA5_card['stdout_lvl'] is None:
2791 MA5_lvl = self.options['stdout_level']
2792 else:
2793 MA5_lvl = MA5_card['stdout_lvl']
2794 else:
2795 MA5_lvl = MA5_opts['MA5_stdout_lvl']
2796
2797
2798 MA5_interpreter = CommonRunCmd.get_MadAnalysis5_interpreter(
2799 self.options['mg5_path'],
2800 self.options['madanalysis5_path'],
2801 logstream=sys.stdout,
2802 loglevel=100,
2803 forced=True,
2804 compilation=True)
2805
2806
2807
2808 if MA5_interpreter is None:
2809 return
2810
2811
2812 used_up_fifos = []
2813
2814 for MA5_run_number, (MA5_runtag, MA5_cmds) in enumerate(MA5_cmds_list):
2815
2816
2817
2818 MA5_run_number = 0
2819
2820 MA5_interpreter.setLogLevel(100)
2821
2822 if mode=='hadron':
2823 MA5_interpreter.init_reco()
2824 else:
2825 MA5_interpreter.init_parton()
2826 MA5_interpreter.setLogLevel(MA5_lvl)
2827
2828 if MA5_runtag!='default':
2829 if MA5_runtag.startswith('_reco_'):
2830 logger.info("MadAnalysis5 now running the reconstruction '%s'..."%
2831 MA5_runtag[6:],'$MG:color:GREEN')
2832 elif MA5_runtag=='Recasting':
2833 logger.info("MadAnalysis5 now running the recasting...",
2834 '$MG:color:GREEN')
2835 else:
2836 logger.info("MadAnalysis5 now running the '%s' analysis..."%
2837 MA5_runtag,'$MG:color:GREEN')
2838
2839
2840
2841 if not CommonRunCmd.runMA5(MA5_interpreter, MA5_cmds, MA5_runtag,
2842 pjoin(self.me_dir,'Events',self.run_name,'%s_MA5_%s.log'%(self.run_tag,MA5_runtag))):
2843
2844 return
2845
2846 if MA5_runtag.startswith('_reco_'):
2847
2848
2849
2850
2851 links_created=[]
2852 for i, input in enumerate(MA5_opts['inputs']):
2853
2854
2855 if not banner_mod.MadAnalysis5Card.events_can_be_reconstructed(input):
2856 continue
2857
2858 if input.endswith('.fifo'):
2859 if input in used_up_fifos:
2860
2861 continue
2862 else:
2863 used_up_fifos.append(input)
2864
2865 reco_output = pjoin(self.me_dir,
2866 'MA5_%s_ANALYSIS%s_%d'%(mode.upper(),MA5_runtag,i+1))
2867
2868 reco_event_file = misc.glob('*.lhe.gz',pjoin(reco_output,'Output','SAF','_reco_events','lheEvents0_%d'%MA5_run_number))+\
2869 misc.glob('*.root',pjoin(reco_output,'Output','SAF','_reco_events', 'RecoEvents0_%d'%MA5_run_number))
2870 if len(reco_event_file)==0:
2871 raise MadGraph5Error("MadAnalysis5 failed to produce the "+\
2872 "reconstructed event file for reconstruction '%s'."%MA5_runtag[6:])
2873 reco_event_file = reco_event_file[0]
2874
2875 shutil.move(reco_output,pjoin(self.me_dir,'HTML',
2876 self.run_name,'%s_MA5_%s_ANALYSIS%s_%d'%
2877 (self.run_tag,mode.upper(),MA5_runtag,i+1)))
2878
2879
2880 links_created.append(os.path.basename(reco_event_file))
2881 parent_dir_name = os.path.basename(os.path.dirname(reco_event_file))
2882 files.ln(pjoin(self.me_dir,'HTML',self.run_name,
2883 '%s_MA5_%s_ANALYSIS%s_%d'%(self.run_tag,mode.upper(),
2884 MA5_runtag,i+1),'Output','SAF','_reco_events',parent_dir_name,links_created[-1]),
2885 pjoin(self.me_dir,'Events',self.run_name))
2886
2887 logger.info("MadAnalysis5 successfully completed the reconstruction "+
2888 "'%s'. Links to the reconstructed event files are:"%MA5_runtag[6:])
2889 for link in links_created:
2890 logger.info(' --> %s'%pjoin(self.me_dir,'Events',self.run_name,link))
2891 continue
2892
2893 if MA5_runtag.upper()=='RECASTING':
2894 target = pjoin(self.me_dir,'MA5_%s_ANALYSIS_%s'\
2895 %(mode.upper(),MA5_runtag),'Output','CLs_output_summary.dat')
2896 else:
2897 target = pjoin(self.me_dir,'MA5_%s_ANALYSIS_%s'\
2898 %(mode.upper(),MA5_runtag),'Output','PDF','MadAnalysis5job_%d'%MA5_run_number,'main.pdf')
2899 has_pdf = True
2900 if not os.path.isfile(target):
2901 has_pdf = False
2902
2903
2904 if MA5_runtag.upper()=='RECASTING':
2905 carboncopy_name = '%s_MA5_CLs.dat'%(self.run_tag)
2906 else:
2907 carboncopy_name = '%s_MA5_%s_analysis_%s.pdf'%(
2908 self.run_tag,mode,MA5_runtag)
2909 if has_pdf:
2910 shutil.copy(target, pjoin(self.me_dir,'Events',self.run_name,carboncopy_name))
2911 else:
2912 logger.error('MadAnalysis5 failed to create PDF output')
2913 if MA5_runtag!='default':
2914 logger.info("MadAnalysis5 successfully completed the "+
2915 "%s. Reported results are placed in:"%("analysis '%s'"%MA5_runtag
2916 if MA5_runtag.upper()!='RECASTING' else "recasting"))
2917 else:
2918 logger.info("MadAnalysis5 successfully completed the analysis."+
2919 " Reported results are placed in:")
2920 logger.info(' --> %s'%pjoin(self.me_dir,'Events',self.run_name,carboncopy_name))
2921
2922 anal_dir = pjoin(self.me_dir,'MA5_%s_ANALYSIS_%s' %(mode.upper(),MA5_runtag))
2923 if not os.path.exists(anal_dir):
2924 logger.error('MadAnalysis5 failed to completed succesfully')
2925 return
2926
2927 shutil.move(anal_dir, pjoin(self.me_dir,'HTML',self.run_name,
2928 '%s_MA5_%s_ANALYSIS_%s'%(self.run_tag,mode.upper(),MA5_runtag)))
2929
2930
2931
2932 new_details={}
2933 for detail in ['nb_event','cross','error']:
2934 new_details[detail] = \
2935 self.results[self.run_name].get_current_info()[detail]
2936 for detail in new_details:
2937 self.results.add_detail(detail,new_details[detail])
2938
2939 self.update_status('Finished MA5 analyses.', level='madanalysis5_%s'%mode,
2940 makehtml=False)
2941
2942
2943 self.banner.add(pjoin(self.me_dir, 'Cards',
2944 'madanalysis5_%s_card.dat'%mode))
2945 banner_path = pjoin(self.me_dir,'Events', self.run_name,
2946 '%s_%s_banner.txt'%(self.run_name, self.run_tag))
2947 self.banner.write(banner_path)
2948
2949 if not no_default:
2950 logger.info('Find more information about this run on the HTML local page')
2951 logger.info(' --> %s'%pjoin(self.me_dir,'index.html'))
2952
2953
2954
2955
2956
2958 """ run delphes and make associate root file/plot """
2959
2960 args = self.split_arg(line)
2961
2962 if '--no_default' in args:
2963 no_default = True
2964 args.remove('--no_default')
2965 else:
2966 no_default = False
2967
2968 if no_default and not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')):
2969 logger.info('No delphes_card detected, so not run Delphes')
2970 return
2971
2972
2973 filepath = self.check_delphes(args, nodefault=no_default)
2974 if no_default and not filepath:
2975 return
2976
2977 self.update_status('prepare delphes run', level=None)
2978
2979 if os.path.exists(pjoin(self.options['delphes_path'], 'data')):
2980 delphes3 = False
2981 prog = '../bin/internal/run_delphes'
2982 if filepath and '.hepmc' in filepath[:-10]:
2983 raise self.InvalidCmd('delphes2 do not support hepmc')
2984 else:
2985 delphes3 = True
2986 prog = '../bin/internal/run_delphes3'
2987
2988
2989
2990 if not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_card.dat')):
2991 if no_default:
2992 logger.info('No delphes_card detected, so not running Delphes')
2993 return
2994 files.cp(pjoin(self.me_dir, 'Cards', 'delphes_card_default.dat'),
2995 pjoin(self.me_dir, 'Cards', 'delphes_card.dat'))
2996 logger.info('No delphes card found. Take the default one.')
2997 if not delphes3 and not os.path.exists(pjoin(self.me_dir, 'Cards', 'delphes_trigger.dat')):
2998 files.cp(pjoin(self.me_dir, 'Cards', 'delphes_trigger_default.dat'),
2999 pjoin(self.me_dir, 'Cards', 'delphes_trigger.dat'))
3000 if not (no_default or self.force):
3001 if delphes3:
3002 self.ask_edit_cards(['delphes_card.dat'], args)
3003 else:
3004 self.ask_edit_cards(['delphes_card.dat', 'delphes_trigger.dat'], args)
3005
3006 self.update_status('Running Delphes', level=None)
3007
3008 delphes_dir = self.options['delphes_path']
3009 tag = self.run_tag
3010 if os.path.exists(pjoin(self.me_dir, 'Source', 'banner_header.txt')):
3011 self.banner.add(pjoin(self.me_dir, 'Cards','delphes_card.dat'))
3012 if not delphes3:
3013 self.banner.add(pjoin(self.me_dir, 'Cards','delphes_trigger.dat'))
3014 self.banner.write(pjoin(self.me_dir, 'Events', self.run_name, '%s_%s_banner.txt' % (self.run_name, tag)))
3015
3016 cross = self.results[self.run_name].get_current_info()['cross']
3017
3018 delphes_log = pjoin(self.me_dir, 'Events', self.run_name, "%s_delphes.log" % tag)
3019 if not self.cluster:
3020 clus = cluster.onecore
3021 else:
3022 clus = self.cluster
3023 clus.launch_and_wait(prog,
3024 argument= [delphes_dir, self.run_name, tag, str(cross), filepath],
3025 stdout=delphes_log, stderr=subprocess.STDOUT,
3026 cwd=pjoin(self.me_dir,'Events'))
3027
3028 if not os.path.exists(pjoin(self.me_dir, 'Events',
3029 self.run_name, '%s_delphes_events.lhco.gz' % tag))\
3030 and not os.path.exists(pjoin(self.me_dir, 'Events',
3031 self.run_name, '%s_delphes_events.lhco' % tag)):
3032 logger.info('If you are interested in lhco output. please run root2lhco converter.')
3033 logger.info(' or edit bin/internal/run_delphes3 to run the converter automatically.')
3034
3035
3036
3037 madir = self.options['madanalysis_path']
3038 td = self.options['td_path']
3039
3040 if os.path.exists(pjoin(self.me_dir, 'Events',
3041 self.run_name, '%s_delphes_events.lhco' % tag)):
3042
3043 self.create_plot('Delphes')
3044
3045 if os.path.exists(pjoin(self.me_dir, 'Events', self.run_name, '%s_delphes_events.lhco' % tag)):
3046 misc.gzip(pjoin(self.me_dir, 'Events', self.run_name, '%s_delphes_events.lhco' % tag))
3047
3048 self.update_status('delphes done', level='delphes', makehtml=False)
3049
3050
3051
3053 """Find the pid of all particles in the final and initial states"""
3054 pids = set()
3055 subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses',
3056 'subproc.mg'))]
3057 nb_init = self.ninitial
3058 pat = re.compile(r'''DATA \(IDUP\(I,\d+\),I=1,\d+\)/([\+\-\d,\s]*)/''', re.I)
3059 for Pdir in subproc:
3060 text = open(pjoin(self.me_dir, 'SubProcesses', Pdir, 'born_leshouche.inc')).read()
3061 group = pat.findall(text)
3062 for particles in group:
3063 particles = particles.split(',')
3064 pids.update(set(particles))
3065
3066 return pids
3067
3068
3093
3094
3095 if hasattr(self, 'pdffile') and self.pdffile:
3096 return self.pdffile
3097 else:
3098 for line in open(pjoin(self.me_dir,'Source','PDF','pdf_list.txt')):
3099 data = line.split()
3100 if len(data) < 4:
3101 continue
3102 if data[1].lower() == self.run_card['pdlabel'].lower():
3103 self.pdffile = check_cluster(pjoin(self.me_dir, 'lib', 'Pdfdata', data[2]))
3104 return self.pdffile
3105 else:
3106
3107 path = pjoin(self.me_dir, 'lib', 'PDFsets')
3108 if os.path.exists(path):
3109 self.pdffile = path
3110 else:
3111 self.pdffile = " "
3112 return self.pdffile
3113
3114
3124
3125
3126 - def do_set(self, line, log=True):
3127 """Set an option, which will be default for coming generations/outputs
3128 """
3129
3130
3131
3132 args = self.split_arg(line)
3133
3134 self.check_set(args)
3135
3136 if args[0] in self.options_configuration and '--no_save' not in args:
3137 self.do_save('options --auto')
3138
3139 if args[0] == "stdout_level":
3140 if args[1].isdigit():
3141 logging.root.setLevel(int(args[1]))
3142 logging.getLogger('madgraph').setLevel(int(args[1]))
3143 else:
3144 logging.root.setLevel(eval('logging.' + args[1]))
3145 logging.getLogger('madgraph').setLevel(eval('logging.' + args[1]))
3146 if log: logger.info('set output information to level: %s' % args[1])
3147 elif args[0] == "fortran_compiler":
3148 if args[1] == 'None':
3149 args[1] = None
3150 self.options['fortran_compiler'] = args[1]
3151 current = misc.detect_current_compiler(pjoin(self.me_dir,'Source','make_opts'), 'fortran')
3152 if current != args[1] and args[1] != None:
3153 misc.mod_compilator(self.me_dir, args[1], current, 'gfortran')
3154 elif args[0] == "cpp_compiler":
3155 if args[1] == 'None':
3156 args[1] = None
3157 self.options['cpp_compiler'] = args[1]
3158 current = misc.detect_current_compiler(pjoin(self.me_dir,'Source','make_opts'), 'cpp')
3159 if current != args[1] and args[1] != None:
3160 misc.mod_compilator(self.me_dir, args[1], current, 'cpp')
3161 elif args[0] == "run_mode":
3162 if not args[1] in [0,1,2,'0','1','2']:
3163 raise self.InvalidCmd('run_mode should be 0, 1 or 2.')
3164 self.cluster_mode = int(args[1])
3165 self.options['run_mode'] = self.cluster_mode
3166 elif args[0] in ['cluster_type', 'cluster_queue', 'cluster_temp_path']:
3167 if args[1] == 'None':
3168 args[1] = None
3169 self.options[args[0]] = args[1]
3170
3171
3172 elif args[0] in ['cluster_nb_retry', 'cluster_retry_wait', 'cluster_size']:
3173 self.options[args[0]] = int(args[1])
3174
3175 elif args[0] == 'nb_core':
3176 if args[1] == 'None':
3177 import multiprocessing
3178 self.nb_core = multiprocessing.cpu_count()
3179 self.options['nb_core'] = self.nb_core
3180 return
3181 if not args[1].isdigit():
3182 raise self.InvalidCmd('nb_core should be a positive number')
3183 self.nb_core = int(args[1])
3184 self.options['nb_core'] = self.nb_core
3185 elif args[0] == 'timeout':
3186 self.options[args[0]] = int(args[1])
3187 elif args[0] == 'cluster_status_update':
3188 if '(' in args[1]:
3189 data = ' '.join([a for a in args[1:] if not a.startswith('-')])
3190 data = data.replace('(','').replace(')','').replace(',',' ').split()
3191 first, second = data[:2]
3192 else:
3193 first, second = args[1:3]
3194
3195 self.options[args[0]] = (int(first), int(second))
3196 elif args[0] == 'notification_center':
3197 if args[1] in ['None','True','False']:
3198 self.allow_notification_center = eval(args[1])
3199 self.options[args[0]] = eval(args[1])
3200 else:
3201 raise self.InvalidCmd('Not a valid value for notification_center')
3202
3203 elif args[0] in ['crash_on_error']:
3204 try:
3205 tmp = banner_mod.ConfigFile.format_variable(args[1], bool, 'crash_on_error')
3206 except:
3207 if args[1].lower() in ['never']:
3208 tmp = args[1].lower()
3209 else:
3210 raise
3211 self.options[args[0]] = tmp
3212 elif args[0].startswith('f2py_compiler'):
3213 to_do = True
3214 if args[0].endswith('_py2') and six.PY3:
3215 to_do = False
3216 elif args[0].endswith('_py3') and six.PY2:
3217 to_do = False
3218 if to_do:
3219 if args[1] == 'None':
3220 self.options['f2py_compiler'] = None
3221 else:
3222 logger.info('set f2py compiler to %s' % args[1])
3223 self.options['f2py_compiler'] = args[1]
3224 elif args[0].startswith('lhapdf'):
3225 to_do = True
3226 if args[0].endswith('_py2') and six.PY3:
3227 to_do = False
3228 elif args[0].endswith('_py3') and six.PY2:
3229 to_do = False
3230 if to_do and args[1] != 'None':
3231 self.options['lhapdf'] = args[1]
3232 elif args[0] in self.options:
3233 if args[1] in ['None','True','False']:
3234 self.options[args[0]] = ast.literal_eval(args[1])
3235 elif args[0].endswith('path'):
3236 if os.path.exists(args[1]):
3237 self.options[args[0]] = args[1]
3238 elif os.path.exists(pjoin(self.me_dir, args[1])):
3239 self.options[args[0]] = pjoin(self.me_dir, args[1])
3240 else:
3241 raise self.InvalidCmd('Not a valid path: keep previous value: \'%s\'' % self.options[args[0]])
3242 else:
3243 self.options[args[0]] = args[1]
3244
3245 - def post_set(self, stop, line):
3246 """Check if we need to save this in the option file"""
3247 try:
3248 args = self.split_arg(line)
3249 if 'cluster' in args[0] or args[0] == 'run_mode':
3250 self.configure_run_mode(self.options['run_mode'])
3251
3252
3253
3254 self.check_set(args)
3255
3256 if args[0] in self.options_configuration and '--no_save' not in args:
3257 self.exec_cmd('save options %s --auto' % args[0])
3258 elif args[0] in self.options_madevent:
3259 logger.info('This option will be the default in any output that you are going to create in this session.')
3260 logger.info('In order to keep this changes permanent please run \'save options\'')
3261 return stop
3262 except self.InvalidCmd:
3263 return stop
3264
3305
3307 """
3308 1) Check that no scan parameter are present
3309 2) Check that all the width are define in the param_card.
3310 - If a scan parameter is define. create the iterator and recall this fonction
3311 on the first element.
3312 - If some width are set on 'Auto', call the computation tools.
3313 - Check that no width are too small (raise a warning if this is the case)
3314 3) if dependent is on True check for dependent parameter (automatic for scan)"""
3315
3316 self.static_check_param_card(path, self, run=run, dependent=dependent)
3317
3318 card = param_card_mod.ParamCard(path)
3319 for param in card['decay']:
3320 width = param.value
3321 if width == 0:
3322 continue
3323 try:
3324 mass = card['mass'].get(param.lhacode).value
3325 except Exception:
3326 continue
3327
3328
3329
3330 @staticmethod
3333 pattern_scan = re.compile(r'''^(decay)?[\s\d]*scan''', re.I+re.M)
3334 pattern_width = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I)
3335 text = open(path).read()
3336
3337 if pattern_scan.search(text):
3338 if not isinstance(interface, cmd.CmdShell):
3339
3340 raise Exception("Scan are not allowed in web mode")
3341
3342 main_card = iterator_class(text)
3343 interface.param_card_iterator = main_card
3344 first_card = main_card.next(autostart=True)
3345 first_card.write(path)
3346 return CommonRunCmd.static_check_param_card(path, interface, run, dependent=True)
3347
3348 pdg_info = pattern_width.findall(text)
3349 if pdg_info:
3350 if run:
3351 logger.info('Computing the width set on auto in the param_card.dat')
3352 has_nlo = any(nlo.lower()=="@nlo" for _,nlo in pdg_info)
3353 pdg = [pdg for pdg,nlo in pdg_info]
3354 if not has_nlo:
3355 line = '%s' % (' '.join(pdg))
3356 else:
3357 line = '%s --nlo' % (' '.join(pdg))
3358 CommonRunCmd.static_compute_widths(line, interface, path)
3359 else:
3360 logger.info('''Some width are on Auto in the card.
3361 Those will be computed as soon as you have finish the edition of the cards.
3362 If you want to force the computation right now and being able to re-edit
3363 the cards afterwards, you can type \"compute_wdiths\".''')
3364
3365 card = param_card_mod.ParamCard(path)
3366 if dependent:
3367 AskforEditCard.update_dependent(interface, interface.me_dir, card, path, timer=20)
3368
3369 for param in card['decay']:
3370 width = param.value
3371 if width == 0:
3372 continue
3373 try:
3374 mass = card['mass'].get(param.lhacode).value
3375 except Exception:
3376 logger.warning('Missing mass in the lhef file (%s) . Please fix this (use the "update missing" command if needed)', param.lhacode[0])
3377 continue
3378 if mass and abs(width/mass) < 1e-12:
3379 if hasattr(interface, 'run_card') and isinstance(interface.run_card, banner_mod.RunCardLO):
3380 if interface.run_card['small_width_treatment'] < 1e-12:
3381 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)
3382 else:
3383 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)
3384 if CommonRunCmd.sleep_for_error:
3385 time.sleep(5)
3386 CommonRunCmd.sleep_for_error = False
3387 elif not mass and width:
3388 logger.error('The width of particle %s is different of zero for a massless particle.', param.lhacode[0])
3389 if CommonRunCmd.sleep_for_error:
3390 time.sleep(5)
3391 CommonRunCmd.sleep_for_error = False
3392 return
3393
3394 @staticmethod
3396 """ factory to try to find a way to call the static method"""
3397
3398 handled = True
3399 if isinstance(interface, CommonRunCmd):
3400 if path:
3401 line = '%s %s' % (line, path)
3402 interface.do_compute_widths(line)
3403 else:
3404 handled = False
3405
3406 if handled:
3407 return
3408
3409 if hasattr(interface, 'do_compute_width'):
3410 interface.do_compute_widths('%s --path=%s' % (line, path))
3411 elif hasattr(interface, 'mother') and interface.mother and isinstance(interface, CommonRunCmd):
3412 return CommonRunCmd.static_compute_width(line, interface.mother, path)
3413 elif not MADEVENT:
3414 from madgraph.interface.master_interface import MasterCmd
3415 cmd = MasterCmd()
3416 interface.define_child_cmd_interface(cmd, interface=False)
3417 if hasattr(interface, 'options'):
3418 cmd.options.update(interface.options)
3419 try:
3420 cmd.exec_cmd('set automatic_html_opening False --no_save')
3421 except Exception:
3422 pass
3423
3424 model = interface.get_model()
3425
3426
3427 line = 'compute_widths %s --path=%s' % (line, path)
3428 cmd.exec_cmd(line, model=model)
3429 interface.child = None
3430 del cmd
3431 return
3432
3433
3434
3435 raise Exception('fail to find a way to handle Auto width')
3436
3437
3439 """return the information that need to be kept for the scan summary.
3440 Auto-width are automatically added."""
3441
3442 return {'cross': self.results.current['cross']}
3443
3444
3446 """If a ME run is currently running add a link in the html output"""
3447
3448
3449
3450 if hasattr(self, 'results') and hasattr(self.results, 'current') and\
3451 self.results.current and 'run_name' in self.results.current and \
3452 hasattr(self, 'me_dir'):
3453 name = self.results.current['run_name']
3454 tag = self.results.current['tag']
3455 self.debug_output = pjoin(self.me_dir, '%s_%s_debug.log' % (name,tag))
3456 if errortype:
3457 self.results.current.debug = errortype
3458 else:
3459 self.results.current.debug = self.debug_output
3460
3461 else:
3462
3463 self.debug_output = CommonRunCmd.debug_output
3464 if os.path.exists('ME5_debug') and not 'ME5_debug' in self.debug_output:
3465 try:
3466 os.remove('ME5_debug')
3467 except Exception:
3468 pass
3469 if not 'ME5_debug' in self.debug_output:
3470 os.system('ln -s %s ME5_debug &> /dev/null' % self.debug_output)
3471
3472
3474 """Not in help: exit """
3475
3476 if not self.force_run:
3477 try:
3478 os.remove(pjoin(self.me_dir,'RunWeb'))
3479 except Exception:
3480 pass
3481
3482 try:
3483 self.store_result()
3484 except Exception:
3485
3486 pass
3487
3488 try:
3489 self.update_status('', level=None)
3490 except Exception as error:
3491 pass
3492
3493 self.gen_card_html()
3494 return super(CommonRunCmd, self).do_quit(line)
3495
3496
3497 do_EOF = do_quit
3498 do_exit = do_quit
3499
3501 """try to remove RunWeb?"""
3502
3503 if not self.stop_for_runweb and not self.force_run:
3504 try:
3505 os.remove(pjoin(self.me_dir,'RunWeb'))
3506 except Exception:
3507 pass
3508
3509
3510 - def update_status(self, status, level, makehtml=True, force=True,
3511 error=False, starttime = None, update_results=True,
3512 print_log=True):
3513 """ update the index status """
3514
3515 if makehtml and not force:
3516 if hasattr(self, 'next_update') and time.time() < self.next_update:
3517 return
3518 else:
3519 self.next_update = time.time() + 3
3520
3521 if print_log:
3522 if isinstance(status, str):
3523 if '<br>' not in status:
3524 logger.info(status)
3525 elif starttime:
3526 running_time = misc.format_timer(time.time()-starttime)
3527 logger.info(' Idle: %s, Running: %s, Completed: %s [ %s ]' % \
3528 (status[0], status[1], status[2], running_time))
3529 else:
3530 logger.info(' Idle: %s, Running: %s, Completed: %s' % status[:3])
3531
3532 if isinstance(status, str) and status.startswith('\x1b['):
3533 status = status[status.index('m')+1:-7]
3534 if 'arXiv' in status:
3535 if '[' in status:
3536 status = status.split('[',1)[0]
3537 else:
3538 status = status.split('arXiv',1)[0]
3539
3540 if update_results:
3541 self.results.update(status, level, makehtml=makehtml, error=error)
3542
3543
3545 """Ask the question when launching generate_events/multi_run"""
3546
3547 check_card = ['pythia_card.dat', 'pgs_card.dat','delphes_card.dat',
3548 'delphes_trigger.dat', 'madspin_card.dat', 'shower_card.dat',
3549 'reweight_card.dat','pythia8_card.dat',
3550 'madanalysis5_parton_card.dat','madanalysis5_hadron_card.dat',
3551 'plot_card.dat']
3552
3553 cards_path = pjoin(self.me_dir,'Cards')
3554 for card in check_card:
3555 if card in ignore or (ignore == ['*'] and card not in need_card):
3556 continue
3557 if card not in need_card:
3558 if os.path.exists(pjoin(cards_path, card)):
3559 files.mv(pjoin(cards_path, card), pjoin(cards_path, '.%s' % card))
3560 else:
3561 if not os.path.exists(pjoin(cards_path, card)):
3562 if os.path.exists(pjoin(cards_path, '.%s' % card)):
3563 files.mv(pjoin(cards_path, '.%s' % card), pjoin(cards_path, card))
3564 else:
3565 default = card.replace('.dat', '_default.dat')
3566 files.cp(pjoin(cards_path, default),pjoin(cards_path, card))
3567
3568
3569 - def set_configuration(self, config_path=None, final=True, initdir=None, amcatnlo=False):
3570 """ assign all configuration variable from file
3571 ./Cards/mg5_configuration.txt. assign to default if not define """
3572
3573 if not hasattr(self, 'options') or not self.options:
3574 self.options = dict(self.options_configuration)
3575 self.options.update(self.options_madgraph)
3576 self.options.update(self.options_madevent)
3577
3578 if not config_path:
3579 if 'MADGRAPH_BASE' in os.environ:
3580 config_path = pjoin(os.environ['MADGRAPH_BASE'],'mg5_configuration.txt')
3581 self.set_configuration(config_path=config_path, final=False)
3582 if 'HOME' in os.environ:
3583 config_path = pjoin(os.environ['HOME'],'.mg5',
3584 'mg5_configuration.txt')
3585 if os.path.exists(config_path):
3586 self.set_configuration(config_path=config_path, final=False)
3587 if amcatnlo:
3588 me5_config = pjoin(self.me_dir, 'Cards', 'amcatnlo_configuration.txt')
3589 else:
3590 me5_config = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
3591 self.set_configuration(config_path=me5_config, final=False, initdir=self.me_dir)
3592
3593 if 'mg5_path' in self.options and self.options['mg5_path']:
3594 MG5DIR = self.options['mg5_path']
3595 config_file = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
3596 self.set_configuration(config_path=config_file, final=False,initdir=MG5DIR)
3597 else:
3598 self.options['mg5_path'] = None
3599 return self.set_configuration(config_path=me5_config, final=final,initdir=self.me_dir)
3600
3601 config_file = open(config_path)
3602
3603
3604 logger.info('load configuration from %s ' % config_file.name)
3605 for line in config_file:
3606
3607 if '#' in line:
3608 line = line.split('#',1)[0]
3609 line = line.replace('\n','').replace('\r\n','')
3610 try:
3611 name, value = line.split('=')
3612 except ValueError:
3613 pass
3614 else:
3615 name = name.strip()
3616 value = value.strip()
3617 if name.endswith('_path') and not name.startswith('cluster'):
3618 path = value
3619 if os.path.isdir(path):
3620 self.options[name] = os.path.realpath(path)
3621 continue
3622 if not initdir:
3623 continue
3624 path = pjoin(initdir, value)
3625 if os.path.isdir(path):
3626 self.options[name] = os.path.realpath(path)
3627 continue
3628 else:
3629 self.options[name] = value
3630 if value.lower() == "none":
3631 self.options[name] = None
3632
3633 if not final:
3634 return self.options
3635
3636
3637
3638 for key in self.options:
3639
3640 if key.endswith('path') and not key.startswith("cluster"):
3641 path = self.options[key]
3642 if path is None:
3643 continue
3644 if os.path.isdir(path):
3645 self.options[key] = os.path.realpath(path)
3646 continue
3647 path = pjoin(self.me_dir, self.options[key])
3648 if os.path.isdir(path):
3649 self.options[key] = os.path.realpath(path)
3650 continue
3651 elif 'mg5_path' in self.options and self.options['mg5_path']:
3652 path = pjoin(self.options['mg5_path'], self.options[key])
3653 if os.path.isdir(path):
3654 self.options[key] = os.path.realpath(path)
3655 continue
3656 self.options[key] = None
3657 elif key.startswith('cluster') and key != 'cluster_status_update':
3658 if key in ('cluster_nb_retry','cluster_wait_retry'):
3659 self.options[key] = int(self.options[key])
3660 if hasattr(self,'cluster'):
3661 del self.cluster
3662 pass
3663 elif key == 'automatic_html_opening':
3664 if self.options[key] in ['False', 'True']:
3665 self.options[key] =ast.literal_eval(self.options[key])
3666 elif key == "notification_center":
3667 if self.options[key] in ['False', 'True']:
3668 self.allow_notification_center =ast.literal_eval(self.options[key])
3669 self.options[key] =ast.literal_eval(self.options[key])
3670 elif key not in ['text_editor','eps_viewer','web_browser','stdout_level',
3671 'complex_mass_scheme', 'gauge', 'group_subprocesses']:
3672
3673 try:
3674 self.do_set("%s %s --no_save" % (key, self.options[key]), log=False)
3675 except self.InvalidCmd:
3676 logger.warning("Option %s from config file not understood" \
3677 % key)
3678
3679
3680 misc.open_file.configure(self.options)
3681
3682
3683 if MADEVENT and 'mg5_path' in self.options and self.options['mg5_path']:
3684 mg5dir = self.options['mg5_path']
3685 if mg5dir not in sys.path:
3686 sys.path.append(mg5dir)
3687 if pjoin(mg5dir, 'PLUGIN') not in self.plugin_path:
3688 self.plugin_path.append(pjoin(mg5dir,'PLUGIN'))
3689
3690 self.configure_run_mode(self.options['run_mode'])
3691 return self.options
3692
3693 @staticmethod
3695 """ find a valid run_name for the current job """
3696
3697 name = 'run_%02d'
3698 data = [int(s[4:j]) for s in os.listdir(pjoin(me_dir,'Events')) for
3699 j in range(4,len(s)+1) if \
3700 s.startswith('run_') and s[4:j].isdigit()]
3701 return name % (max(data+[0])+1)
3702
3703
3704
3706 """Require MG5 directory: decay events with spin correlations
3707 """
3708
3709 if '-from_cards' in line and not os.path.exists(pjoin(self.me_dir, 'Cards', 'madspin_card.dat')):
3710 return
3711
3712
3713
3714 if MADEVENT and not self.options['mg5_path']:
3715 raise self.InvalidCmd('''The module decay_events requires that MG5 is installed on the system.
3716 You can install it and set its path in ./Cards/me5_configuration.txt''')
3717 elif MADEVENT:
3718 sys.path.append(self.options['mg5_path'])
3719 try:
3720 import MadSpin.decay as decay
3721 import MadSpin.interface_madspin as interface_madspin
3722 except ImportError:
3723 if __debug__:
3724 raise
3725 else:
3726 raise self.ConfigurationError('''Can\'t load MadSpin
3727 The variable mg5_path might not be correctly configured.''')
3728
3729 self.update_status('Running MadSpin', level='madspin')
3730 if not '-from_cards' in line and '-f' not in line:
3731 self.keep_cards(['madspin_card.dat'], ignore=['*'])
3732 self.ask_edit_cards(['madspin_card.dat'], 'fixed', plot=False)
3733 self.help_decay_events(skip_syntax=True)
3734
3735
3736 args = self.split_arg(line)
3737 self.check_decay_events(args)
3738
3739 madspin_cmd = interface_madspin.MadSpinInterface(args[0])
3740
3741 madspin_cmd.mg5cmd.options.update(self.options)
3742 for key, value in self.options.items():
3743 if isinstance(value, str):
3744 madspin_cmd.mg5cmd.exec_cmd( 'set %s %s --no_save' %(key,value), errorhandling=False, printcmd=False, precmd=False, postcmd=True)
3745 madspin_cmd.cluster = self.cluster
3746 madspin_cmd.mother = self
3747
3748 madspin_cmd.update_status = lambda *x,**opt: self.update_status(*x, level='madspin',**opt)
3749
3750 path = pjoin(self.me_dir, 'Cards', 'madspin_card.dat')
3751
3752 madspin_cmd.import_command_file(path)
3753
3754
3755 if not madspin_cmd.me_run_name:
3756
3757 i = 1
3758 while os.path.exists(pjoin(self.me_dir,'Events', '%s_decayed_%i' % (self.run_name,i))):
3759 i+=1
3760 new_run = '%s_decayed_%i' % (self.run_name,i)
3761 else:
3762 new_run = madspin_cmd.me_run_name
3763 if os.path.exists(pjoin(self.me_dir,'Events', new_run)):
3764 i = 1
3765 while os.path.exists(pjoin(self.me_dir,'Events', '%s_%i' % (new_run,i))):
3766 i+=1
3767 new_run = '%s_%i' % (new_run,i)
3768
3769 evt_dir = pjoin(self.me_dir, 'Events')
3770
3771 os.mkdir(pjoin(evt_dir, new_run))
3772 current_file = args[0].replace('.lhe', '_decayed.lhe')
3773 new_file = pjoin(evt_dir, new_run, os.path.basename(args[0]))
3774 if not os.path.exists(current_file):
3775 if os.path.exists(current_file+'.gz'):
3776 current_file += '.gz'
3777 new_file += '.gz'
3778 elif current_file.endswith('.gz') and os.path.exists(current_file[:-3]):
3779 current_file = current_file[:-3]
3780 new_file = new_file[:-3]
3781 else:
3782 logger.error('MadSpin fails to create any decayed file.')
3783 return
3784
3785 files.mv(current_file, new_file)
3786 logger.info("The decayed event file has been moved to the following location: ")
3787 logger.info(new_file)
3788
3789 if hasattr(self, 'results'):
3790 current = self.results.current
3791 nb_event = self.results.current['nb_event']
3792 if not nb_event:
3793 current = self.results[self.run_name][0]
3794 nb_event = current['nb_event']
3795
3796 cross = current['cross']
3797 error = current['error']
3798 self.results.add_run( new_run, self.run_card)
3799 self.results.add_detail('nb_event', int(nb_event*madspin_cmd.efficiency))
3800 self.results.add_detail('cross', madspin_cmd.cross)
3801 self.results.add_detail('error', madspin_cmd.error+ cross * madspin_cmd.err_branching_ratio)
3802 self.results.add_detail('run_mode', current['run_mode'])
3803 self.to_store.append("event")
3804
3805 self.run_name = new_run
3806 self.banner = madspin_cmd.banner
3807 self.banner.add(path)
3808 self.banner.write(pjoin(self.me_dir,'Events',self.run_name, '%s_%s_banner.txt' %
3809 (self.run_name, self.run_tag)))
3810 self.update_status('MadSpin Done', level='parton', makehtml=False)
3811 if 'unweighted' in os.path.basename(args[0]):
3812 self.create_plot('parton')
3813
3820
3822 "Complete the print results command"
3823 args = self.split_arg(line[0:begidx], error=False)
3824 if len(args) == 1:
3825
3826 data = misc.glob(pjoin('*','unweighted_events.lhe.gz'),
3827 pjoin(self.me_dir, 'Events'))
3828
3829 data = [n.rsplit('/',2)[1] for n in data]
3830 tmp1 = self.list_completion(text, data)
3831 return tmp1
3832 else:
3833 data = misc.glob('*_pythia_events.hep.gz', pjoin(self.me_dir, 'Events', args[0]))
3834 data = [os.path.basename(p).rsplit('_',1)[0] for p in data]
3835 data += ["--mode=a", "--mode=w", "--path=", "--format=short"]
3836 tmp1 = self.list_completion(text, data)
3837 return tmp1
3838
3840 logger.info("syntax: print_result [RUN] [TAG] [options]")
3841 logger.info("-- show in text format the status of the run (cross-section/nb-event/...)")
3842 logger.info("--path= defines the path of the output file.")
3843 logger.info("--mode=a allow to add the information at the end of the file.")
3844 logger.info("--format=short (only if --path is define)")
3845 logger.info(" allows to have a multi-column output easy to parse")
3846
3847
3848
3850 """ return the model name """
3851 if hasattr(self, 'model_name'):
3852 return self.model_name
3853
3854 def join_line(old, to_add):
3855 if old.endswith('\\'):
3856 newline = old[:-1] + to_add
3857 else:
3858 newline = old + line
3859 return newline
3860
3861
3862
3863 model = 'sm'
3864 proc = []
3865 continuation_line = None
3866 for line in open(os.path.join(self.me_dir,'Cards','proc_card_mg5.dat')):
3867 line = line.split('#')[0]
3868 if continuation_line:
3869 line = line.strip()
3870 if continuation_line == 'model':
3871 model = join_line(model, line)
3872 elif continuation_line == 'proc':
3873 proc = join_line(proc, line)
3874 if not line.endswith('\\'):
3875 continuation_line = None
3876 continue
3877
3878 if line.startswith('import') and 'model' in line:
3879 model = line.split()[2]
3880 proc = []
3881 if model.endswith('\\'):
3882 continuation_line = 'model'
3883 elif line.startswith('generate'):
3884 proc.append(line.split(None,1)[1])
3885 if proc[-1].endswith('\\'):
3886 continuation_line = 'proc'
3887 elif line.startswith('add process'):
3888 proc.append(line.split(None,2)[2])
3889 if proc[-1].endswith('\\'):
3890 continuation_line = 'proc'
3891 self.model = model
3892 self.process = proc
3893 return model
3894
3895
3896
3922
3923
3925 args = self.split_arg(line[0:begidx], error=False)
3926
3927 if len(args) == 1 and os.path.sep not in text:
3928
3929 data = misc.glob(pjoin('*','*events.lhe*'), pjoin(self.me_dir, 'Events'))
3930 data = [n.rsplit('/',2)[1] for n in data]
3931 return self.list_completion(text, data, line)
3932 else:
3933 return self.path_completion(text,
3934 os.path.join('.',*[a for a in args \
3935 if a.endswith(os.path.sep)]))
3936
3938 "Complete the pythia command"
3939 args = self.split_arg(line[0:begidx], error=False)
3940
3941
3942 data = misc.glob(pjoin('*','*events.lhe*'), pjoin(self.me_dir, 'Events'))
3943 data = list(set([n.rsplit('/',2)[1] for n in data]))
3944 if not '-f' in args:
3945 data.append('-f')
3946 tmp1 = self.list_completion(text, data)
3947 return tmp1
3948
3949
3950
3952 "Complete the compute_widths command"
3953
3954 args = self.split_arg(line[0:begidx])
3955
3956 if args[-1] in ['--path=', '--output=']:
3957 completion = {'path': self.path_completion(text)}
3958 elif line[begidx-1] == os.path.sep:
3959 current_dir = pjoin(*[a for a in args if a.endswith(os.path.sep)])
3960 if current_dir.startswith('--path='):
3961 current_dir = current_dir[7:]
3962 if current_dir.startswith('--output='):
3963 current_dir = current_dir[9:]
3964 completion = {'path': self.path_completion(text, current_dir)}
3965 else:
3966 completion = {}
3967 completion['options'] = self.list_completion(text,
3968 ['--path=', '--output=', '--min_br=0.\$', '--nlo',
3969 '--precision_channel=0.\$', '--body_decay='])
3970
3971 return self.deal_multiple_categories(completion, formatting)
3972
3973
3975 """update the make_opts file writing the environmental variables
3976 stored in make_opts_var"""
3977 make_opts = os.path.join(self.me_dir, 'Source', 'make_opts')
3978
3979
3980 if not hasattr(self,'options') or not 'pythia8_path' in self.options or \
3981 not self.options['pythia8_path'] or \
3982 not os.path.isfile(pjoin(self.options['pythia8_path'],'bin','pythia8-config')):
3983 self.make_opts_var['PYTHIA8_PATH']='NotInstalled'
3984 else:
3985 self.make_opts_var['PYTHIA8_PATH']=self.options['pythia8_path']
3986
3987 self.make_opts_var['MG5AMC_VERSION'] = misc.get_pkg_info()['version']
3988
3989 if run_card and run_card.LO:
3990 if __debug__ and 'global_flag' not in run_card.user_set:
3991 self.make_opts_var['GLOBAL_FLAG'] = "-O -fbounds-check"
3992 else:
3993 self.make_opts_var['GLOBAL_FLAG'] = run_card['global_flag']
3994 self.make_opts_var['ALOHA_FLAG'] = run_card['aloha_flag']
3995 self.make_opts_var['MATRIX_FLAG'] = run_card['matrix_flag']
3996
3997 return self.update_make_opts_full(make_opts, self.make_opts_var)
3998
3999 @staticmethod
4001 """update the make_opts file writing the environmental variables
4002 of def_variables.
4003 if a value of the dictionary is None then it is not written.
4004 """
4005 make_opts = path
4006 pattern = re.compile(r'^(\w+)\s*=\s*(.*)$',re.DOTALL)
4007 diff = False
4008
4009
4010 tag = '#end_of_make_opts_variables\n'
4011 make_opts_variable = True
4012 content = []
4013 variables = dict(def_variables)
4014 need_keys = list(variables.keys())
4015 for line in open(make_opts):
4016 line = line.strip()
4017 if make_opts_variable:
4018 if line.startswith('#') or not line:
4019 if line.startswith('#end_of_make_opts_variables'):
4020 make_opts_variable = False
4021 continue
4022 elif pattern.search(line):
4023 key, value = pattern.search(line).groups()
4024 if key not in variables:
4025 variables[key] = value
4026 elif value != variables[key]:
4027 diff=True
4028 else:
4029 need_keys.remove(key)
4030 else:
4031 make_opts_variable = False
4032 content.append(line)
4033 else:
4034 content.append(line)
4035
4036 if need_keys:
4037 diff=True
4038
4039 content_variables = '\n'.join('%s=%s' % (k,v) for k, v in variables.items() if v is not None)
4040 content_variables += '\n%s' % tag
4041
4042 if diff:
4043 with open(make_opts, 'w') as fsock:
4044 fsock.write(content_variables + '\n'.join(content))
4045 return
4046
4047
4048
4050 """links lhapdf into libdir"""
4051
4052 lhapdf_version = self.get_lhapdf_version()
4053 logger.info('Using LHAPDF v%s interface for PDFs' % lhapdf_version)
4054 lhalibdir = subprocess.Popen([self.options['lhapdf'], '--libdir'],
4055 stdout = subprocess.PIPE).stdout.read().decode().strip()
4056
4057 if lhapdf_version.startswith('5.'):
4058 pdfsetsdir = subprocess.Popen([self.options['lhapdf'], '--pdfsets-path'],
4059 stdout = subprocess.PIPE).stdout.read().decode().strip()
4060 else:
4061 pdfsetsdir = subprocess.Popen([self.options['lhapdf'], '--datadir'],
4062 stdout = subprocess.PIPE).stdout.read().decode().strip()
4063
4064 self.lhapdf_pdfsets = self.get_lhapdf_pdfsets_list(pdfsetsdir)
4065
4066 lhalib = 'libLHAPDF.a'
4067
4068 if os.path.exists(pjoin(libdir, lhalib)):
4069 files.rm(pjoin(libdir, lhalib))
4070 files.ln(pjoin(lhalibdir, lhalib), libdir)
4071
4072 if not os.path.isdir(pjoin(libdir, 'PDFsets')):
4073 os.mkdir(pjoin(libdir, 'PDFsets'))
4074 self.make_opts_var['lhapdf'] = self.options['lhapdf']
4075 self.make_opts_var['lhapdfversion'] = lhapdf_version[0]
4076 self.make_opts_var['lhapdfsubversion'] = lhapdf_version.split('.',2)[1]
4077 self.make_opts_var['lhapdf_config'] = self.options['lhapdf']
4078
4079
4081 """reads the proc_characteristics file and initialises the correspondant
4082 dictionary"""
4083
4084 if not path:
4085 path = os.path.join(self.me_dir, 'SubProcesses', 'proc_characteristics')
4086
4087 self.proc_characteristics = banner_mod.ProcCharacteristic(path)
4088 return self.proc_characteristics
4089
4090
4092 """copy (if needed) the lhapdf set corresponding to the lhaid in lhaid_list
4093 into lib/PDFsets.
4094 if require_local is False, just ensure that the pdf is in pdfsets_dir
4095 """
4096
4097 if not hasattr(self, 'lhapdf_pdfsets'):
4098 self.lhapdf_pdfsets = self.get_lhapdf_pdfsets_list(pdfsets_dir)
4099
4100 pdfsetname=set()
4101 for lhaid in lhaid_list:
4102 if isinstance(lhaid, str) and lhaid.isdigit():
4103 lhaid = int(lhaid)
4104 if isinstance(lhaid, (int,float)):
4105 try:
4106 if lhaid in self.lhapdf_pdfsets:
4107 pdfsetname.add(self.lhapdf_pdfsets[lhaid]['filename'])
4108 else:
4109 raise MadGraph5Error('lhaid %s not valid input number for the current lhapdf' % lhaid )
4110 except KeyError:
4111 if self.lhapdf_version.startswith('5'):
4112 raise MadGraph5Error(\
4113 ('invalid lhaid set in th run_card: %d .\nPlease note that some sets' % lhaid) + \
4114 '(eg MSTW 90%CL error sets) \nare not available in aMC@NLO + LHAPDF 5.x.x')
4115 else:
4116 logger.debug('%d not found in pdfsets.index' % lhaid)
4117 else:
4118 pdfsetname.add(lhaid)
4119
4120
4121
4122
4123 if not os.path.isdir(pdfsets_dir):
4124 try:
4125 os.mkdir(pdfsets_dir)
4126 except OSError:
4127 pdfsets_dir = pjoin(self.me_dir, 'lib', 'PDFsets')
4128 elif os.path.exists(pjoin(self.me_dir, 'lib', 'PDFsets')):
4129
4130 for name in os.listdir(pjoin(self.me_dir, 'lib', 'PDFsets')):
4131 if name not in pdfsetname:
4132 try:
4133 if os.path.isdir(pjoin(self.me_dir, 'lib', 'PDFsets', name)):
4134 shutil.rmtree(pjoin(self.me_dir, 'lib', 'PDFsets', name))
4135 else:
4136 os.remove(pjoin(self.me_dir, 'lib', 'PDFsets', name))
4137 except Exception as error:
4138 logger.debug('%s', error)
4139
4140 if self.options["cluster_local_path"]:
4141 lhapdf_cluster_possibilities = [self.options["cluster_local_path"],
4142 pjoin(self.options["cluster_local_path"], "lhapdf"),
4143 pjoin(self.options["cluster_local_path"], "lhapdf", "pdfsets"),
4144 pjoin(self.options["cluster_local_path"], "..", "lhapdf"),
4145 pjoin(self.options["cluster_local_path"], "..", "lhapdf", "pdfsets"),
4146 pjoin(self.options["cluster_local_path"], "..", "lhapdf","pdfsets", "6.1")
4147 ]
4148 else:
4149 lhapdf_cluster_possibilities = []
4150
4151 for pdfset in pdfsetname:
4152
4153 if self.options["cluster_local_path"] and self.options["run_mode"] == 1 and \
4154 any((os.path.exists(pjoin(d, pdfset)) for d in lhapdf_cluster_possibilities)):
4155
4156 os.environ["LHAPATH"] = [d for d in lhapdf_cluster_possibilities if os.path.exists(pjoin(d, pdfset))][0]
4157 os.environ["CLUSTER_LHAPATH"] = os.environ["LHAPATH"]
4158
4159 if os.path.exists(pjoin(pdfsets_dir, pdfset)):
4160 try:
4161 if os.path.isdir(pjoin(pdfsets_dir, name)):
4162 shutil.rmtree(pjoin(pdfsets_dir, name))
4163 else:
4164 os.remove(pjoin(pdfsets_dir, name))
4165 except Exception as error:
4166 logger.debug('%s', error)
4167 if not require_local and (os.path.exists(pjoin(pdfsets_dir, pdfset)) or \
4168 os.path.isdir(pjoin(pdfsets_dir, pdfset))):
4169 continue
4170 if not require_local:
4171 if 'LHAPDF_DATA_PATH' in os.environ:
4172 found = False
4173 for path in os.environ['LHAPDF_DATA_PATH'].split(":"):
4174 if (os.path.exists(pjoin(path, pdfset)) or \
4175 os.path.isdir(pjoin(path, pdfset))):
4176 found =True
4177 break
4178 if found:
4179 continue
4180
4181
4182
4183 elif not os.path.exists(pjoin(self.me_dir, 'lib', 'PDFsets', pdfset)) and \
4184 not os.path.isdir(pjoin(self.me_dir, 'lib', 'PDFsets', pdfset)):
4185
4186 if pdfset and not os.path.exists(pjoin(pdfsets_dir, pdfset)):
4187 self.install_lhapdf_pdfset(pdfsets_dir, pdfset)
4188
4189 if os.path.exists(pjoin(pdfsets_dir, pdfset)):
4190 files.cp(pjoin(pdfsets_dir, pdfset), pjoin(self.me_dir, 'lib', 'PDFsets'))
4191 elif os.path.exists(pjoin(os.path.dirname(pdfsets_dir), pdfset)):
4192 files.cp(pjoin(os.path.dirname(pdfsets_dir), pdfset), pjoin(self.me_dir, 'lib', 'PDFsets'))
4193
4195 """idownloads and install the pdfset filename in the pdfsets_dir"""
4196 lhapdf_version = self.get_lhapdf_version()
4197 local_path = pjoin(self.me_dir, 'lib', 'PDFsets')
4198 return self.install_lhapdf_pdfset_static(self.options['lhapdf'],
4199 pdfsets_dir, filename,
4200 lhapdf_version=lhapdf_version,
4201 alternate_path=local_path)
4202
4203
4204 @staticmethod
4207 """idownloads and install the pdfset filename in the pdfsets_dir.
4208 Version which can be used independently of the class.
4209 local path is used if the global installation fails.
4210 """
4211
4212 if not lhapdf_version:
4213 lhapdf_version = CommonRunCmd.get_lhapdf_version_static(lhapdf_config)
4214
4215 if not pdfsets_dir:
4216 pdfsets_dir = CommonRunCmd.get_lhapdf_pdfsetsdir_static(lhapdf_config, lhapdf_version)
4217
4218 if isinstance(filename, int):
4219 pdf_info = CommonRunCmd.get_lhapdf_pdfsets_list_static(pdfsets_dir, lhapdf_version)
4220 filename = pdf_info[filename]['filename']
4221
4222 if os.path.exists(pjoin(pdfsets_dir, filename)):
4223 logger.debug('%s is already present in %s', filename, pdfsets_dir)
4224 return
4225
4226 logger.info('Trying to download %s' % filename)
4227
4228
4229 if lhapdf_version.startswith('5.'):
4230
4231
4232
4233 getdata = lhapdf_config.replace('lhapdf-config', ('lhapdf-getdata'))
4234 misc.call([getdata, filename], cwd = pdfsets_dir)
4235
4236 elif lhapdf_version.startswith('6.'):
4237
4238
4239 getdata = lhapdf_config.replace('lhapdf-config', ('lhapdf'))
4240
4241 if lhapdf_version.startswith('6.1'):
4242 misc.call([getdata, 'install', filename], cwd = pdfsets_dir)
4243 else:
4244
4245 lhapdf = misc.import_python_lhapdf(lhapdf_config)
4246 if lhapdf:
4247 if 'PYTHONPATH' in os.environ:
4248 os.environ['PYTHONPATH']+= ':' + os.path.dirname(lhapdf.__file__)
4249 else:
4250 os.environ['PYTHONPATH'] = ':'.join(sys.path) + ':' + os.path.dirname(lhapdf.__file__)
4251 else:
4252 logger.warning('lhapdf 6.2.1 requires python integration in order to download pdf set. Trying anyway')
4253 misc.call([getdata, 'install', filename], cwd = pdfsets_dir)
4254
4255 else:
4256 raise MadGraph5Error('Not valid LHAPDF version: %s' % lhapdf_version)
4257
4258
4259 if os.path.exists(pjoin(pdfsets_dir, filename)) or \
4260 os.path.isdir(pjoin(pdfsets_dir, filename)):
4261 logger.info('%s successfully downloaded and stored in %s' \
4262 % (filename, pdfsets_dir))
4263
4264
4265 elif lhapdf_version.startswith('5.'):
4266 logger.warning('Could not download %s into %s. Trying to save it locally' \
4267 % (filename, pdfsets_dir))
4268 CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, alternate_path, filename,
4269 lhapdf_version=lhapdf_version)
4270 elif lhapdf_version.startswith('6.') and '.LHgrid' in filename:
4271 logger.info('Could not download %s: Try %s', filename, filename.replace('.LHgrid',''))
4272 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, pdfsets_dir,
4273 filename.replace('.LHgrid',''),
4274 lhapdf_version, alternate_path)
4275 elif lhapdf_version.startswith('6.'):
4276
4277 wwwpath = "http://lhapdfsets.web.cern.ch/lhapdfsets/current/%s.tar.gz" % filename
4278 misc.wget(wwwpath, pjoin(pdfsets_dir, '%s.tar.gz' %filename))
4279 misc.call(['tar', '-xzpvf', '%s.tar.gz' %filename],
4280 cwd=pdfsets_dir)
4281
4282 if os.path.exists(pjoin(pdfsets_dir, filename)) or \
4283 os.path.isdir(pjoin(pdfsets_dir, filename)):
4284 logger.info('%s successfully downloaded and stored in %s' \
4285 % (filename, pdfsets_dir))
4286 elif 'LHAPDF_DATA_PATH' in os.environ and os.environ['LHAPDF_DATA_PATH']:
4287
4288 if pdfsets_dir in os.environ['LHAPDF_DATA_PATH'].split(':'):
4289 lhapath = os.environ['LHAPDF_DATA_PATH'].split(':')
4290 lhapath = [p for p in lhapath if os.path.exists(p)]
4291 lhapath.remove(pdfsets_dir)
4292 os.environ['LHAPDF_DATA_PATH'] = ':'.join(lhapath)
4293 if lhapath:
4294 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4295 filename,
4296 lhapdf_version, alternate_path)
4297 elif 'LHAPATH' in os.environ and os.environ['LHAPATH']:
4298 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4299 filename,
4300 lhapdf_version, alternate_path)
4301 else:
4302 raise MadGraph5Error( \
4303 'Could not download %s into %s. Please try to install it manually.' \
4304 % (filename, pdfsets_dir))
4305 else:
4306 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4307 filename,
4308 lhapdf_version, alternate_path)
4309 elif 'LHAPATH' in os.environ and os.environ['LHAPATH']:
4310 if pdfsets_dir in os.environ['LHAPATH'].split(':'):
4311 lhapath = os.environ['LHAPATH'].split(':')
4312 lhapath = [p for p in lhapath if os.path.exists(p)]
4313 lhapath.remove(pdfsets_dir)
4314 os.environ['LHAPATH'] = ':'.join(lhapath)
4315 if lhapath:
4316 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4317 filename,
4318 lhapdf_version, alternate_path)
4319 else:
4320 raise MadGraph5Error('Could not download %s into %s. Please try to install it manually.' \
4321 % (filename, pdfsets_dir))
4322 else:
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
4330 else:
4331 raise MadGraph5Error('Could not download %s into %s. Please try to install it manually.' \
4332 % (filename, pdfsets_dir))
4333
4334
4335
4337 """read the PDFsets.index file, which should be located in the same
4338 place as pdfsets_dir, and return a list of dictionaries with the information
4339 about each pdf set"""
4340 lhapdf_version = self.get_lhapdf_version()
4341 return self.get_lhapdf_pdfsets_list_static(pdfsets_dir, lhapdf_version)
4342
4343 @staticmethod
4345
4346 if lhapdf_version.startswith('5.'):
4347 if os.path.exists('%s.index' % pdfsets_dir):
4348 indexfile = '%s.index' % pdfsets_dir
4349 else:
4350 raise MadGraph5Error('index of lhapdf file not found')
4351 pdfsets_lines = \
4352 [l for l in open(indexfile).read().split('\n') if l.strip() and \
4353 not '90cl' in l]
4354 lhapdf_pdfsets = dict( (int(l.split()[0]), {'lhaid': int(l.split()[0]),
4355 'pdflib_ntype': int(l.split()[1]),
4356 'pdflib_ngroup': int(l.split()[2]),
4357 'pdflib_nset': int(l.split()[3]),
4358 'filename': l.split()[4],
4359 'lhapdf_nmem': int(l.split()[5]),
4360 'q2min': float(l.split()[6]),
4361 'q2max': float(l.split()[7]),
4362 'xmin': float(l.split()[8]),
4363 'xmax': float(l.split()[9]),
4364 'description': l.split()[10]}) \
4365 for l in pdfsets_lines)
4366
4367 elif lhapdf_version.startswith('6.'):
4368 pdfsets_lines = \
4369 [l for l in open(pjoin(pdfsets_dir, 'pdfsets.index'),'r').read().split('\n') if l.strip()]
4370 lhapdf_pdfsets = dict( (int(l.split()[0]),
4371 {'lhaid': int(l.split()[0]),
4372 'filename': l.split()[1]}) \
4373 for l in pdfsets_lines)
4374
4375 else:
4376 raise MadGraph5Error('Not valid LHAPDF version: %s' % lhapdf_version)
4377
4378 return lhapdf_pdfsets
4379
4380 @staticmethod
4382 """returns the lhapdf version number"""
4383
4384 try:
4385 lhapdf_version = \
4386 subprocess.Popen([lhapdf_config, '--version'],
4387 stdout = subprocess.PIPE).stdout.read().decode().strip()
4388 except OSError as error:
4389 if error.errno == 2:
4390 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)
4391 else:
4392 raise
4393
4394
4395 if lhapdf_version.startswith('6.0'):
4396 raise MadGraph5Error('LHAPDF 6.0.x not supported. Please use v6.1 or later')
4397 return lhapdf_version
4398
4399
4401 """returns the lhapdf version number"""
4402 if not hasattr(self, 'lhapdfversion'):
4403 self.lhapdf_version = self.get_lhapdf_version_static(self.options['lhapdf'])
4404 return self.lhapdf_version
4405
4406 @staticmethod
4408 """ """
4409 if not lhapdf_version:
4410 lhapdf_version = CommonRunCmd.get_lhapdf_version_static(lhapdf_config)
4411
4412
4413 if 'LHAPDF_DATA_PATH' in list(os.environ.keys()) and os.environ['LHAPDF_DATA_PATH']:
4414 datadir = os.environ['LHAPDF_DATA_PATH']
4415 elif lhapdf_version.startswith('5.'):
4416 datadir = subprocess.Popen([lhapdf_config, '--pdfsets-path'],
4417 stdout = subprocess.PIPE).stdout.read().decode().strip()
4418
4419 elif lhapdf_version.startswith('6.'):
4420 datadir = subprocess.Popen([lhapdf_config, '--datadir'],
4421 stdout = subprocess.PIPE).stdout.read().decode().strip()
4422
4423 if ':' in datadir:
4424 for totry in datadir.split(':'):
4425 if os.path.exists(pjoin(totry, 'pdfsets.index')):
4426 return totry
4427 else:
4428 return None
4429
4430 return datadir
4431
4436
4437
4439 """get the list of Pdirectory if not yet saved."""
4440
4441 if hasattr(self, "Pdirs"):
4442 if self.me_dir in self.Pdirs[0]:
4443 return self.Pdirs
4444 self.Pdirs = [pjoin(self.me_dir, 'SubProcesses', l.strip())
4445 for l in open(pjoin(self.me_dir,'SubProcesses', 'subproc.mg'))]
4446 return self.Pdirs
4447
4449
4450 if 'LHAPATH' in os.environ:
4451 for d in os.environ['LHAPATH'].split(':'):
4452 if os.path.isdir(d):
4453 return d
4454
4455
4456 lhapdf_version = self.get_lhapdf_version()
4457
4458 if lhapdf_version.startswith('5.'):
4459 libdir = subprocess.Popen([self.options['lhapdf-config'], '--libdir'],
4460 stdout = subprocess.PIPE).stdout.read().decode().strip()
4461
4462 elif lhapdf_version.startswith('6.'):
4463 libdir = subprocess.Popen([self.options['lhapdf'], '--libs'],
4464 stdout = subprocess.PIPE).stdout.read().decode().strip()
4465
4466 return libdir
4467
4469 """A class for asking a question where in addition you can have the
4470 set command define and modifying the param_card/run_card correctly
4471
4472 special action can be trigger via trigger_XXXX when the user start a line
4473 with XXXX. the output of such function should be new line that can be handle.
4474 (return False to repeat the question)
4475 """
4476
4477 all_card_name = ['param_card', 'run_card', 'pythia_card', 'pythia8_card',
4478 'madweight_card', 'MadLoopParams', 'shower_card']
4479 to_init_card = ['param', 'run', 'madweight', 'madloop',
4480 'shower', 'pythia8','delphes','madspin']
4481 special_shortcut = {}
4482 special_shortcut_help = {}
4483
4484 integer_bias = 1
4485
4486 PY8Card_class = banner_mod.PY8Card
4487
4489 """ define all default variable. No load of card here.
4490 This allow to subclass this class and just change init and still have
4491 all variables defined."""
4492
4493 if not hasattr(self, 'me_dir'):
4494 self.me_dir = None
4495 self.param_card = None
4496 self.run_card = {}
4497 self.pname2block = {}
4498 self.conflict = []
4499 self.restricted_value = {}
4500 self.mode = ''
4501 self.cards = []
4502 self.run_set = []
4503 self.has_mw = False
4504 self.has_ml = False
4505 self.has_shower = False
4506 self.has_PY8 = False
4507 self.has_delphes = False
4508 self.paths = {}
4509 self.update_block = []
4510
4511
4513
4514 if 'pwd' in opt:
4515 self.me_dir = opt['pwd']
4516 elif 'mother_interface' in opt:
4517 self.mother_interface = opt['mother_interface']
4518 if not hasattr(self, 'me_dir') or not self.me_dir:
4519 self.me_dir = self.mother_interface.me_dir
4520
4521
4522 self.paths['param'] = pjoin(self.me_dir,'Cards','param_card.dat')
4523 self.paths['param_default'] = pjoin(self.me_dir,'Cards','param_card_default.dat')
4524 self.paths['run'] = pjoin(self.me_dir,'Cards','run_card.dat')
4525 self.paths['run_default'] = pjoin(self.me_dir,'Cards','run_card_default.dat')
4526 self.paths['transfer'] =pjoin(self.me_dir,'Cards','transfer_card.dat')
4527 self.paths['MadWeight'] =pjoin(self.me_dir,'Cards','MadWeight_card.dat')
4528 self.paths['MadWeight_default'] =pjoin(self.me_dir,'Cards','MadWeight_card_default.dat')
4529 self.paths['ML'] =pjoin(self.me_dir,'Cards','MadLoopParams.dat')
4530 self.paths['shower'] = pjoin(self.me_dir,'Cards','shower_card.dat')
4531 self.paths['shower_default'] = pjoin(self.me_dir,'Cards','shower_card_default.dat')
4532 self.paths['FO_analyse'] = pjoin(self.me_dir,'Cards','FO_analyse_card.dat')
4533 self.paths['FO_analyse_default'] = pjoin(self.me_dir,'Cards','FO_analyse_card_default.dat')
4534 self.paths['pythia'] =pjoin(self.me_dir, 'Cards','pythia_card.dat')
4535 self.paths['pythia8'] = pjoin(self.me_dir, 'Cards','pythia8_card.dat')
4536 self.paths['pythia8_default'] = pjoin(self.me_dir, 'Cards','pythia8_card_default.dat')
4537 self.paths['madspin_default'] = pjoin(self.me_dir,'Cards/madspin_card_default.dat')
4538 self.paths['madspin'] = pjoin(self.me_dir,'Cards/madspin_card.dat')
4539 self.paths['reweight'] = pjoin(self.me_dir,'Cards','reweight_card.dat')
4540 self.paths['delphes'] = pjoin(self.me_dir,'Cards','delphes_card.dat')
4541 self.paths['plot'] = pjoin(self.me_dir,'Cards','plot_card.dat')
4542 self.paths['plot_default'] = pjoin(self.me_dir,'Cards','plot_card_default.dat')
4543 self.paths['madanalysis5_parton'] = pjoin(self.me_dir,'Cards','madanalysis5_parton_card.dat')
4544 self.paths['madanalysis5_hadron'] = pjoin(self.me_dir,'Cards','madanalysis5_hadron_card.dat')
4545 self.paths['madanalysis5_parton_default'] = pjoin(self.me_dir,'Cards','madanalysis5_parton_card_default.dat')
4546 self.paths['madanalysis5_hadron_default'] = pjoin(self.me_dir,'Cards','madanalysis5_hadron_card_default.dat')
4547 self.paths['FO_analyse'] = pjoin(self.me_dir,'Cards', 'FO_analyse_card.dat')
4548
4549
4550
4551
4552 - def __init__(self, question, cards=[], from_banner=None, banner=None, mode='auto', *args, **opt):
4553
4554
4555 self.load_default()
4556 self.define_paths(**opt)
4557 self.last_editline_pos = 0
4558
4559 if 'allow_arg' not in opt or not opt['allow_arg']:
4560
4561 opt['allow_arg'] = list(range(self.integer_bias, self.integer_bias+len(cards)))
4562
4563 self.param_consistency = True
4564 if 'param_consistency' in opt:
4565 self.param_consistency = opt['param_consistency']
4566
4567 cmd.OneLinePathCompletion.__init__(self, question, *args, **opt)
4568
4569 self.conflict = set()
4570 self.mode = mode
4571 self.cards = cards
4572 self.all_vars = set()
4573 self.modified_card = set()
4574
4575 self.init_from_banner(from_banner, banner)
4576 self.writting_card = True
4577 if 'write_file' in opt:
4578 if not opt['write_file']:
4579 self.writting_card = False
4580 self.param_consistency = False
4581
4582
4583 for card in cards:
4584 if os.path.exists(card) and os.path.sep in cards:
4585 card_name = CommonRunCmd.detect_card_type(card)
4586 card_name = card_name.split('_',1)[0]
4587 self.paths[card_name] = card
4588
4589
4590 for name in self.to_init_card:
4591 new_vars = set(getattr(self, 'init_%s' % name)(cards))
4592 new_conflict = self.all_vars.intersection(new_vars)
4593 self.conflict.union(new_conflict)
4594 self.all_vars.union(new_vars)
4595
4596
4598 """ defined card that need to be initialized from the banner file
4599 from_banner should be a list of card to load from the banner object
4600 """
4601
4602 if from_banner is None:
4603 self.from_banner = {}
4604 return
4605
4606 self.from_banner = {}
4607 try:
4608 for card in from_banner:
4609 self.from_banner[card] = banner.charge_card(card)
4610 except KeyError:
4611 if from_banner == ['param', 'run'] and list(banner.keys()) == ['mgversion']:
4612 if self.mother_interface:
4613 results = self.mother_interface.results
4614 run_name = self.mother_interface.run_name
4615 run_tag = self.mother_interface.run_tag
4616 banner = banner_mod.recover_banner(results, 'parton', run_name, run_tag)
4617 self.mother_interface.banner = banner
4618 return self.init_from_banner(from_banner, banner)
4619 else:
4620 raise
4621
4622 return self.from_banner
4623
4624
4626 """initialise the path if requested"""
4627
4628 defname = '%s_default' % name
4629
4630 if name in self.from_banner:
4631 return self.from_banner[name]
4632
4633 if isinstance(cards, list):
4634 if name in cards:
4635 return True
4636 elif '%s_card.dat' % name in cards:
4637 return True
4638 elif name in self.paths and self.paths[name] in cards:
4639 return True
4640 else:
4641 cardnames = [os.path.basename(p) for p in cards]
4642 if '%s_card.dat' % name in cardnames:
4643 return True
4644 else:
4645 return False
4646
4647 elif isinstance(cards, dict) and name in cards:
4648 self.paths[name]= cards[name]
4649 if defname in cards:
4650 self.paths[defname] = cards[defname]
4651 elif os.path.isfile(cards[name].replace('.dat', '_default.dat')):
4652 self.paths[defname] = cards[name].replace('.dat', '_default.dat')
4653 else:
4654 self.paths[defname] = self.paths[name]
4655
4656 return True
4657 else:
4658 return False
4659
4661 """check if we need to load the param_card"""
4662
4663 self.pname2block = {}
4664 self.restricted_value = {}
4665 self.param_card = {}
4666
4667 is_valid_path = self.get_path('param', cards)
4668 if not is_valid_path:
4669 self.param_consistency = False
4670 return []
4671 if isinstance(is_valid_path, param_card_mod.ParamCard):
4672 self.param_card = is_valid_path
4673 self.param_consistency = False
4674 return []
4675
4676 try:
4677 self.param_card = param_card_mod.ParamCard(self.paths['param'])
4678 except (param_card_mod.InvalidParamCard, ValueError) as e:
4679 logger.error('Current param_card is not valid. We are going to use the default one.')
4680 logger.error('problem detected: %s' % e)
4681 files.cp(self.paths['param_default'], self.paths['param'])
4682 self.param_card = param_card_mod.ParamCard(self.paths['param'])
4683
4684
4685
4686
4687 if os.path.exists(self.paths['param_default']):
4688 default_param = param_card_mod.ParamCard(self.paths['param_default'])
4689 else:
4690 default_param = param_card_mod.ParamCard(self.param_card)
4691 self.pname2block, self.restricted_value = default_param.analyze_param_card()
4692 self.param_card_default = default_param
4693 return list(self.pname2block.keys())
4694
4696
4697 self.run_set = []
4698 is_valid_path = self.get_path('run', cards)
4699 if not is_valid_path:
4700 return []
4701 if isinstance(is_valid_path, banner_mod.RunCard):
4702 self.run_card = is_valid_path
4703 return []
4704
4705
4706 try:
4707 self.run_card = banner_mod.RunCard(self.paths['run'], consistency='warning')
4708 except IOError:
4709 self.run_card = {}
4710 try:
4711 run_card_def = banner_mod.RunCard(self.paths['run_default'])
4712 except IOError:
4713 run_card_def = {}
4714
4715
4716 if run_card_def:
4717 if self.run_card:
4718 self.run_set = list(run_card_def.keys()) + self.run_card.hidden_param
4719 else:
4720 self.run_set = list(run_card_def.keys()) + run_card_def.hidden_param
4721 elif self.run_card:
4722 self.run_set = list(self.run_card.keys())
4723 else:
4724 self.run_set = []
4725
4726 if self.run_set:
4727 self.special_shortcut.update(
4728 {'ebeam':([float],['run_card ebeam1 %(0)s', 'run_card ebeam2 %(0)s']),
4729 'lpp': ([int],['run_card lpp1 %(0)s', 'run_card lpp2 %(0)s' ]),
4730 'lhc': ([int],['run_card lpp1 1', 'run_card lpp2 1', 'run_card ebeam1 %(0)s*1000/2', 'run_card ebeam2 %(0)s*1000/2']),
4731 'lep': ([int],['run_card lpp1 0', 'run_card lpp2 0', 'run_card ebeam1 %(0)s/2', 'run_card ebeam2 %(0)s/2']),
4732 'ilc': ([int],['run_card lpp1 0', 'run_card lpp2 0', 'run_card ebeam1 %(0)s/2', 'run_card ebeam2 %(0)s/2']),
4733 'lcc': ([int],['run_card lpp1 1', 'run_card lpp2 1', 'run_card ebeam1 %(0)s*1000/2', 'run_card ebeam2 %(0)s*1000/2']),
4734 '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']),
4735 'no_parton_cut':([],['run_card nocut T']),
4736 'cm_velocity':([float], [lambda self :self.set_CM_velocity]),
4737 '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']),
4738 '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' ]),
4739 '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']),
4740 })
4741
4742 self.special_shortcut_help.update({
4743 'ebeam' : 'syntax: set ebeam VALUE:\n This parameter sets the energy to both beam to the value in GeV',
4744 'lpp' : 'syntax: set ebeam VALUE:\n'+\
4745 ' Set the type of beam to a given value for both beam\n'+\
4746 ' 0 : means no PDF\n'+\
4747 ' 1 : means proton PDF\n'+\
4748 ' -1 : means antiproton PDF\n'+\
4749 ' 2 : means PDF for elastic photon emited from a proton\n'+\
4750 ' 3 : means PDF for elastic photon emited from an electron',
4751 'lhc' : 'syntax: set lhc VALUE:\n Set for a proton-proton collision with that given center of mass energy (in TeV)',
4752 'lep' : 'syntax: set lep VALUE:\n Set for a electron-positron collision with that given center of mass energy (in GeV)',
4753 'fixed_scale' : 'syntax: set fixed_scale VALUE:\n Set all scales to the give value (in GeV)',
4754 'no_parton_cut': 'remove all cut (but BW_cutoff)',
4755 'cm_velocity': 'set sqrts to have the above velocity for the incoming particles',
4756 'pbpb': 'setup heavy ion configuration for lead-lead collision',
4757 'pbp': 'setup heavy ion configuration for lead-proton collision',
4758 'pp': 'remove setup of heavy ion configuration to set proton-proton collision',
4759 })
4760
4761 self.update_block += [b.name for b in self.run_card.blocks]
4762
4763 return self.run_set
4764
4766
4767 self.has_mw = False
4768 if not self.get_path('madweight', cards):
4769 return []
4770
4771
4772 self.do_change_tf = self.mother_interface.do_define_transfer_fct
4773 self.complete_change_tf = self.mother_interface.complete_define_transfer_fct
4774 self.help_change_tf = self.mother_interface.help_define_transfer_fct
4775 if not os.path.exists(self.paths['transfer']):
4776 logger.warning('No transfer function currently define. Please use the change_tf command to define one.')
4777
4778 self.has_mw = True
4779 try:
4780 import madgraph.madweight.Cards as mwcards
4781 except:
4782 import internal.madweight.Cards as mwcards
4783 self.mw_card = mwcards.Card(self.paths['MadWeight'])
4784 self.mw_card = self.mw_card.info
4785 self.mw_vars = []
4786 for key in self.mw_card:
4787 if key == 'comment':
4788 continue
4789 for key2 in self.mw_card.info[key]:
4790 if isinstance(key2, str) and not key2.isdigit():
4791 self.mw_vars.append(key2)
4792 return self.mw_vars
4793
4795
4796 if isinstance(cards, dict):
4797 for key in ['ML', 'madloop','MadLoop']:
4798 if key in cards:
4799 self.paths['ML'] = cards[key]
4800
4801 self.has_ml = False
4802 if os.path.isfile(self.paths['ML']):
4803 self.has_ml = True
4804 self.MLcard = banner_mod.MadLoopParam(self.paths['ML'])
4805 self.MLcardDefault = banner_mod.MadLoopParam()
4806 self.ml_vars = [k.lower() for k in self.MLcard.keys()]
4807 return self.ml_vars
4808 return []
4809
4811
4812 self.has_shower = False
4813 if not self.get_path('shower', cards):
4814 return []
4815 self.has_shower = True
4816 self.shower_card = shower_card_mod.ShowerCard(self.paths['shower'])
4817 self.shower_vars = list(self.shower_card.keys())
4818 return self.shower_vars
4819
4821
4822 self.has_PY8 = False
4823 if not self.get_path('pythia8', cards):
4824 return []
4825
4826 self.has_PY8 = True
4827 self.PY8Card = self.PY8Card_class(self.paths['pythia8'])
4828 self.PY8CardDefault = self.PY8Card_class()
4829
4830 self.py8_vars = [k.lower() for k in self.PY8Card.keys()]
4831
4832 self.special_shortcut.update({
4833 'simplepy8':([],['pythia8_card hadronlevel:all False',
4834 'pythia8_card partonlevel:mpi False',
4835 'pythia8_card BeamRemnants:primordialKT False',
4836 'pythia8_card PartonLevel:Remnants False',
4837 'pythia8_card Check:event False',
4838 'pythia8_card TimeShower:QEDshowerByQ False',
4839 'pythia8_card TimeShower:QEDshowerByL False',
4840 'pythia8_card SpaceShower:QEDshowerByQ False',
4841 'pythia8_card SpaceShower:QEDshowerByL False',
4842 'pythia8_card PartonLevel:FSRinResonances False',
4843 'pythia8_card ProcessLevel:resonanceDecays False',
4844 ]),
4845 'mpi':([bool],['pythia8_card partonlevel:mpi %(0)s']),
4846 })
4847 self.special_shortcut_help.update({
4848 'simplepy8' : 'Turn off non-perturbative slow features of Pythia8.',
4849 'mpi' : 'syntax: set mpi value: allow to turn mpi in Pythia8 on/off',
4850 })
4851 return []
4852
4854
4855 if not self.get_path('madspin', cards):
4856 return []
4857
4858 self.special_shortcut.update({
4859 'spinmode':([str], ['add madspin_card --before_line="launch" set spinmode %(0)s']),
4860 'nodecay':([], ['edit madspin_card --comment_line="decay"'])
4861 })
4862 self.special_shortcut_help.update({
4863 '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.',
4864 'nodecay': 'remove all decay previously defined in madspin',
4865 })
4866 return []
4867
4869
4870 self.has_delphes = False
4871 if not self.get_path('pythia8', cards):
4872 return []
4873 self.has_delphes = True
4874 return []
4875
4876
4878 """compute sqrts from the velocity in the center of mass frame"""
4879
4880 v = banner_mod.ConfigFile.format_variable(line, float, 'velocity')
4881
4882 self.mother_interface.get_characteristics()
4883 proc_info = self.mother_interface.proc_characteristics
4884 if 'pdg_initial1' not in proc_info:
4885 logger.warning('command not supported')
4886
4887 if len(proc_info['pdg_initial1']) == 1 == len(proc_info['pdg_initial2']) and\
4888 abs(proc_info['pdg_initial1'][0]) == abs(proc_info['pdg_initial2'][0]):
4889
4890 m = self.param_card.get_value('mass', abs(proc_info['pdg_initial1'][0]))
4891 sqrts = 2*m/ math.sqrt(1-v**2)
4892 self.do_set('run_card ebeam1 %s' % (sqrts/2.0))
4893 self.do_set('run_card ebeam2 %s' % (sqrts/2.0))
4894 self.do_set('run_card lpp 0')
4895 else:
4896 logger.warning('This is only possible for a single particle in the initial state')
4897
4898
4899
4900 - def do_help(self, line, conflict_raise=False, banner=True):
4901
4902
4903
4904 if banner:
4905 logger.info('*** HELP MESSAGE ***', '$MG:BOLD')
4906
4907 args = self.split_arg(line)
4908
4909 if len(args)==0 or (len(args) == 1 and hasattr(self, 'do_%s' % args[0])):
4910 out = cmd.BasicCmd.do_help(self, line)
4911 if len(args)==0:
4912 print('Allowed Argument')
4913 print('================')
4914 print('\t'.join(self.allow_arg))
4915 print()
4916 print('Special shortcut: (type help <name>)')
4917 print('====================================')
4918 print(' syntax: set <name> <value>')
4919 print('\t'.join(self.special_shortcut))
4920 print()
4921 if banner:
4922 logger.info('*** END HELP ***', '$MG:BOLD')
4923 return out
4924
4925
4926 if args[0] in self.special_shortcut:
4927 if args[0] in self.special_shortcut_help:
4928 print(self.special_shortcut_help[args[0]])
4929 if banner:
4930 logger.info('*** END HELP ***', '$MG:BOLD')
4931 return
4932
4933 start = 0
4934 card = ''
4935 if args[0]+'_card' in self.all_card_name+ self.cards:
4936 args[0] += '_card'
4937 elif args[0]+'.dat' in self.all_card_name+ self.cards:
4938 args[0] += '.dat'
4939 elif args[0]+'_card.dat' in self.all_card_name+ self.cards:
4940 args[0] += '_card.dat'
4941 if args[0] in self.all_card_name + self.cards:
4942 start += 1
4943 card = args[0]
4944 if len(args) == 1:
4945 if args[0] == 'pythia8_card':
4946 args[0] = 'PY8Card'
4947 if args[0] == 'param_card':
4948 logger.info("Param_card information: ", '$MG:color:BLUE')
4949 print("File to define the various model parameter")
4950 logger.info("List of the Block defined:",'$MG:color:BLUE')
4951 print("\t".join(list(self.param_card.keys())))
4952 elif args[0].startswith('madanalysis5'):
4953 print('This card allow to make plot with the madanalysis5 package')
4954 print('An example card is provided. For more information about the ')
4955 print('syntax please refer to: https://madanalysis.irmp.ucl.ac.be/')
4956 print('or to the user manual [arXiv:1206.1599]')
4957 if args[0].startswith('madanalysis5_hadron'):
4958 print()
4959 print('This card also allow to make recasting analysis')
4960 print('For more detail, see: arXiv:1407.3278')
4961 elif hasattr(self, args[0]):
4962 logger.info("%s information: " % args[0], '$MG:color:BLUE')
4963 print((eval('self.%s' % args[0]).__doc__))
4964 logger.info("List of parameter associated", '$MG:color:BLUE')
4965 print("\t".join(list(eval('self.%s' % args[0]).keys())))
4966 if banner:
4967 logger.info('*** END HELP ***', '$MG:BOLD')
4968 return card
4969
4970
4971 if args[start] in [l.lower() for l in self.run_card.keys()] and card in ['', 'run_card']:
4972 if args[start] not in self.run_set:
4973 args[start] = [l for l in self.run_set if l.lower() == args[start]][0]
4974
4975 if args[start] in self.conflict and not conflict_raise:
4976 conflict_raise = True
4977 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
4978 if card == '':
4979 logger.info('** If not explicitely speficy this parameter will modif the run_card file', '$MG:BOLD')
4980
4981 self.run_card.do_help(args[start])
4982
4983 elif (args[start] in self.param_card or args[start] == 'width') \
4984 and card in ['','param_card']:
4985 if args[start] in self.conflict and not conflict_raise:
4986 conflict_raise = True
4987 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
4988 if card == '':
4989 logger.info('** If not explicitely speficy this parameter will modif the param_card file', '$MG:BOLD')
4990
4991 if args[start] == 'width':
4992 args[start] = 'decay'
4993
4994 if len(args) == start+1:
4995 self.param_card.do_help(args[start], tuple())
4996 key = None
4997 elif args[start+1] in self.pname2block:
4998 all_var = self.pname2block[args[start+1]]
4999 key = None
5000 for bname, lhaid in all_var:
5001 if bname == args[start]:
5002 key = lhaid
5003 break
5004 else:
5005 logger.warning('%s is not part of block "%s" but "%s". please correct.' %
5006 (args[start+1], args[start], bname))
5007 else:
5008 try:
5009 key = tuple([int(i) for i in args[start+1:]])
5010 except ValueError:
5011 logger.warning('Failed to identify LHA information')
5012 return card
5013
5014 if key in self.param_card[args[start]].param_dict:
5015 self.param_card.do_help(args[start], key, default=self.param_card_default)
5016 elif key:
5017 logger.warning('invalid information: %s not defined in the param_card' % (key,))
5018
5019 elif args[start] in self.pname2block and card in ['','param_card']:
5020 if args[start] in self.conflict and not conflict_raise:
5021 conflict_raise = True
5022 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
5023 if card == '':
5024 logger.info('** If not explicitely speficy this parameter will modif the param_card file', '$MG:BOLD')
5025
5026 all_var = self.pname2block[args[start]]
5027 for bname, lhaid in all_var:
5028 new_line = 'param_card %s %s %s' % (bname,
5029 ' '.join([ str(i) for i in lhaid]), ' '.join(args[start+1:]))
5030 self.do_help(new_line, conflict_raise=True, banner=False)
5031
5032
5033 elif self.has_ml and args[start] in self.ml_vars \
5034 and card in ['', 'MadLoop_card']:
5035
5036 if args[start] in self.conflict and not conflict_raise:
5037 conflict_raise = True
5038 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
5039 if card == '':
5040 logger.info('** If not explicitely speficy this parameter will modif the madloop_card file', '$MG:BOLD')
5041
5042 self.MLcard.do_help(args[start])
5043
5044
5045 elif self.has_PY8 and args[start] in self.PY8Card:
5046 if args[start] in self.conflict and not conflict_raise:
5047 conflict_raise = True
5048 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
5049 if card == '':
5050 logger.info('** If not explicitely speficy this parameter will modif the pythia8_card file', '$MG:BOLD')
5051
5052 self.PY8Card.do_help(args[start])
5053 elif card.startswith('madanalysis5'):
5054 print('MA5')
5055
5056
5057 elif banner:
5058 print("no help available")
5059
5060 if banner:
5061 logger.info('*** END HELP ***', '$MG:BOLD')
5062
5063 return card
5064
5065
5066
5067
5068
5069
5071 prev_timer = signal.alarm(0)
5072 if prev_timer:
5073 nb_back = len(line)
5074 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
5075 self.stdout.write(line)
5076 self.stdout.flush()
5077
5078 possibilities = self.complete_set(text, line, begidx, endidx,formatting=False)
5079 if line[:begidx].strip() == 'help':
5080 possibilities['Defined command'] = cmd.BasicCmd.completenames(self, text, line)
5081 possibilities.update(self.complete_add(text, line, begidx, endidx,formatting=False))
5082 return self.deal_multiple_categories(possibilities)
5083
5084
5085
5086
5087
5089 prev_timer = signal.alarm(0)
5090 if prev_timer:
5091 nb_back = len(line)
5092 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
5093 self.stdout.write(line)
5094 self.stdout.flush()
5095
5096 valid = ['dependent', 'missing', 'to_slha1', 'to_slha2', 'to_full']
5097 valid += self.update_block
5098
5099 arg = line[:begidx].split()
5100 if len(arg) <=1:
5101 return self.list_completion(text, valid, line)
5102 elif arg[0] == 'to_full':
5103 return self.list_completion(text, self.cards , line)
5104
5105 - def complete_set(self, text, line, begidx, endidx, formatting=True):
5106 """ Complete the set command"""
5107
5108 prev_timer = signal.alarm(0)
5109 if prev_timer:
5110 nb_back = len(line)
5111 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
5112 self.stdout.write(line)
5113 self.stdout.flush()
5114
5115 possibilities = {}
5116 allowed = {}
5117 args = self.split_arg(line[0:begidx])
5118 if args[-1] in ['Auto', 'default']:
5119 return
5120
5121 if len(args) == 1:
5122 allowed = {'category':'', 'run_card':'', 'block':'all', 'param_card':'','shortcut':''}
5123 if self.has_mw:
5124 allowed['madweight_card'] = ''
5125 allowed['mw_block'] = 'all'
5126 if self.has_shower:
5127 allowed['shower_card'] = ''
5128 if self.has_ml:
5129 allowed['madloop_card'] = ''
5130 if self.has_PY8:
5131 allowed['pythia8_card'] = ''
5132 if self.has_delphes:
5133 allowed['delphes_card'] = ''
5134
5135 elif len(args) == 2:
5136 if args[1] == 'run_card':
5137 allowed = {'run_card':'default'}
5138 elif args[1] == 'param_card':
5139 allowed = {'block':'all', 'param_card':'default'}
5140 elif self.param_card and args[1] in list(self.param_card.keys()):
5141 allowed = {'block':args[1]}
5142 elif args[1] == 'width':
5143 allowed = {'block': 'decay'}
5144 elif args[1] == 'MadWeight_card':
5145 allowed = {'madweight_card':'default', 'mw_block': 'all'}
5146 elif args[1] == 'MadLoop_card':
5147 allowed = {'madloop_card':'default'}
5148 elif args[1] == 'pythia8_card':
5149 allowed = {'pythia8_card':'default'}
5150 elif self.has_mw and args[1] in list(self.mw_card.keys()):
5151 allowed = {'mw_block':args[1]}
5152 elif args[1] == 'shower_card':
5153 allowed = {'shower_card':'default'}
5154 elif args[1] == 'delphes_card':
5155 allowed = {'delphes_card':'default'}
5156 else:
5157 allowed = {'value':''}
5158
5159 else:
5160 start = 1
5161 if args[1] in ['run_card', 'param_card', 'MadWeight_card', 'shower_card',
5162 'MadLoop_card','pythia8_card','delphes_card','plot_card',
5163 'madanalysis5_parton_card','madanalysis5_hadron_card']:
5164 start = 2
5165
5166 if args[-1] in list(self.pname2block.keys()):
5167 allowed['value'] = 'default'
5168 elif args[start] in list(self.param_card.keys()) or args[start] == 'width':
5169 if args[start] == 'width':
5170 args[start] = 'decay'
5171
5172 if args[start+1:]:
5173 allowed = {'block':(args[start], args[start+1:])}
5174 else:
5175 allowed = {'block':args[start]}
5176 elif self.has_mw and args[start] in list(self.mw_card.keys()):
5177 if args[start+1:]:
5178 allowed = {'mw_block':(args[start], args[start+1:])}
5179 else:
5180 allowed = {'mw_block':args[start]}
5181
5182
5183 else:
5184 allowed['value'] = ''
5185
5186 if 'category' in list(allowed.keys()):
5187 categories = ['run_card', 'param_card']
5188 if self.has_mw:
5189 categories.append('MadWeight_card')
5190 if self.has_shower:
5191 categories.append('shower_card')
5192 if self.has_ml:
5193 categories.append('MadLoop_card')
5194 if self.has_PY8:
5195 categories.append('pythia8_card')
5196 if self.has_delphes:
5197 categories.append('delphes_card')
5198
5199 possibilities['category of parameter (optional)'] = \
5200 self.list_completion(text, categories)
5201
5202 if 'shortcut' in list(allowed.keys()):
5203 possibilities['special values'] = self.list_completion(text, list(self.special_shortcut.keys())+['qcut', 'showerkt'])
5204
5205 if 'run_card' in list(allowed.keys()):
5206 opts = self.run_set
5207 if allowed['run_card'] == 'default':
5208 opts.append('default')
5209
5210
5211 possibilities['Run Card'] = self.list_completion(text, opts)
5212
5213 if 'param_card' in list(allowed.keys()):
5214 opts = list(self.pname2block.keys())
5215 if allowed['param_card'] == 'default':
5216 opts.append('default')
5217 possibilities['Param Card'] = self.list_completion(text, opts)
5218
5219 if 'madweight_card' in list(allowed.keys()):
5220 opts = self.mw_vars + [k for k in self.mw_card.keys() if k !='comment']
5221 if allowed['madweight_card'] == 'default':
5222 opts.append('default')
5223 possibilities['MadWeight Card'] = self.list_completion(text, opts)
5224
5225 if 'madloop_card' in list(allowed.keys()):
5226 opts = self.ml_vars
5227 if allowed['madloop_card'] == 'default':
5228 opts.append('default')
5229 possibilities['MadLoop Parameter'] = self.list_completion(text, opts)
5230
5231 if 'pythia8_card' in list(allowed.keys()):
5232 opts = self.py8_vars
5233 if allowed['pythia8_card'] == 'default':
5234 opts.append('default')
5235 possibilities['Pythia8 Parameter'] = self.list_completion(text, opts)
5236
5237 if 'shower_card' in list(allowed.keys()):
5238 opts = self.shower_vars + [k for k in self.shower_card.keys() if k !='comment']
5239 if allowed['shower_card'] == 'default':
5240 opts.append('default')
5241 possibilities['Shower Card'] = self.list_completion(text, opts)
5242
5243 if 'delphes_card' in allowed:
5244 if allowed['delphes_card'] == 'default':
5245 opts = ['default', 'atlas', 'cms']
5246 possibilities['Delphes Card'] = self.list_completion(text, opts)
5247
5248 if 'value' in list(allowed.keys()):
5249 opts = ['default']
5250 if 'decay' in args:
5251 opts.append('Auto')
5252 opts.append('Auto@NLO')
5253 elif args[-1] in self.pname2block and self.pname2block[args[-1]][0][0] == 'decay':
5254 opts.append('Auto')
5255 opts.append('Auto@NLO')
5256 if args[-1] in self.run_set:
5257 allowed_for_run = []
5258 if args[-1].lower() in self.run_card.allowed_value:
5259 allowed_for_run = self.run_card.allowed_value[args[-1].lower()]
5260 if '*' in allowed_for_run:
5261 allowed_for_run.remove('*')
5262 elif isinstance(self.run_card[args[-1]], bool):
5263 allowed_for_run = ['True', 'False']
5264 opts += [str(i) for i in allowed_for_run]
5265
5266
5267 possibilities['Special Value'] = self.list_completion(text, opts)
5268
5269 if 'block' in list(allowed.keys()) and self.param_card:
5270 if allowed['block'] == 'all' and self.param_card:
5271 allowed_block = [i for i in self.param_card.keys() if 'qnumbers' not in i]
5272 allowed_block.append('width')
5273 possibilities['Param Card Block' ] = \
5274 self.list_completion(text, allowed_block)
5275
5276 elif isinstance(allowed['block'], six.string_types):
5277 block = self.param_card[allowed['block']].param_dict
5278 ids = [str(i[0]) for i in block
5279 if (allowed['block'], i) not in self.restricted_value]
5280 possibilities['Param Card id' ] = self.list_completion(text, ids)
5281 varname = [name for name, all_var in self.pname2block.items()
5282 if any((bname == allowed['block']
5283 for bname,lhaid in all_var))]
5284 possibilities['Param card variable'] = self.list_completion(text,
5285 varname)
5286 else:
5287 block = self.param_card[allowed['block'][0]].param_dict
5288 nb = len(allowed['block'][1])
5289 ids = [str(i[nb]) for i in block if len(i) > nb and \
5290 [str(a) for a in i[:nb]] == allowed['block'][1]]
5291
5292 if not ids:
5293 if tuple([int(i) for i in allowed['block'][1]]) in block:
5294 opts = ['default']
5295 if allowed['block'][0] == 'decay':
5296 opts.append('Auto')
5297 opts.append('Auto@NLO')
5298 possibilities['Special value'] = self.list_completion(text, opts)
5299 possibilities['Param Card id' ] = self.list_completion(text, ids)
5300
5301 if 'mw_block' in list(allowed.keys()):
5302 if allowed['mw_block'] == 'all':
5303 allowed_block = [i for i in self.mw_card.keys() if 'comment' not in i]
5304 possibilities['MadWeight Block' ] = \
5305 self.list_completion(text, allowed_block)
5306 elif isinstance(allowed['mw_block'], six.string_types):
5307 block = self.mw_card[allowed['mw_block']]
5308 ids = [str(i[0]) if isinstance(i, tuple) else str(i) for i in block]
5309 possibilities['MadWeight Card id' ] = self.list_completion(text, ids)
5310 else:
5311 block = self.mw_card[allowed['mw_block'][0]]
5312 nb = len(allowed['mw_block'][1])
5313 ids = [str(i[nb]) for i in block if isinstance(i, tuple) and\
5314 len(i) > nb and \
5315 [str(a) for a in i[:nb]] == allowed['mw_block'][1]]
5316
5317 if not ids:
5318 if tuple([i for i in allowed['mw_block'][1]]) in block or \
5319 allowed['mw_block'][1][0] in list(block.keys()):
5320 opts = ['default']
5321 possibilities['Special value'] = self.list_completion(text, opts)
5322 possibilities['MadWeight Card id' ] = self.list_completion(text, ids)
5323
5324 return self.deal_multiple_categories(possibilities, formatting)
5325
5327 """ edit the value of one parameter in the card"""
5328
5329
5330 args = self.split_arg(line)
5331
5332
5333 if len(args) == 0:
5334 logger.warning("No argument. For help type 'help set'.")
5335
5336 if len(args)==1 and '=' in args[-1]:
5337 arg1, arg2 = args.pop(-1).split('=',1)
5338 args += [arg1, arg2]
5339 if '=' in args:
5340 args.remove('=')
5341
5342 args[:-1] = [ a.lower() for a in args[:-1]]
5343 if len(args) == 1:
5344 args = [args[0].lower()]
5345
5346 if args[0] in self.special_shortcut:
5347 targettypes , cmd = self.special_shortcut[args[0]]
5348 if len(args) != len(targettypes) +1:
5349 logger.warning('shortcut %s requires %s argument' % (args[0], len(targettypes)))
5350 if len(args) < len(targettypes) +1:
5351 return
5352 else:
5353 logger.warning('additional argument will be ignored')
5354 values ={}
5355 for i, argtype in enumerate(targettypes):
5356 try:
5357 values = {str(i): banner_mod.ConfigFile.format_variable(args[i+1], argtype, args[0])}
5358 except ValueError as e:
5359 logger.warning("Wrong argument: The entry #%s should be of type %s.", i+1, argtype)
5360 return
5361 except InvalidCmd as e:
5362 logger.warning(str(e))
5363 return
5364
5365
5366
5367 for arg in cmd:
5368 if isinstance(arg, str):
5369 try:
5370 text = arg % values
5371 except KeyError:
5372 logger.warning("This command requires one argument")
5373 return
5374 except Exception as e:
5375 logger.warning(str(e))
5376 return
5377 else:
5378 split = text.split()
5379 if hasattr(self, 'do_%s' % split[0]):
5380 getattr(self, 'do_%s' % split[0])(' '.join(split[1:]))
5381 else:
5382 self.do_set(text)
5383
5384 else:
5385 val = [values[str(i)] for i in range(len(values))]
5386 try:
5387 arg(self)(*val)
5388 except Exception as e:
5389 logger.warning(str(e))
5390 return
5391
5392 start = 0
5393 if len(args) < 2:
5394 logger.warning('Invalid set command %s (need two arguments)' % line)
5395 return
5396
5397
5398 if args[0].lower() == 'qcut':
5399 pythia_path = self.paths['pythia']
5400 if os.path.exists(pythia_path):
5401 logger.info('add line QCUT = %s in pythia_card.dat' % args[1])
5402 p_card = open(pythia_path,'r').read()
5403 p_card, n = re.subn('''^\s*QCUT\s*=\s*[\de\+\-\.]*\s*$''',
5404 ''' QCUT = %s ''' % args[1], \
5405 p_card, flags=(re.M+re.I))
5406 if n==0:
5407 p_card = '%s \n QCUT= %s' % (p_card, args[1])
5408 with open(pythia_path, 'w') as fsock:
5409 fsock.write(p_card)
5410 return
5411
5412 if args[0].lower() == 'showerkt':
5413 pythia_path = self.paths['pythia']
5414 if os.path.exists(pythia_path):
5415 logger.info('add line SHOWERKT = %s in pythia_card.dat' % args[1].upper())
5416 p_card = open(pythia_path,'r').read()
5417 p_card, n = re.subn('''^\s*SHOWERKT\s*=\s*[default\de\+\-\.]*\s*$''',
5418 ''' SHOWERKT = %s ''' % args[1].upper(), \
5419 p_card, flags=(re.M+re.I))
5420 if n==0:
5421 p_card = '%s \n SHOWERKT= %s' % (p_card, args[1].upper())
5422 with open(pythia_path, 'w') as fsock:
5423 fsock.write(p_card)
5424 return
5425
5426 card = ''
5427 if args[0] == 'madweight_card':
5428 if not self.mw_card:
5429 logger.warning('Invalid Command: No MadWeight card defined.')
5430 return
5431 args[0] = 'MadWeight_card'
5432
5433 if args[0] == 'shower_card':
5434 if not self.shower_card:
5435 logger.warning('Invalid Command: No Shower card defined.')
5436 return
5437 args[0] = 'shower_card'
5438
5439 if args[0] == "madloop_card":
5440 if not self.has_ml:
5441 logger.warning('Invalid Command: No MadLoopParam card defined.')
5442 return
5443 args[0] = 'MadLoop_card'
5444
5445 if args[0] == "pythia8_card":
5446 if not self.has_PY8:
5447 logger.warning('Invalid Command: No Pythia8 card defined.')
5448 return
5449 args[0] = 'pythia8_card'
5450
5451 if args[0] == 'delphes_card':
5452 if not self.has_delphes:
5453 logger.warning('Invalid Command: No Delphes card defined.')
5454 return
5455 if args[1] == 'atlas':
5456 logger.info("set default ATLAS configuration for Delphes", '$MG:BOLD')
5457 files.cp(pjoin(self.me_dir,'Cards', 'delphes_card_ATLAS.dat'),
5458 pjoin(self.me_dir,'Cards', 'delphes_card.dat'))
5459 return
5460 elif args[1] == 'cms':
5461 logger.info("set default CMS configuration for Delphes",'$MG:BOLD')
5462 files.cp(pjoin(self.me_dir,'Cards', 'delphes_card_CMS.dat'),
5463 pjoin(self.me_dir,'Cards', 'delphes_card.dat'))
5464 return
5465
5466 if args[0] in ['run_card', 'param_card', 'MadWeight_card', 'shower_card',
5467 'delphes_card','madanalysis5_hadron_card','madanalysis5_parton_card']:
5468
5469 if args[1] == 'default':
5470 logger.info('replace %s by the default card' % args[0],'$MG:BOLD')
5471 files.cp(self.paths['%s_default' %args[0][:-5]], self.paths[args[0][:-5]])
5472 if args[0] == 'param_card':
5473 self.param_card = param_card_mod.ParamCard(self.paths['param'])
5474 elif args[0] == 'run_card':
5475 self.run_card = banner_mod.RunCard(self.paths['run'])
5476 elif args[0] == 'shower_card':
5477 self.shower_card = shower_card_mod.ShowerCard(self.paths['shower'])
5478 return
5479 else:
5480 card = args[0]
5481 start=1
5482 if len(args) < 3:
5483 logger.warning('Invalid set command: %s (not enough arguments)' % line)
5484 return
5485
5486 elif args[0] in ['MadLoop_card']:
5487 if args[1] == 'default':
5488 logger.info('replace MadLoopParams.dat by the default card','$MG:BOLD')
5489 self.MLcard = banner_mod.MadLoopParam(self.MLcardDefault)
5490 self.MLcard.write(self.paths['ML'],
5491 commentdefault=True)
5492 return
5493 else:
5494 card = args[0]
5495 start=1
5496 if len(args) < 3:
5497 logger.warning('Invalid set command: %s (not enough arguments)' % line)
5498 return
5499 elif args[0] in ['pythia8_card']:
5500 if args[1] == 'default':
5501 logger.info('replace pythia8_card.dat by the default card','$MG:BOLD')
5502 self.PY8Card = self.PY8Card_class(self.PY8CardDefault)
5503 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'),
5504 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'),
5505 print_only_visible=True)
5506 return
5507 else:
5508 card = args[0]
5509 start=1
5510 if len(args) < 3:
5511 logger.warning('Invalid set command: %s (not enough arguments)' % line)
5512 return
5513 elif args[0] in ['madspin_card']:
5514 if args[1] == 'default':
5515 logger.info('replace madspin_card.dat by the default card','$MG:BOLD')
5516 files.cp(self.paths['MS_default'], self.paths['madspin'])
5517 return
5518 else:
5519 logger.warning("""Command set not allowed for modifying the madspin_card.
5520 Check the command \"decay\" instead.""")
5521 return
5522
5523
5524 if args[start] in [l.lower() for l in self.run_card.keys()] and card in ['', 'run_card']:
5525
5526 if args[start] not in self.run_set:
5527 if card in self.from_banner or 'run' in self.from_banner:
5528 raise Exception("change not allowed for this card: event already generated!")
5529 args[start] = [l for l in self.run_set if l.lower() == args[start]][0]
5530
5531 if args[start] in self.conflict and card == '':
5532 text = 'Ambiguous name (present in more than one card). Will assume it to be referred to run_card.\n'
5533 text += 'If this is not intended, please reset it in the run_card and specify the relevant card to \n'
5534 text += 'edit, in the format < set card parameter value >'
5535 logger.warning(text)
5536
5537 if args[start+1] == 'default':
5538 default = banner_mod.RunCard(self.paths['run_default'])
5539 if args[start] in list(default.keys()):
5540 self.setR(args[start],default[args[start]])
5541 else:
5542 logger.info('remove information %s from the run_card' % args[start],'$MG:BOLD')
5543 del self.run_card[args[start]]
5544 else:
5545 lower_name = args[0].lower()
5546 if lower_name.startswith('sys_') or \
5547 lower_name in self.run_card.list_parameter or \
5548 lower_name in self.run_card.dict_parameter:
5549 val = ' '.join(args[start+1:])
5550 val = val.split('#')[0]
5551 else:
5552 val = ' '.join(args[start+1:])
5553 self.setR(args[start], val)
5554 self.modified_card.add('run')
5555
5556 elif card == 'run_card' and args[start] in ['nocut', 'no_cut']:
5557 logger.info("Going to remove all cuts from the run_card", '$MG:BOLD')
5558 self.run_card.remove_all_cut()
5559 self.modified_card.add('run')
5560
5561 elif self.param_card and (args[start] in self.param_card or args[start] == 'width') \
5562 and card in ['','param_card']:
5563
5564 if any(t.startswith('scan') for t in args):
5565 index = [i for i,t in enumerate(args) if t.startswith('scan')][0]
5566 args = args[:index] + [' '.join(args[index:])]
5567
5568 if args[start] in self.conflict and card == '':
5569 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5570 text += ' in the format < set card parameter value>'
5571 logger.warning(text)
5572 return
5573
5574 if args[start] == 'width':
5575 args[start] = 'decay'
5576
5577 if args[start+1] in self.pname2block:
5578 all_var = self.pname2block[args[start+1]]
5579 key = None
5580 for bname, lhaid in all_var:
5581 if bname == args[start]:
5582 key = lhaid
5583 break
5584 else:
5585 logger.warning('%s is not part of block "%s" but "%s". please correct.' %
5586 (args[start+1], args[start], bname))
5587 return
5588 else:
5589 try:
5590 key = tuple([int(i) for i in args[start+1:-1]])
5591 except ValueError:
5592 if args[start+1:-1] == ['all']:
5593 for key in self.param_card[args[start]].param_dict:
5594 if (args[start], key) in self.restricted_value:
5595 continue
5596 else:
5597 self.setP(args[start], key, args[-1])
5598 self.modified_card.add('param')
5599 return
5600 logger.warning('invalid set command %s (failed to identify LHA information)' % line)
5601 return
5602
5603 if key in self.param_card[args[start]].param_dict:
5604 if (args[start], key) in self.restricted_value:
5605 text = "Note that this parameter seems to be ignore by MG.\n"
5606 text += "MG will use instead the expression: %s\n" % \
5607 self.restricted_value[(args[start], key)]
5608 text += "You need to match this expression for external program (such pythia)."
5609 logger.warning(text)
5610
5611 if args[-1].lower() in ['default', 'auto', 'auto@nlo'] or args[-1].startswith('scan'):
5612 self.setP(args[start], key, args[-1])
5613 else:
5614 try:
5615 value = float(args[-1])
5616 except Exception:
5617 logger.warning('Invalid input: Expected number and not \'%s\'' \
5618 % args[-1])
5619 return
5620 self.setP(args[start], key, value)
5621 else:
5622 logger.warning('invalid set command %s' % line)
5623 return
5624 self.modified_card.add('param')
5625
5626
5627 elif args[start] in self.pname2block and card in ['','param_card']:
5628 if args[start] in self.conflict and card == '':
5629 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5630 text += ' in the format < set card parameter value>'
5631 logger.warning(text)
5632 return
5633
5634 all_var = self.pname2block[args[start]]
5635 for bname, lhaid in all_var:
5636 new_line = 'param_card %s %s %s' % (bname,
5637 ' '.join([ str(i) for i in lhaid]), ' '.join(args[start+1:]))
5638 self.do_set(new_line)
5639 if len(all_var) > 1:
5640 logger.warning('This variable correspond to more than one parameter in the param_card.')
5641 for bname, lhaid in all_var:
5642 logger.warning(' %s %s' % (bname, ' '.join([str(i) for i in lhaid])))
5643 logger.warning('all listed variables have been modified')
5644
5645
5646 elif self.has_mw and (args[start] in self.mw_card and args[start] != 'comment') \
5647 and card in ['','MadWeight_card']:
5648
5649 if args[start] in self.conflict and card == '':
5650 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5651 text += ' in the format < set card parameter value>'
5652 logger.warning(text)
5653 return
5654
5655 block = args[start]
5656 name = args[start+1]
5657 value = args[start+2:]
5658 self.setM(block, name, value)
5659 self.mw_card.write(self.paths['MadWeight'])
5660
5661
5662 elif self.has_mw and args[start] in self.mw_vars \
5663 and card in ['', 'MadWeight_card']:
5664
5665 if args[start] in self.conflict and card == '':
5666 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5667 text += ' in the format < set card parameter value>'
5668 logger.warning(text)
5669 return
5670
5671 block = [b for b, data in self.mw_card.items() if args[start] in data]
5672 if len(block) > 1:
5673 logger.warning('%s is define in more than one block: %s.Please specify.'
5674 % (args[start], ','.join(block)))
5675 return
5676
5677 block = block[0]
5678 name = args[start]
5679 value = args[start+1:]
5680 self.setM(block, name, value)
5681 self.mw_card.write(self.paths['MadWeight'])
5682
5683
5684 elif self.has_mw and args[start].startswith('mw_') and len(args[start:]) == 3\
5685 and card == 'MadWeight_card':
5686 block = args[start]
5687 name = args[start+1]
5688 value = args[start+2]
5689 self.setM(block, name, value)
5690 self.mw_card.write(self.paths['MadWeight'])
5691
5692
5693 elif self.has_shower and args[start].lower() in [l.lower() for l in \
5694 self.shower_card.keys()] and card in ['', 'shower_card']:
5695 if args[start] not in self.shower_card:
5696 args[start] = [l for l in self.shower_card if l.lower() == args[start].lower()][0]
5697
5698 if args[start] in self.conflict and card == '':
5699 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5700 text += ' in the format < set card parameter value>'
5701 logger.warning(text)
5702 return
5703
5704 if args[start+1].lower() == 'default':
5705 default = shower_card_mod.ShowerCard(self.paths['shower_default'])
5706 if args[start] in list(default.keys()):
5707 self.shower_card.set_param(args[start],default[args[start]], self.paths['shower'])
5708 else:
5709 logger.info('remove information %s from the shower_card' % args[start],'$MG:BOLD')
5710 del self.shower_card[args[start]]
5711 elif args[start+1].lower() in ['t','.true.','true']:
5712 self.shower_card.set_param(args[start],'.true.',self.paths['shower'])
5713 elif args[start+1].lower() in ['f','.false.','false']:
5714 self.shower_card.set_param(args[start],'.false.',self.paths['shower'])
5715 elif args[start] in ['analyse', 'extralibs', 'extrapaths', 'includepaths'] or\
5716 args[start].startswith('dm_'):
5717
5718 args = line.split()
5719 args_str = ' '.join(str(a) for a in args[start+1:len(args)])
5720 self.shower_card.set_param(args[start],args_str,pjoin(self.me_dir,'Cards','shower_card.dat'))
5721 else:
5722 args_str = ' '.join(str(a) for a in args[start+1:len(args)])
5723 self.shower_card.set_param(args[start],args_str,self.paths['shower'])
5724
5725
5726 elif self.has_ml and args[start] in self.ml_vars \
5727 and card in ['', 'MadLoop_card']:
5728
5729 if args[start] in self.conflict and card == '':
5730 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5731 logger.warning(text)
5732 return
5733
5734 if args[start+1] == 'default':
5735 value = self.MLcardDefault[args[start]]
5736 default = True
5737 else:
5738 value = args[start+1]
5739 default = False
5740 self.setML(args[start], value, default=default)
5741 self.MLcard.write(self.paths['ML'],
5742 commentdefault=True)
5743
5744
5745 elif self.has_PY8 and (card == 'pythia8_card' or (card == '' and \
5746 args[start] in self.PY8Card)):
5747
5748 if args[start] in self.conflict and card == '':
5749 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5750 logger.warning(text)
5751 return
5752
5753 if args[start+1] == 'default':
5754 value = self.PY8CardDefault[args[start]]
5755 default = True
5756 else:
5757 value = ' '.join(args[start+1:])
5758 default = False
5759 self.setPY8(args[start], value, default=default)
5760 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'),
5761 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'),
5762 print_only_visible=True)
5763
5764
5765 else:
5766 logger.warning('invalid set command %s ' % line)
5767 arg = args[start].lower()
5768 if self.has_PY8:
5769 close_opts = [name for name in self.PY8Card if name.lower().startswith(arg[:3]) or arg in name.lower()]
5770 if close_opts:
5771 logger.info('Did you mean one of the following PY8 options:\n%s' % '\t'.join(close_opts))
5772 if self.run_card:
5773 close_opts = [name for name in self.run_card if name.lower().startswith(arg[:3]) or arg in name.lower()]
5774 if close_opts:
5775 logger.info('Did you mean one of the following run_card options:\n%s' % '\t'.join(close_opts))
5776
5777 return
5778
5779 - def setM(self, block, name, value):
5780
5781 if isinstance(value, list) and len(value) == 1:
5782 value = value[0]
5783
5784 if block not in self.mw_card:
5785 logger.warning('block %s was not present in the current MadWeight card. We are adding it' % block)
5786 self.mw_card[block] = {}
5787 elif name not in self.mw_card[block]:
5788 logger.info('name %s was not present in the block %s for the current MadWeight card. We are adding it' % (name,block),'$MG:BOLD')
5789 if value == 'default':
5790 import madgraph.madweight.Cards as mwcards
5791 mw_default = mwcards.Card(self.paths['MadWeight_default'])
5792 try:
5793 value = mw_default[block][name]
5794 except KeyError:
5795 logger.info('removing id "%s" from Block "%s" '% (name, block),'$MG:BOLD')
5796 if name in self.mw_card[block]:
5797 del self.mw_card[block][name]
5798 return
5799 if value:
5800 logger.info('modify madweight_card information BLOCK "%s" with id "%s" set to %s',
5801 block, name, value, '$MG:BOLD')
5802 else:
5803 logger.warning("Invalid command: No value. To set default value. Use \"default\" as value")
5804 return
5805
5806 self.mw_card[block][name] = value
5807
5808 - def setR(self, name, value):
5809
5810 if self.mother_interface.inputfile:
5811 self.run_card.set(name, value, user=True, raiseerror=True)
5812 else:
5813 self.run_card.set(name, value, user=True)
5814 new_value = self.run_card.get(name)
5815 logger.info('modify parameter %s of the run_card.dat to %s' % (name, new_value),'$MG:BOLD')
5816
5817
5818 - def setML(self, name, value, default=False):
5819
5820 try:
5821 self.MLcard.set(name, value, user=True)
5822 except Exception as error:
5823 logger.warning("Fail to change parameter. Please Retry. Reason: %s." % error)
5824 return
5825 logger.info('modify parameter %s of the MadLoopParam.dat to %s' % (name, value),'$MG:BOLD')
5826 if default and name.lower() in self.MLcard.user_set:
5827 self.MLcard.user_set.remove(name.lower())
5828
5829 - def setPY8(self, name, value, default=False):
5838
5839 - def setP(self, block, lhaid, value):
5840 if isinstance(value, str):
5841 value = value.lower()
5842 if value == 'default':
5843 default = param_card_mod.ParamCard(self.paths['param_default'])
5844 value = default[block].param_dict[lhaid].value
5845
5846 elif value in ['auto', 'auto@nlo']:
5847 if 'nlo' in value:
5848 value = 'Auto@NLO'
5849 else:
5850 value = 'Auto'
5851 if block != 'decay':
5852 logger.warning('Invalid input: \'Auto\' value only valid for DECAY')
5853 return
5854 elif value.startswith('scan'):
5855 if ':' not in value:
5856 logger.warning('Invalid input: \'scan\' mode requires a \':\' before the definition.')
5857 return
5858 tag = value.split(':')[0]
5859 tag = tag[4:].strip()
5860 if tag and not tag.isdigit():
5861 logger.warning('Invalid input: scan tag need to be integer and not "%s"' % tag)
5862 return
5863
5864
5865 pass
5866 else:
5867 try:
5868 value = float(value)
5869 except ValueError:
5870 logger.warning('Invalid input: \'%s\' not valid intput.'% value)
5871
5872 logger.info('modify param_card information BLOCK %s with id %s set to %s' %\
5873 (block, lhaid, value), '$MG:BOLD')
5874 self.param_card[block].param_dict[lhaid].value = value
5875
5877 """This is run on quitting the class. Apply here all the self-consistency
5878 rule that you want. Do the modification via the set command."""
5879
5880
5881
5882
5883 if isinstance(self.run_card,banner_mod.RunCardLO):
5884
5885 proc_charac = self.mother_interface.proc_characteristics
5886 if proc_charac['grouped_matrix'] and \
5887 abs(self.run_card['lpp1']) == 1 == abs(self.run_card['lpp2']) and \
5888 (self.run_card['nb_proton1'] != self.run_card['nb_proton2'] or
5889 self.run_card['nb_neutron1'] != self.run_card['nb_neutron2'] or
5890 self.run_card['mass_ion1'] != self.run_card['mass_ion2']):
5891 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\".")
5892
5893
5894 for param in self.param_card['decay']:
5895 width = param.value
5896 if width == 0 or isinstance(width,str):
5897 continue
5898 try:
5899 mass = self.param_card['mass'].get(param.lhacode).value
5900 except Exception:
5901 continue
5902 if isinstance(mass,str):
5903 continue
5904
5905 if mass:
5906 to_sleep = True
5907 if abs(width/mass) < self.run_card['small_width_treatment']:
5908 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",
5909 param.lhacode[0], width)
5910 elif abs(width/mass) < 1e-12:
5911 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)
5912 else:
5913 to_sleep = False
5914 if CommonRunCmd.sleep_for_error and to_sleep:
5915 time.sleep(5)
5916 CommonRunCmd.sleep_for_error = False
5917
5918
5919 if 'pythia_card.dat' in self.cards and 'run' in self.allow_arg:
5920 if self.run_card['event_norm'] != 'sum':
5921 logger.info('Pythia6 needs a specific normalisation of the events. We will change it accordingly.', '$MG:BOLD' )
5922 self.do_set('run_card event_norm sum')
5923
5924 elif 'pythia8_card.dat' in self.cards:
5925 if self.run_card['event_norm'] == 'sum':
5926 logger.info('Pythia8 needs a specific normalisation of the events. We will change it accordingly.', '$MG:BOLD' )
5927 self.do_set('run_card event_norm average')
5928
5929 if 'MLM' in proc_charac['limitations']:
5930 if self.run_card['dynamical_scale_choice'] == -1:
5931 raise InvalidCmd("Your model is identified as not fully supported within MG5aMC.\n" +\
5932 "As your process seems to be impacted by the issue,\n"+\
5933 "You can NOT run with CKKW dynamical scale for this model. Please choose another one.")
5934 if self.run_card['ickkw']:
5935 raise InvalidCmd("Your model is identified as not fully supported within MG5aMC.\n" +\
5936 "As your process seems to be impacted by the issue,\n" +\
5937 "You can NOT run with MLM matching/merging. Please check if merging outside MG5aMC are suitable or refrain to use merging with this model")
5938
5939
5940 if self.run_card and isinstance(self.run_card,banner_mod.RunCardLO):
5941 if not 'sde_strategy' in self.run_card.user_set:
5942 if proc_charac['single_color']:
5943 self.run_card['SDE_strategy'] = 2
5944 else:
5945 self.run_card['SDE_strategy'] = 1
5946 logger.debug("set SDE to %s", self.run_card['SDE_strategy'])
5947 else:
5948 logger.debug("keep SDE to %s", self.run_card['SDE_strategy'])
5949
5950
5951
5952
5953
5954 if isinstance(self.run_card,banner_mod.RunCardNLO):
5955
5956 try:
5957 proc_charac = self.mother_interface.proc_characteristics
5958 except:
5959 proc_charac = None
5960
5961 if proc_charac and 'MLM' in proc_charac['limitations']:
5962 if self.run_card['ickkw']:
5963 raise Exception( "Your model is identified as not fully supported within MG5aMC.\n" +\
5964 "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")
5965
5966 for pdg in set(list(self.run_card['pt_min_pdg'].keys())+list(self.run_card['pt_max_pdg'].keys())+
5967 list(self.run_card['mxx_min_pdg'].keys())):
5968
5969 if int(pdg)<0:
5970 raise Exception("For PDG specific cuts, always use positive PDG codes: the cuts are applied to both particles and anti-particles")
5971 if self.param_card.get_value('mass', int(pdg), default=0) ==0:
5972 raise Exception("For NLO runs, you can use PDG specific cuts only for massive particles: (failed for %s)" % pdg)
5973
5974
5975 if 'reweight' in self.allow_arg and 'run' in self.allow_arg and \
5976 not self.run_card['store_rwgt_info']:
5977
5978 re_pattern = re.compile(r'''^\s*change\s*mode\s* (LO\+NLO|LO|NLO|NLO_tree)\s*(?:#|$)''', re.M+re.I)
5979 text = open(self.paths['reweight']).read()
5980 options = re_pattern.findall(text)
5981 if any(o in ['NLO', 'LO+NLO'] for o in options):
5982 logger.info('NLO reweighting is on ON. Automatically set store_rwgt_info to True', '$MG:BOLD' )
5983 self.do_set('run_card store_rwgt_info True')
5984
5985
5986
5987 if 'run' in self.allow_arg and \
5988 self.run_card['systematics_program'] == 'systematics' and \
5989 not self.run_card['store_rwgt_info']:
5990 logger.warning('To be able to run systematics program, we set store_rwgt_info to True')
5991 self.do_set('run_card store_rwgt_info True')
5992
5993
5994 if 'run' in self.allow_arg and self.run_card['ickkw'] == 3 :
5995 if 'shower' in self.allow_arg:
5996 if self.shower_card['qcut'] == -1:
5997 self.do_set('shower_card qcut %f' % (2*self.run_card['ptj']))
5998 elif self.shower_card['qcut'] < self.run_card['ptj']*2:
5999 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 ",
6000 self.run_card['ptj'], self.shower_card['qcut'])
6001
6002 if self.shower_card['njmax'] == -1:
6003 if not proc_charac:
6004 raise Exception( "Impossible to setup njmax automatically. Please setup that value manually.")
6005 njmax = proc_charac['max_n_matched_jets']
6006 self.do_set('shower_card njmax %i' % njmax)
6007 if self.shower_card['njmax'] == 0:
6008 raise Exception("Invalid njmax parameter. Can not be set to 0")
6009
6010
6011
6012
6013
6014 if self.has_shower and isinstance(self.run_card, banner_mod.RunCardNLO):
6015 modify_extralibs, modify_extrapaths = False,False
6016 extralibs = self.shower_card['extralibs'].split()
6017 extrapaths = self.shower_card['extrapaths'].split()
6018
6019 if self.run_card['parton_shower'] in ['PYTHIA8', 'HERWIGPP', 'HW7']:
6020 if 'stdhep' in self.shower_card['extralibs']:
6021 extralibs.remove('stdhep')
6022 modify_extralibs = True
6023 if 'Fmcfio' in self.shower_card['extralibs']:
6024 extralibs.remove('Fmcfio')
6025 modify_extralibs = True
6026 if self.run_card['parton_shower'] == 'PYTHIA8':
6027
6028 if not self.mother_interface.options['pythia8_path']:
6029 raise self.mother_interface.InvalidCmd('Pythia8 is not correctly specified to MadGraph5_aMC@NLO')
6030 executable = pjoin(self.mother_interface.options['pythia8_path'], 'bin', 'pythia8-config')
6031 if not os.path.exists(executable):
6032 raise self.mother.InvalidCmd('Pythia8 is not correctly specified to MadGraph5_aMC@NLO')
6033
6034
6035 libs , paths = [], []
6036 p = misc.subprocess.Popen([executable, '--libs'], stdout=subprocess.PIPE)
6037 stdout, _ = p. communicate()
6038 libs = [x[2:] for x in stdout.decode().split() if x.startswith('-l') or paths.append(x[2:])]
6039
6040
6041 p = misc.subprocess.Popen([executable, '--config'], stdout=subprocess.PIPE)
6042 stdout, _ = p. communicate()
6043 for lib in ['-ldl','-lstdc++','-lc++']:
6044 if lib in stdout.decode():
6045 libs.append(lib[2:])
6046
6047
6048
6049 supports_HEPMCHACK = '-DHEPMC2HACK' in stdout.decode()
6050
6051
6052 for L in paths:
6053 if L not in extrapaths:
6054 modify_extrapaths = True
6055 extrapaths.append(L)
6056 for l in libs:
6057 if l == 'boost_iostreams':
6058
6059 for L in paths + extrapaths:
6060 if misc.glob('*boost_iostreams*', L):
6061 break
6062 else:
6063 continue
6064 if l not in extralibs:
6065 modify_extralibs = True
6066 extralibs.append(l)
6067
6068 if modify_extralibs:
6069 if extralibs:
6070 self.do_set('shower_card extralibs %s ' % ' '.join(extralibs))
6071 else:
6072 self.do_set('shower_card extralibs None ')
6073 if modify_extrapaths:
6074 if extrapaths:
6075 self.do_set('shower_card extrapaths %s ' % ' '.join(extrapaths))
6076 else:
6077 self.do_set('shower_card extrapaths None ')
6078
6079
6080 if self.writting_card:
6081 for key in list(self.modified_card):
6082 self.write_card(key)
6083
6084
6085 - def reask(self, *args, **opt):
6086
6087 cmd.OneLinePathCompletion.reask(self,*args, **opt)
6088 if self.has_mw and not os.path.exists(pjoin(self.me_dir,'Cards','transfer_card.dat')):
6089 logger.warning('No transfer function currently define. Please use the change_tf command to define one.')
6090
6091 fail_due_to_format = 0
6092 - def postcmd(self, stop, line):
6093
6094 if line not in [None, '0', 'done', '']:
6095 ending_question = cmd.OneLinePathCompletion.postcmd(self,stop,line)
6096 else:
6097 ending_question = True
6098
6099 if ending_question:
6100 self.check_card_consistency()
6101 if self.param_consistency:
6102 try:
6103 self.do_update('dependent', timer=20)
6104 except MadGraph5Error as error:
6105 if 'Missing block:' in str(error):
6106 self.fail_due_to_format +=1
6107 if self.fail_due_to_format == 10:
6108 missing, unknow = str(error).split('\n')[-2:]
6109 logger.warning("Invalid param_card:\n%s\n%s\n" % (missing, unknow))
6110 logger.info("Type \"update missing\" to use default value.\n ", '$MG:BOLD')
6111 self.value = False
6112 return self.reask(True)
6113 else:
6114 raise
6115
6116 return ending_question
6117
6118
6119
6120
6121
6123 """ syntax: update dependent: Change the mass/width of particles which are not free parameter for the model.
6124 update missing: add to the current param_card missing blocks/parameters.
6125 update to_slha1: pass SLHA2 card to SLHA1 convention. (beta)
6126 update to_slha2: pass SLHA1 card to SLHA2 convention. (beta)
6127 update to_full [run_card]
6128 update XXX [where XXX correspond to a hidden block of the run_card]
6129 """
6130 args = self.split_arg(line)
6131 if len(args)==0:
6132 logger.warning('miss an argument (dependent or missing). Please retry')
6133 return
6134
6135 if args[0] == 'dependent':
6136 if not self.mother_interface:
6137 logger.warning('Failed to update dependent parameter. This might create trouble for external program (like MadSpin/shower/...)')
6138
6139 pattern_width = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I)
6140 pattern_scan = re.compile(r'''^(decay)?[\s\d]*scan''', re.I+re.M)
6141 param_text= open(self.paths['param']).read()
6142
6143 if pattern_scan.search(param_text):
6144
6145
6146
6147 return
6148 elif pattern_width.search(param_text):
6149 self.do_compute_widths('')
6150 self.param_card = param_card_mod.ParamCard(self.paths['param'])
6151
6152
6153 self.update_dependent(self.mother_interface, self.me_dir, self.param_card,
6154 self.paths['param'], timer)
6155
6156 elif args[0] == 'missing':
6157 self.update_missing()
6158 return
6159
6160 elif args[0] == 'to_slha2':
6161 try:
6162 param_card_mod.convert_to_mg5card(self.paths['param'])
6163 logger.info('card updated')
6164 except Exception as error:
6165 logger.warning('failed to update to slha2 due to %s' % error)
6166 self.param_card = param_card_mod.ParamCard(self.paths['param'])
6167 elif args[0] == 'to_slha1':
6168 try:
6169 param_card_mod.convert_to_slha1(self.paths['param'])
6170 logger.info('card updated')
6171 except Exception as error:
6172 logger.warning('failed to update to slha1 due to %s' % error)
6173 self.param_card = param_card_mod.ParamCard(self.paths['param'])
6174 elif args[0] == 'to_full':
6175 return self.update_to_full(args[1:])
6176 elif args[0] in self.update_block:
6177 self.run_card.display_block.append(args[0].lower())
6178 self.modified_card.add('run')
6179 logger.info('add optional block %s to the run_card', args[0])
6180 else:
6181 self.help_update()
6182 logger.warning('unvalid options for update command. Please retry')
6183
6184
6186 """ trigger via update to_full LINE"""
6187
6188 logger.info("update the run_card by including all the hidden parameter")
6189 self.run_card.write(self.paths['run'], self.paths['run_default'], write_hidden=True)
6190 if 'run' in self.modified_card:
6191 self.modified_card.remove('run')
6192
6194 """proxy on how to write any card"""
6195
6196 if hasattr(self, 'write_card_%s' % name):
6197 getattr(self, 'write_card_%s' % name)()
6198 if name in self.modified_card:
6199 self.modified_card.remove(name)
6200 else:
6201 raise Exception("Need to add the associate writter proxy for %s" % name)
6202
6204 """ write the run_card """
6205 self.run_card.write(self.paths['run'], self.paths['run_default'])
6206
6208 """ write the param_card """
6209
6210 self.param_card.write(self.paths['param'])
6211
6212 @staticmethod
6214 """static method which can also be called from outside the class
6215 usefull in presence of scan.
6216 return if the param_card was updated or not
6217 """
6218
6219 if not param_card:
6220 return False
6221
6222 logger.info('Update the dependent parameter of the param_card.dat')
6223 modify = True
6224 class TimeOutError(Exception):
6225 pass
6226 def handle_alarm(signum, frame):
6227 raise TimeOutError
6228 signal.signal(signal.SIGALRM, handle_alarm)
6229 if timer:
6230 signal.alarm(timer)
6231 log_level=30
6232 else:
6233 log_level=20
6234
6235 try:
6236 model = mecmd.get_model()
6237 signal.alarm(0)
6238 except TimeOutError:
6239 logger.warning('The model takes too long to load so we bypass the updating of dependent parameter.\n'+\
6240 'This might create trouble for external program (like MadSpin/shower/...)\n'+\
6241 'The update can be forced without timer by typing \'update dependent\' at the time of the card edition')
6242 modify =False
6243 except Exception as error:
6244 logger.debug(str(error))
6245 logger.warning('Failed to update dependent parameter. This might create trouble for external program (like MadSpin/shower/...)')
6246 signal.alarm(0)
6247 else:
6248 restrict_card = pjoin(me_dir,'Source','MODEL','param_card_rule.dat')
6249 if not os.path.exists(restrict_card):
6250 restrict_card = None
6251
6252 if model:
6253 modify = param_card.update_dependent(model, restrict_card, log_level)
6254 if modify and path:
6255 param_card.write(path)
6256 else:
6257 logger.warning('missing MG5aMC code. Fail to update dependent parameter. This might create trouble for program like MadSpin/shower/...')
6258
6259 if log_level==20:
6260 logger.info('param_card up to date.')
6261
6262 return modify
6263
6264
6265
6267
6268 def check_block(self, blockname):
6269 add_entry = 0
6270 if blockname.lower() not in self.param_card_default:
6271 logger.info('unknow block %s: block will be ignored', blockname)
6272 return add_entry
6273 block = self.param_card_default[blockname]
6274 for key in block.keys():
6275 if key not in input_in_block:
6276 param = block.get(key)
6277 if blockname != 'decay':
6278 text.append('\t%s\t%s # %s\n' % (' \t'.join([repr(i) for i in param.lhacode]), param.value, param.comment))
6279 else:
6280 text.append('DECAY \t%s\t%s # %s\n' % (' \t'.join([repr(i) for i in param.lhacode]), param.value, param.comment))
6281 add_entry += 1
6282 if add_entry:
6283 text.append('\n')
6284 if add_entry:
6285 logger.info("Adding %s parameter(s) to block %s", add_entry, blockname)
6286 return add_entry
6287
6288
6289 current_block = ''
6290 input_in_block = set()
6291 defined_blocks = set()
6292 decay = set()
6293 text = []
6294 add_entry = 0
6295 for line in open(self.paths['param']):
6296
6297 new_block = re.findall(r'^\s*(block|decay)\s*(\w*)', line, re.I)
6298 if new_block:
6299 new_block = new_block[0]
6300 defined_blocks.add(new_block[1].lower())
6301 if current_block:
6302 add_entry += check_block(self, current_block)
6303
6304 current_block= new_block[1]
6305 input_in_block = set()
6306 if new_block[0].lower() == 'decay':
6307 decay.add((int(new_block[1]),))
6308 current_block = ''
6309 if new_block[1].lower() == 'qnumbers':
6310 current_block = ''
6311
6312 text.append(line)
6313 if not current_block:
6314 continue
6315
6316
6317
6318 line = line.split('#',1)[0]
6319 split = line.split()
6320 if not split:
6321 continue
6322 else:
6323 try:
6324 lhacode = [int(i) for i in split[:-1]]
6325 except:
6326 continue
6327 input_in_block.add(tuple(lhacode))
6328
6329 if current_block:
6330 add_entry += check_block(self, current_block)
6331
6332
6333 for block in self.param_card_default:
6334
6335 if block.startswith(('qnumbers', 'decay')):
6336 continue
6337
6338 if block not in defined_blocks:
6339 nb_entry = len(self.param_card_default[block])
6340 logger.info("Block %s was missing. Adding the %s associated parameter(s)", block,nb_entry)
6341 add_entry += nb_entry
6342 text.append(str(self.param_card_default[block]))
6343
6344
6345 input_in_block = decay
6346 add_entry += check_block(self, 'decay')
6347
6348 if add_entry:
6349 logger.info('write new param_card with %s new parameter(s).', add_entry, '$MG:BOLD')
6350 open(self.paths['param'],'w').write(''.join(text))
6351 self.reload_card(self.paths['param'])
6352 else:
6353 logger.info('No missing parameter detected.', '$MG:BOLD')
6354
6355
6360
6388
6390
6391 line = line.strip()
6392 args = line.split()
6393
6394 if not args:
6395 return line
6396 if not hasattr(self, 'trigger_%s' % args[0]):
6397 return line
6398
6399 triggerfct = getattr(self, 'trigger_%s' % args[0])
6400
6401
6402 outline = triggerfct(' '.join(args[1:]))
6403 if not outline:
6404 return 'repeat'
6405 return outline
6406
6408 """Default action if line is not recognized"""
6409
6410
6411 line = self.trigger(line)
6412
6413
6414 line = line.strip()
6415 args = line.split()
6416 if line == '' and self.default_value is not None:
6417 self.value = self.default_value
6418
6419 elif hasattr(self, 'do_%s' % args[0]):
6420 self.do_set(' '.join(args[1:]))
6421 elif line.strip() != '0' and line.strip() != 'done' and \
6422 str(line) != 'EOF' and line.strip() in self.allow_arg:
6423 self.open_file(line)
6424 self.value = 'repeat'
6425 elif os.path.isfile(line):
6426 self.copy_file(line)
6427 self.value = 'repeat'
6428 elif self.me_dir and os.path.exists(pjoin(self.me_dir, line)):
6429 self.copy_file(pjoin(self.me_dir,line))
6430 self.value = 'repeat'
6431 elif line.strip().startswith(('http:','www', 'https')):
6432 self.value = 'repeat'
6433 import tempfile
6434 fsock, path = tempfile.mkstemp()
6435 try:
6436 text = six.moves.urllib.request.urlopen(line.strip())
6437 url = line.strip()
6438 except Exception:
6439 logger.error('fail to load the file')
6440 else:
6441 for line in text:
6442 os.write(fsock, line)
6443 os.close(fsock)
6444 self.copy_file(path, pathname=url)
6445 os.remove(path)
6446
6447
6448 else:
6449 self.value = line
6450
6451 return line
6452
6453
6455 """edit the madspin_card to define the decay of the associate particle"""
6456 signal.alarm(0)
6457 path = self.paths['madspin']
6458
6459 if 'madspin_card.dat' not in self.cards or not os.path.exists(path):
6460 logger.warning("Command decay not valid. Since MadSpin is not available.")
6461 return
6462
6463 if ">" not in line:
6464 logger.warning("invalid command for decay. Line ignored")
6465 return
6466
6467 if "-add" in line:
6468
6469 particle = line.split('>')[0].strip()
6470 text = open(path).read()
6471 line = line.replace('--add', '').replace('-add','')
6472 logger.info("change madspin_card to add one decay to %s: %s" %(particle, line.strip()), '$MG:BOLD')
6473 if 'launch' in text:
6474 text = text.replace('launch', "\ndecay %s\nlaunch\n" % line,1)
6475 else:
6476 text += '\ndecay %s\n launch \n' % line
6477 else:
6478
6479
6480 particle = line.split('>')[0].strip()
6481 logger.info("change madspin_card to define the decay of %s: %s" %(particle, line.strip()), '$MG:BOLD')
6482 particle = particle.replace('+','\+').replace('-','\-')
6483 decay_pattern = re.compile(r"^\s*decay\s+%s\s*>[\s\w+-~]*?$" % particle, re.I+re.M)
6484 text= open(path).read()
6485 text = decay_pattern.sub('', text)
6486 if 'launch' in text:
6487 text = text.replace('launch', "\ndecay %s\nlaunch\n" % line,1)
6488 else:
6489 text += '\ndecay %s\n launch \n' % line
6490
6491 with open(path,'w') as fsock:
6492 fsock.write(text)
6493 self.reload_card(path)
6494
6495
6496
6498 signal.alarm(0)
6499
6500
6501 if 'param' in self.modified_card:
6502 self.write_card('param')
6503 self.modified_card.discard('param')
6504
6505 path = self.paths['param']
6506 pattern = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I)
6507 text = open(path).read()
6508 pdg_info = pattern.findall(text)
6509 has_nlo = any("@nlo"==nlo.lower() for _, nlo in pdg_info)
6510 pdg = [p for p,_ in pdg_info]
6511
6512
6513 line = '%s %s' % (line, ' '.join(pdg))
6514 if not '--path' in line:
6515 line += ' --path=%s' % path
6516 if has_nlo:
6517 line += ' --nlo'
6518
6519 try:
6520 out = self.mother_interface.do_compute_widths(line)
6521 except InvalidCmd as error:
6522 logger.error("Invalid command: %s " % error)
6523 else:
6524 self.reload_card(path)
6525 if hasattr(self, 'run_card'):
6526 for pid, info in out.items():
6527 total = 0
6528 for key, partial in info:
6529 total += partial
6530 mass = self.param_card.get_value('mass', pid)
6531 try:
6532 small_width_treatment = self.run_card['small_width_treatment']
6533 except Exception:
6534 small_width_treatment = 0
6535
6536 if total and total/mass < small_width_treatment:
6537 text = "Particle %s with very small width (%g): Learn about special handling here: https://answers.launchpad.net/mg5amcnlo/+faq/3053"
6538 logger.warning(text,pid,total)
6539 elif total and total/mass < 1e-11:
6540 text = "Particle %s with very small width (%g): Numerical inaccuracies can occur if that particle is in a s-channel"
6541 logger.critical(text,pid,total)
6542
6543
6544 return out
6545
6546
6550
6552 """help for command decay which modifies MadSpin_card"""
6553
6554 signal.alarm(0)
6555 print('--syntax: decay PROC [--add]')
6556 print(' ')
6557 print(' modify the madspin_card to modify the decay of the associate particle.')
6558 print(' and define it to PROC.')
6559 print(' if --add is present, just add a new decay for the associate particle.')
6560
6562 prev_timer = signal.alarm(0)
6563 if prev_timer:
6564 nb_back = len(line)
6565 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
6566 self.stdout.write(line)
6567 self.stdout.flush()
6568 return self.mother_interface.complete_compute_widths(text, line, begidx, endidx,**opts)
6569
6570
6572 """help for add command"""
6573
6574 logger.info('********************* HELP ADD ***************************')
6575 logger.info( '-- syntax: add pythia8_card NAME VALUE')
6576 logger.info( " add a definition of name in the pythia8_card with the given value")
6577 logger.info( " Do not work for the param_card" )
6578 logger.info('')
6579 return self.help_edit(prefix=False)
6580
6582 """help for edit command"""
6583
6584 if prefix: logger.info('********************* HELP ADD|EDIT ***************************')
6585 logger.info( '-- syntax: add filename [OPTION] LINE')
6586 logger.info( '-- syntax: edit filename [OPTION] LINE')
6587 logger.info( ' add the given LINE to the end of the associate file (all file supported).')
6588 logger.info( '')
6589 logger.info( ' OPTION parameter allows to change the position where to write in the file')
6590 logger.info( ' --after_line=banner : write the line at the end of the banner')
6591 logger.info( ' --line_position=X : insert the line before line X (starts at 0)')
6592 logger.info( ' --line_position=afterlast : insert the line after the latest inserted/modified line.')
6593 logger.info( ' --after_line="<regular-expression>" write the line after the first line matching the regular expression')
6594 logger.info( ' --before_line="<regular-expression>" write the line before the first line matching the regular expression')
6595 logger.info( ' --replace_line="<regular-expression>" replace the line matching the regular expression')
6596 logger.info( ' --clean remove all previously existing line in the file')
6597 logger.info( ' --comment_line="<regular-expression>" comment all lines matching the regular expression')
6598 logger.info('')
6599 logger.info(' Note: all regular-expression will be prefixed by ^\s*')
6600 logger.info('')
6601 logger.info( ' example: edit reweight --after_line="change mode\b" change model heft')
6602 logger.info( ' edit madspin --after_line="banner" change model XXXX')
6603 logger.info('********************* HELP ADD|EDIT ***************************')
6604
6605
6606 - def complete_add(self, text, line, begidx, endidx, formatting=True):
6607 """ auto-completion for add command"""
6608
6609 prev_timer = signal.alarm(0)
6610 if prev_timer:
6611 nb_back = len(line)
6612 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
6613 self.stdout.write(line)
6614 self.stdout.flush()
6615
6616 split = line[:begidx].split()
6617 if len(split)==1:
6618 possibilities = {}
6619 cards = [c.rsplit('.',1)[0] for c in self.cards]
6620 possibilities['category of parameter (optional)'] = \
6621 self.list_completion(text, cards)
6622 elif len(split) == 2:
6623 possibilities = {}
6624 options = ['--line_position=','--line_position=afterlast','--after_line=banner', '--after_line="','--before_line="']
6625 possibilities['category of parameter (optional)'] = \
6626 self.list_completion(text, options, line)
6627 else:
6628 return
6629 return self.deal_multiple_categories(possibilities, formatting)
6630
6632 """ syntax: add filename NAME VALUE
6633 syntax: add filename LINE"""
6634
6635 args = self.split_arg(line)
6636 if len(args) == 3 and args[0] in ['pythia8_card', 'pythia8_card.dat'] and self.has_PY8:
6637 name= args[1]
6638 value = args[2]
6639 self.PY8Card.userSet(name, value)
6640 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'),
6641 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'),
6642 print_only_visible=True)
6643 logger.info("add in the pythia8_card the parameter \"%s\" with value \"%s\"" % (name, value), '$MG:BOLD')
6644 elif len(args) > 0:
6645 if args[0] in self.cards:
6646 card = args[0]
6647 elif "%s.dat" % args[0] in self.cards:
6648 card = "%s.dat" % args[0]
6649 elif "%s_card.dat" % args[0] in self.cards:
6650 card = "%s_card.dat" % args[0]
6651 elif self.has_ml and args[0].lower() == "madloop":
6652 card = "MadLoopParams.dat"
6653 else:
6654 logger.error("unknow card %s. Please retry." % args[0])
6655 return
6656
6657 if card in self.modified_card:
6658 self.write_card(card)
6659 self.modified_card.discard(card)
6660
6661 if card in self.paths:
6662 path = self.paths[card]
6663 elif os.path.exists(card):
6664 path = card
6665 elif os.path.exists(pjoin(self.me_dir,'Cards',card)):
6666 path = pjoin(self.me_dir,'Cards',card)
6667 else:
6668 raise Exception('unknow path')
6669
6670
6671 if args[1] == '--clean':
6672 ff = open(path,'w')
6673 ff.write("# %s \n" % card)
6674 ff.write("%s \n" % line.split(None,2)[2])
6675 ff.close()
6676 logger.info("writing the line in %s (empty file) the line: \"%s\"" %(card, line.split(None,2)[2] ),'$MG:BOLD')
6677 elif args[1].startswith('--line_position=afterlast'):
6678
6679 text = open(path).read()
6680 split = text.split('\n')
6681 if self.last_editline_pos > 0:
6682 pos = self.last_editline_pos +1
6683 newline = line.split(None,2)[2]
6684 split.insert(pos, newline)
6685 ff = open(path,'w')
6686 ff.write('\n'.join(split))
6687 logger.info("writting at line %d of the file %s the line: \"%s\"" %(pos, card, line.split(None,2)[2] ),'$MG:BOLD')
6688 self.last_editline_pos = pos
6689 elif args[1].startswith('--line_position='):
6690
6691 text = open(path).read()
6692 split = text.split('\n')
6693 pos = int(args[1].split('=',1)[1])
6694 newline = line.split(None,2)[2]
6695 split.insert(pos, newline)
6696 ff = open(path,'w')
6697 ff.write('\n'.join(split))
6698 logger.info("writting at line %d of the file %s the line: \"%s\"" %(pos, card, line.split(None,2)[2] ),'$MG:BOLD')
6699 self.last_editline_pos = pos
6700
6701 elif args[1].startswith(('--after_line=banner','--after_line=\'banner\'','--after_line=\"banner\"')):
6702
6703 text = open(path).read()
6704 split = text.split('\n')
6705 for posline,l in enumerate(split):
6706 if not l.startswith('#'):
6707 break
6708 split.insert(posline, line.split(None,2)[2])
6709 ff = open(path,'w')
6710 ff.write('\n'.join(split))
6711 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline, card, line.split(None,2)[2] ),'$MG:BOLD')
6712 self.last_editline_pos = posline
6713
6714 elif args[1].startswith('--replace_line='):
6715
6716
6717 text = open(path).read()
6718 split = text.split('\n')
6719 search_pattern=r'''replace_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6720 pattern = '^\s*' + re.search(search_pattern, line).group()[14:-1]
6721 for posline,l in enumerate(split):
6722 if re.search(pattern, l):
6723 break
6724 else:
6725 new_line = re.split(search_pattern,line)[-1].strip()
6726 if new_line.startswith(('--before_line=','--after_line')):
6727 return self.do_add('%s %s' % (args[0], new_line))
6728 raise Exception('invalid regular expression: not found in file')
6729
6730
6731 new_line = re.split(search_pattern,line)[-1].strip()
6732 if new_line.startswith(('--before_line=','--after_line')):
6733 search_pattern=r'''(?:before|after)_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6734 new_line = re.split(search_pattern,new_line)[-1]
6735
6736 old_line = split[posline]
6737 split[posline] = new_line
6738 ff = open(path,'w')
6739 ff.write('\n'.join(split))
6740 logger.info("Replacing the line \"%s\" [line %d of %s] by \"%s\"" %
6741 (old_line, posline, card, new_line ),'$MG:BOLD')
6742 self.last_editline_pos = posline
6743
6744 elif args[1].startswith('--comment_line='):
6745
6746
6747 text = open(path).read()
6748 split = text.split('\n')
6749 search_pattern=r'''comment_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6750 pattern = '^\s*' + re.search(search_pattern, line).group()[14:-1]
6751 nb_mod = 0
6752 for posline,l in enumerate(split):
6753 if re.search(pattern, l):
6754 split[posline] = '#%s' % l
6755 nb_mod +=1
6756 logger.info("Commenting line \"%s\" [line %d of %s]" %
6757 (l, posline, card ),'$MG:BOLD')
6758
6759 if not nb_mod:
6760 logger.warning('no line commented (no line matching)')
6761 ff = open(path,'w')
6762 ff.write('\n'.join(split))
6763
6764 self.last_editline_pos = posline
6765
6766
6767 elif args[1].startswith('--before_line='):
6768
6769 text = open(path).read()
6770 split = text.split('\n')
6771 search_pattern=r'''before_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6772 pattern = '^\s*' + re.search(search_pattern, line).group()[13:-1]
6773 for posline,l in enumerate(split):
6774 if re.search(pattern, l):
6775 break
6776 else:
6777 raise Exception('invalid regular expression: not found in file')
6778 split.insert(posline, re.split(search_pattern,line)[-1])
6779 ff = open(path,'w')
6780 ff.write('\n'.join(split))
6781 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline, card, line.split(None,2)[2] ),'$MG:BOLD')
6782 self.last_editline_pos = posline
6783
6784 elif args[1].startswith('--after_line='):
6785
6786 text = open(path).read()
6787 split = text.split('\n')
6788 search_pattern = r'''after_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6789 pattern = '^\s*' + re.search(search_pattern, line).group()[12:-1]
6790 for posline,l in enumerate(split):
6791 if re.search(pattern, l):
6792 break
6793 else:
6794 posline=len(split)
6795 split.insert(posline+1, re.split(search_pattern,line)[-1])
6796 ff = open(path,'w')
6797 ff.write('\n'.join(split))
6798
6799 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline+1, card, line.split(None,2)[2] ),'$MG:BOLD')
6800 self.last_editline_pos = posline+1
6801
6802 else:
6803 ff = open(path,'a')
6804 ff.write("%s \n" % line.split(None,1)[1])
6805 ff.close()
6806 logger.info("adding at the end of the file %s the line: \"%s\"" %(card, line.split(None,1)[1] ),'$MG:BOLD')
6807 self.last_editline_pos = -1
6808
6809 self.reload_card(path)
6810
6811 do_edit = do_add
6812 complete_edit = complete_add
6813
6815 """Help associated to the asperge command"""
6816 signal.alarm(0)
6817
6818 print('-- syntax: asperge [options]')
6819 print(' Call ASperGe to diagonalize all mass matrices in the model.')
6820 print(' This works only if the ASperGE module is part of the UFO model (a subdirectory).')
6821 print(' If you specify some names after the command (i.e. asperge m1 m2) then ASperGe will only')
6822 print(' diagonalize the associate mass matrices (here m1 and m2).')
6823
6825 prev_timer = signal.alarm(0)
6826 if prev_timer:
6827 nb_back = len(line)
6828 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
6829 self.stdout.write(line)
6830 self.stdout.flush()
6831 blockname = list(self.pname2block.keys())
6832
6833 wrong = ['decay', 'mass', 'sminput']
6834 valid = [k for k in blockname if 'mix' in k]
6835 potential = [k for k in blockname if k not in valid+wrong]
6836 output = {'Mixing matrices': self.list_completion(text, valid, line),
6837 'Other potential valid input': self.list_completion(text, potential, line)}
6838
6839 return self.deal_multiple_categories(output, formatting)
6840
6841
6843 """Running ASperGe"""
6844 signal.alarm(0)
6845
6846
6847 if 'param' in self.modified_card:
6848 self.write_card('param')
6849 self.modified_card.discard('param')
6850
6851
6852 path = pjoin(self.me_dir,'bin','internal','ufomodel','ASperGE')
6853 if not os.path.exists(path):
6854 logger.error('ASperge has not been detected in the current model, therefore it will not be run.')
6855 return
6856 elif not os.path.exists(pjoin(path,'ASperGe')):
6857 logger.info('ASperGe has been detected but is not compiled. Running the compilation now.')
6858 try:
6859 misc.compile(cwd=path,shell=True)
6860 except MadGraph5Error as error:
6861 logger.error('''ASperGe failed to compile. Note that gsl is needed
6862 for this compilation to go trough. More information on how to install this package on
6863 http://www.gnu.org/software/gsl/
6864 Full compilation log is available at %s''' % pjoin(self.me_dir, 'ASperge_compilation.log'))
6865 open(pjoin(self.me_dir, 'ASperge_compilation.log'),'w').write(str(error))
6866 return
6867
6868 opts = line.split()
6869 card = self.paths['param']
6870 logger.info('running ASperGE')
6871 returncode = misc.call([pjoin(path,'ASperGe'), card, '%s.new' % card] + opts)
6872 if returncode:
6873 logger.error('ASperGE fails with status %s' % returncode)
6874 else:
6875 logger.info('AsPerGe creates the file succesfully')
6876 files.mv(card, '%s.beforeasperge' % card)
6877 files.mv('%s.new' % card, card)
6878 self.reload_card(card)
6879
6880
6881
6883 """detect the type of the file and overwritte the current file"""
6884
6885 if not pathname:
6886 pathname = path
6887
6888 if path.endswith('.lhco'):
6889
6890
6891 self.do_set('mw_run inputfile %s' % os.path.relpath(path, self.mother_interface.me_dir))
6892 return
6893 elif path.endswith('.lhco.gz'):
6894
6895
6896 self.do_set('mw_run inputfile %s' % os.path.relpath(path, self.mother_interface.me_dir))
6897 return
6898 else:
6899 card_name = self.detect_card_type(path)
6900
6901 if card_name == 'unknown':
6902 logger.warning('Fail to determine the type of the file. Not copied')
6903 if card_name != 'banner':
6904 logger.info('copy %s as %s' % (pathname, card_name))
6905 files.cp(path, self.paths[card_name.rsplit('_',1)[0]])
6906 self.reload_card(self.paths[card_name.rsplit('_',1)[0]])
6907 elif card_name == 'banner':
6908 banner_mod.split_banner(path, self.mother_interface.me_dir, proc_card=False)
6909 logger.info('Splitting the banner in it\'s component')
6910 if not self.mode == 'auto':
6911 self.mother_interface.keep_cards(self.cards)
6912 for card_name in self.cards:
6913 self.reload_card(pjoin(self.me_dir, 'Cards', card_name))
6914
6919
6921 """open the file"""
6922
6923 try:
6924 me_dir = self.mother_interface.me_dir
6925 except:
6926 me_dir = None
6927
6928 if answer.isdigit():
6929 if answer == '9':
6930 answer = 'plot'
6931 else:
6932 answer = self.cards[int(answer)-self.integer_bias]
6933
6934 if 'madweight' in answer:
6935 answer = answer.replace('madweight', 'MadWeight')
6936 elif 'MadLoopParams' in answer:
6937 answer = self.paths['ML']
6938 elif 'pythia8_card' in answer:
6939 answer = self.paths['pythia8']
6940 if os.path.exists(answer):
6941 path = answer
6942 else:
6943 if not '.dat' in answer and not '.lhco' in answer:
6944 if answer != 'trigger':
6945 path = self.paths[answer]
6946 else:
6947 path = self.paths['delphes']
6948 elif not '.lhco' in answer:
6949 if '_' in answer:
6950 path = self.paths['_'.join(answer.split('_')[:-1])]
6951 else:
6952 path = pjoin(me_dir, 'Cards', answer)
6953 else:
6954 path = pjoin(me_dir, self.mw_card['mw_run']['inputfile'])
6955 if not os.path.exists(path):
6956 logger.info('Path in MW_card not existing')
6957 path = pjoin(me_dir, 'Events', answer)
6958
6959 path = path.replace('_card_card','_card')
6960
6961 if answer in self.modified_card:
6962 self.write_card(answer)
6963 elif os.path.basename(answer.replace('_card.dat','')) in self.modified_card:
6964 self.write_card(os.path.basename(answer.replace('_card.dat','')))
6965
6966 try:
6967 self.mother_interface.exec_cmd('open %s' % path)
6968 except InvalidCmd as error:
6969 if str(error) != 'No default path for this file':
6970 raise
6971 if answer == 'transfer_card.dat':
6972 logger.warning('You have to specify a transfer function first!')
6973 elif answer == 'input.lhco':
6974 path = pjoin(me_dir,'Events', 'input.lhco')
6975 ff = open(path,'w')
6976 ff.write('''No LHCO information imported at current time.
6977 To import a lhco file: Close this file and type the path of your file.
6978 You can also copy/paste, your event file here.''')
6979 ff.close()
6980 self.open_file(path)
6981 else:
6982 raise
6983 self.reload_card(path)
6984
6986 """reload object to have it in sync"""
6987
6988 if path == self.paths['param']:
6989 try:
6990 self.param_card = param_card_mod.ParamCard(path)
6991 except (param_card_mod.InvalidParamCard, ValueError) as e:
6992 logger.error('Current param_card is not valid. We are going to use the default one.')
6993 logger.error('problem detected: %s' % e)
6994 logger.error('Please re-open the file and fix the problem.')
6995 logger.warning('using the \'set\' command without opening the file will discard all your manual change')
6996 elif path == self.paths['run']:
6997 self.run_card = banner_mod.RunCard(path)
6998 elif path == self.paths['shower']:
6999 self.shower_card = shower_card_mod.ShowerCard(path)
7000 elif path == self.paths['ML']:
7001 self.MLcard = banner_mod.MadLoopParam(path)
7002 elif path == self.paths['pythia8']:
7003
7004
7005 if not self.PY8Card:
7006 self.PY8Card = self.PY8Card_class(self.paths['pythia8_default'])
7007
7008 self.PY8Card.read(self.paths['pythia8'], setter='user')
7009 self.py8_vars = [k.lower() for k in self.PY8Card.keys()]
7010 elif path == self.paths['MadWeight']:
7011 try:
7012 import madgraph.madweight.Cards as mwcards
7013 except:
7014 import internal.madweight.Cards as mwcards
7015 self.mw_card = mwcards.Card(path)
7016 else:
7017 logger.debug('not keep in sync: %s', path)
7018 return path
7019
7020
7021
7022 -def scanparamcardhandling(input_path=lambda obj: pjoin(obj.me_dir, 'Cards', 'param_card.dat'),
7023 store_for_scan=lambda obj: obj.store_scan_result,
7024 get_run_name=lambda obj: obj.run_name,
7025 set_run_name=lambda obj: obj.set_run_name,
7026 result_path=lambda obj: pjoin(obj.me_dir, 'Events', 'scan_%s.txt' ),
7027 ignoreerror=ZeroResult,
7028 iteratorclass=param_card_mod.ParamCardIterator,
7029 summaryorder=lambda obj: lambda:None,
7030 check_card=lambda obj: CommonRunCmd.static_check_param_card,
7031 ):
7032 """ This is a decorator for customizing/using scan over the param_card (or technically other)
7033 This should be use like this:
7034
7035 @scanparamcardhandling(arguments)
7036 def run_launch(self, *args, **opts)
7037
7038 possible arguments are listed above and should be function who takes a single
7039 argument the instance of intereset. those return
7040 input_path -> function that return the path of the card to read
7041 store_for_scan -> function that return a dict of entry to keep in memory
7042 get_run_name -> function that return the string with the current run_name
7043 set_run_name -> function that return the function that allow the set the next run_name
7044 result_path -> function that return the path of the summary result to write
7045 ignoreerror -> one class of error which are not for the error
7046 IteratorClass -> class to use for the iterator
7047 summaryorder -> function that return the function to call to get the order
7048
7049 advanced:
7050 check_card -> function that return the function to read the card and init stuff (compute auto-width/init self.iterator/...)
7051 This function should define the self.param_card_iterator if a scan exists
7052 and the one calling the auto-width functionalities/...
7053
7054 All the function are taking a single argument (an instance of the class on which the decorator is used)
7055 and they can either return themself a function or a string.
7056
7057 Note:
7058 1. the link to auto-width is not fully trivial due to the model handling
7059 a. If you inherit from CommonRunCmd (or if the self.mother is). Then
7060 everything should be automatic.
7061
7062 b. If you do not you can/should create the funtion self.get_model().
7063 Which returns the appropriate MG model (like the one from import_ufo.import_model)
7064
7065 c. You can also have full control by defining your own do_compute_widths(self, line)
7066 functions.
7067 """
7068 class restore_iterator(object):
7069 """ensure that the original card is always restore even for crash"""
7070 def __init__(self, iterator, path):
7071 self.iterator = iterator
7072 self.path = path
7073
7074 def __enter__(self):
7075 return self.iterator
7076
7077 def __exit__(self, ctype, value, traceback ):
7078 self.iterator.write(self.path)
7079
7080 def decorator(original_fct):
7081 def new_fct(obj, *args, **opts):
7082
7083 if isinstance(input_path, str):
7084 card_path = input_path
7085 else:
7086 card_path = input_path(obj)
7087
7088
7089
7090
7091
7092
7093
7094
7095 check_card(obj)(card_path, obj, iterator_class=iteratorclass)
7096
7097 param_card_iterator = None
7098 if obj.param_card_iterator:
7099 param_card_iterator = obj.param_card_iterator
7100 obj.param_card_iterator = []
7101
7102 if not param_card_iterator:
7103
7104 original_fct(obj, *args, **opts)
7105 return
7106
7107 with restore_iterator(param_card_iterator, card_path):
7108
7109
7110
7111 if not hasattr(obj, 'allow_notification_center'):
7112 obj.allow_notification_center = False
7113 with misc.TMP_variable(obj, 'allow_notification_center', False):
7114 orig_name = get_run_name(obj)
7115 next_name = orig_name
7116
7117 set_run_name(obj)(next_name)
7118
7119 original_fct(obj, *args, **opts)
7120 param_card_iterator.store_entry(next_name, store_for_scan(obj)(), param_card_path=card_path)
7121 for card in param_card_iterator:
7122 card.write(card_path)
7123
7124 check_card(obj)(card_path, obj, dependent=True)
7125 next_name = param_card_iterator.get_next_name(next_name)
7126 set_run_name(obj)(next_name)
7127 try:
7128 original_fct(obj, *args, **opts)
7129 except ignoreerror as error:
7130 param_card_iterator.store_entry(next_name, {'exception': error})
7131 else:
7132 param_card_iterator.store_entry(next_name, store_for_scan(obj)(), param_card_path=card_path)
7133
7134
7135 name = misc.get_scan_name(orig_name, next_name)
7136 path = result_path(obj) % name
7137 logger.info("write scan results in %s" % path ,'$MG:BOLD')
7138 order = summaryorder(obj)()
7139 param_card_iterator.write_summary(path, order=order)
7140 return new_fct
7141 return decorator
7142