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