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:
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
3932
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 return self.update_make_opts_full(make_opts, self.make_opts_var)
3986
3987 @staticmethod
3989 """update the make_opts file writing the environmental variables
3990 of def_variables.
3991 if a value of the dictionary is None then it is not written.
3992 """
3993 make_opts = path
3994 pattern = re.compile(r'^(\w+)\s*=\s*(.*)$',re.DOTALL)
3995 diff = False
3996
3997
3998 tag = '#end_of_make_opts_variables\n'
3999 make_opts_variable = True
4000 content = []
4001 variables = dict(def_variables)
4002 need_keys = list(variables.keys())
4003 for line in open(make_opts):
4004 line = line.strip()
4005 if make_opts_variable:
4006 if line.startswith('#') or not line:
4007 if line.startswith('#end_of_make_opts_variables'):
4008 make_opts_variable = False
4009 continue
4010 elif pattern.search(line):
4011 key, value = pattern.search(line).groups()
4012 if key not in variables:
4013 variables[key] = value
4014 elif value != variables[key]:
4015 diff=True
4016 else:
4017 need_keys.remove(key)
4018 else:
4019 make_opts_variable = False
4020 content.append(line)
4021 else:
4022 content.append(line)
4023
4024 if need_keys:
4025 diff=True
4026
4027 content_variables = '\n'.join('%s=%s' % (k,v) for k, v in variables.items() if v is not None)
4028 content_variables += '\n%s' % tag
4029
4030 if diff:
4031 with open(make_opts, 'w') as fsock:
4032 fsock.write(content_variables + '\n'.join(content))
4033 return
4034
4035
4036
4038 """links lhapdf into libdir"""
4039
4040 lhapdf_version = self.get_lhapdf_version()
4041 logger.info('Using LHAPDF v%s interface for PDFs' % lhapdf_version)
4042 lhalibdir = subprocess.Popen([self.options['lhapdf'], '--libdir'],
4043 stdout = subprocess.PIPE).stdout.read().decode().strip()
4044
4045 if lhapdf_version.startswith('5.'):
4046 pdfsetsdir = subprocess.Popen([self.options['lhapdf'], '--pdfsets-path'],
4047 stdout = subprocess.PIPE).stdout.read().decode().strip()
4048 else:
4049 pdfsetsdir = subprocess.Popen([self.options['lhapdf'], '--datadir'],
4050 stdout = subprocess.PIPE).stdout.read().decode().strip()
4051
4052 self.lhapdf_pdfsets = self.get_lhapdf_pdfsets_list(pdfsetsdir)
4053
4054 lhalib = 'libLHAPDF.a'
4055
4056 if os.path.exists(pjoin(libdir, lhalib)):
4057 files.rm(pjoin(libdir, lhalib))
4058 files.ln(pjoin(lhalibdir, lhalib), libdir)
4059
4060 if not os.path.isdir(pjoin(libdir, 'PDFsets')):
4061 os.mkdir(pjoin(libdir, 'PDFsets'))
4062 self.make_opts_var['lhapdf'] = self.options['lhapdf']
4063 self.make_opts_var['lhapdfversion'] = lhapdf_version[0]
4064 self.make_opts_var['lhapdfsubversion'] = lhapdf_version.split('.',2)[1]
4065 self.make_opts_var['lhapdf_config'] = self.options['lhapdf']
4066
4067
4069 """reads the proc_characteristics file and initialises the correspondant
4070 dictionary"""
4071
4072 if not path:
4073 path = os.path.join(self.me_dir, 'SubProcesses', 'proc_characteristics')
4074
4075 self.proc_characteristics = banner_mod.ProcCharacteristic(path)
4076 return self.proc_characteristics
4077
4078
4080 """copy (if needed) the lhapdf set corresponding to the lhaid in lhaid_list
4081 into lib/PDFsets.
4082 if require_local is False, just ensure that the pdf is in pdfsets_dir
4083 """
4084
4085 if not hasattr(self, 'lhapdf_pdfsets'):
4086 self.lhapdf_pdfsets = self.get_lhapdf_pdfsets_list(pdfsets_dir)
4087
4088 pdfsetname=set()
4089 for lhaid in lhaid_list:
4090 if isinstance(lhaid, str) and lhaid.isdigit():
4091 lhaid = int(lhaid)
4092 if isinstance(lhaid, (int,float)):
4093 try:
4094 if lhaid in self.lhapdf_pdfsets:
4095 pdfsetname.add(self.lhapdf_pdfsets[lhaid]['filename'])
4096 else:
4097 raise MadGraph5Error('lhaid %s not valid input number for the current lhapdf' % lhaid )
4098 except KeyError:
4099 if self.lhapdf_version.startswith('5'):
4100 raise MadGraph5Error(\
4101 ('invalid lhaid set in th run_card: %d .\nPlease note that some sets' % lhaid) + \
4102 '(eg MSTW 90%CL error sets) \nare not available in aMC@NLO + LHAPDF 5.x.x')
4103 else:
4104 logger.debug('%d not found in pdfsets.index' % lhaid)
4105 else:
4106 pdfsetname.add(lhaid)
4107
4108
4109
4110
4111 if not os.path.isdir(pdfsets_dir):
4112 try:
4113 os.mkdir(pdfsets_dir)
4114 except OSError:
4115 pdfsets_dir = pjoin(self.me_dir, 'lib', 'PDFsets')
4116 elif os.path.exists(pjoin(self.me_dir, 'lib', 'PDFsets')):
4117
4118 for name in os.listdir(pjoin(self.me_dir, 'lib', 'PDFsets')):
4119 if name not in pdfsetname:
4120 try:
4121 if os.path.isdir(pjoin(self.me_dir, 'lib', 'PDFsets', name)):
4122 shutil.rmtree(pjoin(self.me_dir, 'lib', 'PDFsets', name))
4123 else:
4124 os.remove(pjoin(self.me_dir, 'lib', 'PDFsets', name))
4125 except Exception as error:
4126 logger.debug('%s', error)
4127
4128 if self.options["cluster_local_path"]:
4129 lhapdf_cluster_possibilities = [self.options["cluster_local_path"],
4130 pjoin(self.options["cluster_local_path"], "lhapdf"),
4131 pjoin(self.options["cluster_local_path"], "lhapdf", "pdfsets"),
4132 pjoin(self.options["cluster_local_path"], "..", "lhapdf"),
4133 pjoin(self.options["cluster_local_path"], "..", "lhapdf", "pdfsets"),
4134 pjoin(self.options["cluster_local_path"], "..", "lhapdf","pdfsets", "6.1")
4135 ]
4136 else:
4137 lhapdf_cluster_possibilities = []
4138
4139 for pdfset in pdfsetname:
4140
4141 if self.options["cluster_local_path"] and self.options["run_mode"] == 1 and \
4142 any((os.path.exists(pjoin(d, pdfset)) for d in lhapdf_cluster_possibilities)):
4143
4144 os.environ["LHAPATH"] = [d for d in lhapdf_cluster_possibilities if os.path.exists(pjoin(d, pdfset))][0]
4145 os.environ["CLUSTER_LHAPATH"] = os.environ["LHAPATH"]
4146
4147 if os.path.exists(pjoin(pdfsets_dir, pdfset)):
4148 try:
4149 if os.path.isdir(pjoin(pdfsets_dir, name)):
4150 shutil.rmtree(pjoin(pdfsets_dir, name))
4151 else:
4152 os.remove(pjoin(pdfsets_dir, name))
4153 except Exception as error:
4154 logger.debug('%s', error)
4155 if not require_local and (os.path.exists(pjoin(pdfsets_dir, pdfset)) or \
4156 os.path.isdir(pjoin(pdfsets_dir, pdfset))):
4157 continue
4158 if not require_local:
4159 if 'LHAPDF_DATA_PATH' in os.environ:
4160 found = False
4161 for path in os.environ['LHAPDF_DATA_PATH'].split(":"):
4162 if (os.path.exists(pjoin(path, pdfset)) or \
4163 os.path.isdir(pjoin(path, pdfset))):
4164 found =True
4165 break
4166 if found:
4167 continue
4168
4169
4170
4171 elif not os.path.exists(pjoin(self.me_dir, 'lib', 'PDFsets', pdfset)) and \
4172 not os.path.isdir(pjoin(self.me_dir, 'lib', 'PDFsets', pdfset)):
4173
4174 if pdfset and not os.path.exists(pjoin(pdfsets_dir, pdfset)):
4175 self.install_lhapdf_pdfset(pdfsets_dir, pdfset)
4176
4177 if os.path.exists(pjoin(pdfsets_dir, pdfset)):
4178 files.cp(pjoin(pdfsets_dir, pdfset), pjoin(self.me_dir, 'lib', 'PDFsets'))
4179 elif os.path.exists(pjoin(os.path.dirname(pdfsets_dir), pdfset)):
4180 files.cp(pjoin(os.path.dirname(pdfsets_dir), pdfset), pjoin(self.me_dir, 'lib', 'PDFsets'))
4181
4183 """idownloads and install the pdfset filename in the pdfsets_dir"""
4184 lhapdf_version = self.get_lhapdf_version()
4185 local_path = pjoin(self.me_dir, 'lib', 'PDFsets')
4186 return self.install_lhapdf_pdfset_static(self.options['lhapdf'],
4187 pdfsets_dir, filename,
4188 lhapdf_version=lhapdf_version,
4189 alternate_path=local_path)
4190
4191
4192 @staticmethod
4195 """idownloads and install the pdfset filename in the pdfsets_dir.
4196 Version which can be used independently of the class.
4197 local path is used if the global installation fails.
4198 """
4199
4200 if not lhapdf_version:
4201 lhapdf_version = CommonRunCmd.get_lhapdf_version_static(lhapdf_config)
4202
4203 if not pdfsets_dir:
4204 pdfsets_dir = CommonRunCmd.get_lhapdf_pdfsetsdir_static(lhapdf_config, lhapdf_version)
4205
4206 if isinstance(filename, int):
4207 pdf_info = CommonRunCmd.get_lhapdf_pdfsets_list_static(pdfsets_dir, lhapdf_version)
4208 filename = pdf_info[filename]['filename']
4209
4210 if os.path.exists(pjoin(pdfsets_dir, filename)):
4211 logger.debug('%s is already present in %s', filename, pdfsets_dir)
4212 return
4213
4214 logger.info('Trying to download %s' % filename)
4215
4216
4217 if lhapdf_version.startswith('5.'):
4218
4219
4220
4221 getdata = lhapdf_config.replace('lhapdf-config', ('lhapdf-getdata'))
4222 misc.call([getdata, filename], cwd = pdfsets_dir)
4223
4224 elif lhapdf_version.startswith('6.'):
4225
4226
4227 getdata = lhapdf_config.replace('lhapdf-config', ('lhapdf'))
4228
4229 if lhapdf_version.startswith('6.1'):
4230 misc.call([getdata, 'install', filename], cwd = pdfsets_dir)
4231 else:
4232
4233 lhapdf = misc.import_python_lhapdf(lhapdf_config)
4234 if lhapdf:
4235 if 'PYTHONPATH' in os.environ:
4236 os.environ['PYTHONPATH']+= ':' + os.path.dirname(lhapdf.__file__)
4237 else:
4238 os.environ['PYTHONPATH'] = ':'.join(sys.path) + ':' + os.path.dirname(lhapdf.__file__)
4239 else:
4240 logger.warning('lhapdf 6.2.1 requires python integration in order to download pdf set. Trying anyway')
4241 misc.call([getdata, 'install', filename], cwd = pdfsets_dir)
4242
4243 else:
4244 raise MadGraph5Error('Not valid LHAPDF version: %s' % lhapdf_version)
4245
4246
4247 if os.path.exists(pjoin(pdfsets_dir, filename)) or \
4248 os.path.isdir(pjoin(pdfsets_dir, filename)):
4249 logger.info('%s successfully downloaded and stored in %s' \
4250 % (filename, pdfsets_dir))
4251
4252
4253 elif lhapdf_version.startswith('5.'):
4254 logger.warning('Could not download %s into %s. Trying to save it locally' \
4255 % (filename, pdfsets_dir))
4256 CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, alternate_path, filename,
4257 lhapdf_version=lhapdf_version)
4258 elif lhapdf_version.startswith('6.') and '.LHgrid' in filename:
4259 logger.info('Could not download %s: Try %s', filename, filename.replace('.LHgrid',''))
4260 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, pdfsets_dir,
4261 filename.replace('.LHgrid',''),
4262 lhapdf_version, alternate_path)
4263 elif lhapdf_version.startswith('6.'):
4264
4265 wwwpath = "http://lhapdfsets.web.cern.ch/lhapdfsets/current/%s.tar.gz" % filename
4266 misc.wget(wwwpath, pjoin(pdfsets_dir, '%s.tar.gz' %filename))
4267 misc.call(['tar', '-xzpvf', '%s.tar.gz' %filename],
4268 cwd=pdfsets_dir)
4269
4270 if os.path.exists(pjoin(pdfsets_dir, filename)) or \
4271 os.path.isdir(pjoin(pdfsets_dir, filename)):
4272 logger.info('%s successfully downloaded and stored in %s' \
4273 % (filename, pdfsets_dir))
4274 elif 'LHAPDF_DATA_PATH' in os.environ and os.environ['LHAPDF_DATA_PATH']:
4275
4276 if pdfsets_dir in os.environ['LHAPDF_DATA_PATH'].split(':'):
4277 lhapath = os.environ['LHAPDF_DATA_PATH'].split(':')
4278 lhapath = [p for p in lhapath if os.path.exists(p)]
4279 lhapath.remove(pdfsets_dir)
4280 os.environ['LHAPDF_DATA_PATH'] = ':'.join(lhapath)
4281 if lhapath:
4282 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4283 filename,
4284 lhapdf_version, alternate_path)
4285 elif 'LHAPATH' in os.environ and os.environ['LHAPATH']:
4286 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4287 filename,
4288 lhapdf_version, alternate_path)
4289 else:
4290 raise MadGraph5Error( \
4291 'Could not download %s into %s. Please try to install it manually.' \
4292 % (filename, pdfsets_dir))
4293 else:
4294 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4295 filename,
4296 lhapdf_version, alternate_path)
4297 elif 'LHAPATH' in os.environ and os.environ['LHAPATH']:
4298 if pdfsets_dir in os.environ['LHAPATH'].split(':'):
4299 lhapath = os.environ['LHAPATH'].split(':')
4300 lhapath = [p for p in lhapath if os.path.exists(p)]
4301 lhapath.remove(pdfsets_dir)
4302 os.environ['LHAPATH'] = ':'.join(lhapath)
4303 if lhapath:
4304 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4305 filename,
4306 lhapdf_version, alternate_path)
4307 else:
4308 raise MadGraph5Error('Could not download %s into %s. Please try to install it manually.' \
4309 % (filename, pdfsets_dir))
4310 else:
4311 return CommonRunCmd.install_lhapdf_pdfset_static(lhapdf_config, None,
4312 filename,
4313 lhapdf_version, alternate_path)
4314 else:
4315 raise MadGraph5Error('Could not download %s into %s. Please try to install it manually.' \
4316 % (filename, pdfsets_dir))
4317
4318 else:
4319 raise MadGraph5Error('Could not download %s into %s. Please try to install it manually.' \
4320 % (filename, pdfsets_dir))
4321
4322
4323
4325 """read the PDFsets.index file, which should be located in the same
4326 place as pdfsets_dir, and return a list of dictionaries with the information
4327 about each pdf set"""
4328 lhapdf_version = self.get_lhapdf_version()
4329 return self.get_lhapdf_pdfsets_list_static(pdfsets_dir, lhapdf_version)
4330
4331 @staticmethod
4333
4334 if lhapdf_version.startswith('5.'):
4335 if os.path.exists('%s.index' % pdfsets_dir):
4336 indexfile = '%s.index' % pdfsets_dir
4337 else:
4338 raise MadGraph5Error('index of lhapdf file not found')
4339 pdfsets_lines = \
4340 [l for l in open(indexfile).read().split('\n') if l.strip() and \
4341 not '90cl' in l]
4342 lhapdf_pdfsets = dict( (int(l.split()[0]), {'lhaid': int(l.split()[0]),
4343 'pdflib_ntype': int(l.split()[1]),
4344 'pdflib_ngroup': int(l.split()[2]),
4345 'pdflib_nset': int(l.split()[3]),
4346 'filename': l.split()[4],
4347 'lhapdf_nmem': int(l.split()[5]),
4348 'q2min': float(l.split()[6]),
4349 'q2max': float(l.split()[7]),
4350 'xmin': float(l.split()[8]),
4351 'xmax': float(l.split()[9]),
4352 'description': l.split()[10]}) \
4353 for l in pdfsets_lines)
4354
4355 elif lhapdf_version.startswith('6.'):
4356 pdfsets_lines = \
4357 [l for l in open(pjoin(pdfsets_dir, 'pdfsets.index'),'r').read().split('\n') if l.strip()]
4358 lhapdf_pdfsets = dict( (int(l.split()[0]),
4359 {'lhaid': int(l.split()[0]),
4360 'filename': l.split()[1]}) \
4361 for l in pdfsets_lines)
4362
4363 else:
4364 raise MadGraph5Error('Not valid LHAPDF version: %s' % lhapdf_version)
4365
4366 return lhapdf_pdfsets
4367
4368 @staticmethod
4370 """returns the lhapdf version number"""
4371
4372 try:
4373 lhapdf_version = \
4374 subprocess.Popen([lhapdf_config, '--version'],
4375 stdout = subprocess.PIPE).stdout.read().decode().strip()
4376 except OSError as error:
4377 if error.errno == 2:
4378 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)
4379 else:
4380 raise
4381
4382
4383 if lhapdf_version.startswith('6.0'):
4384 raise MadGraph5Error('LHAPDF 6.0.x not supported. Please use v6.1 or later')
4385 return lhapdf_version
4386
4387
4389 """returns the lhapdf version number"""
4390 if not hasattr(self, 'lhapdfversion'):
4391 self.lhapdf_version = self.get_lhapdf_version_static(self.options['lhapdf'])
4392 return self.lhapdf_version
4393
4394 @staticmethod
4396 """ """
4397 if not lhapdf_version:
4398 lhapdf_version = CommonRunCmd.get_lhapdf_version_static(lhapdf_config)
4399
4400
4401 if 'LHAPDF_DATA_PATH' in list(os.environ.keys()) and os.environ['LHAPDF_DATA_PATH']:
4402 datadir = os.environ['LHAPDF_DATA_PATH']
4403 elif lhapdf_version.startswith('5.'):
4404 datadir = subprocess.Popen([lhapdf_config, '--pdfsets-path'],
4405 stdout = subprocess.PIPE).stdout.read().decode().strip()
4406
4407 elif lhapdf_version.startswith('6.'):
4408 datadir = subprocess.Popen([lhapdf_config, '--datadir'],
4409 stdout = subprocess.PIPE).stdout.read().decode().strip()
4410
4411 if ':' in datadir:
4412 for totry in datadir.split(':'):
4413 if os.path.exists(pjoin(totry, 'pdfsets.index')):
4414 return totry
4415 else:
4416 return None
4417
4418 return datadir
4419
4424
4425
4427 """get the list of Pdirectory if not yet saved."""
4428
4429 if hasattr(self, "Pdirs"):
4430 if self.me_dir in self.Pdirs[0]:
4431 return self.Pdirs
4432 self.Pdirs = [pjoin(self.me_dir, 'SubProcesses', l.strip())
4433 for l in open(pjoin(self.me_dir,'SubProcesses', 'subproc.mg'))]
4434 return self.Pdirs
4435
4437
4438 if 'LHAPATH' in os.environ:
4439 for d in os.environ['LHAPATH'].split(':'):
4440 if os.path.isdir(d):
4441 return d
4442
4443
4444 lhapdf_version = self.get_lhapdf_version()
4445
4446 if lhapdf_version.startswith('5.'):
4447 libdir = subprocess.Popen([self.options['lhapdf-config'], '--libdir'],
4448 stdout = subprocess.PIPE).stdout.read().decode().strip()
4449
4450 elif lhapdf_version.startswith('6.'):
4451 libdir = subprocess.Popen([self.options['lhapdf'], '--libs'],
4452 stdout = subprocess.PIPE).stdout.read().decode().strip()
4453
4454 return libdir
4455
4457 """A class for asking a question where in addition you can have the
4458 set command define and modifying the param_card/run_card correctly
4459
4460 special action can be trigger via trigger_XXXX when the user start a line
4461 with XXXX. the output of such function should be new line that can be handle.
4462 (return False to repeat the question)
4463 """
4464
4465 all_card_name = ['param_card', 'run_card', 'pythia_card', 'pythia8_card',
4466 'madweight_card', 'MadLoopParams', 'shower_card']
4467 to_init_card = ['param', 'run', 'madweight', 'madloop',
4468 'shower', 'pythia8','delphes','madspin']
4469 special_shortcut = {}
4470 special_shortcut_help = {}
4471
4472 integer_bias = 1
4473
4474 PY8Card_class = banner_mod.PY8Card
4475
4477 """ define all default variable. No load of card here.
4478 This allow to subclass this class and just change init and still have
4479 all variables defined."""
4480
4481 if not hasattr(self, 'me_dir'):
4482 self.me_dir = None
4483 self.param_card = None
4484 self.run_card = {}
4485 self.pname2block = {}
4486 self.conflict = []
4487 self.restricted_value = {}
4488 self.mode = ''
4489 self.cards = []
4490 self.run_set = []
4491 self.has_mw = False
4492 self.has_ml = False
4493 self.has_shower = False
4494 self.has_PY8 = False
4495 self.has_delphes = False
4496 self.paths = {}
4497 self.update_block = []
4498
4499
4501
4502 if 'pwd' in opt:
4503 self.me_dir = opt['pwd']
4504 elif 'mother_interface' in opt:
4505 self.mother_interface = opt['mother_interface']
4506 if not hasattr(self, 'me_dir') or not self.me_dir:
4507 self.me_dir = self.mother_interface.me_dir
4508
4509
4510 self.paths['param'] = pjoin(self.me_dir,'Cards','param_card.dat')
4511 self.paths['param_default'] = pjoin(self.me_dir,'Cards','param_card_default.dat')
4512 self.paths['run'] = pjoin(self.me_dir,'Cards','run_card.dat')
4513 self.paths['run_default'] = pjoin(self.me_dir,'Cards','run_card_default.dat')
4514 self.paths['transfer'] =pjoin(self.me_dir,'Cards','transfer_card.dat')
4515 self.paths['MadWeight'] =pjoin(self.me_dir,'Cards','MadWeight_card.dat')
4516 self.paths['MadWeight_default'] =pjoin(self.me_dir,'Cards','MadWeight_card_default.dat')
4517 self.paths['ML'] =pjoin(self.me_dir,'Cards','MadLoopParams.dat')
4518 self.paths['shower'] = pjoin(self.me_dir,'Cards','shower_card.dat')
4519 self.paths['shower_default'] = pjoin(self.me_dir,'Cards','shower_card_default.dat')
4520 self.paths['FO_analyse'] = pjoin(self.me_dir,'Cards','FO_analyse_card.dat')
4521 self.paths['FO_analyse_default'] = pjoin(self.me_dir,'Cards','FO_analyse_card_default.dat')
4522 self.paths['pythia'] =pjoin(self.me_dir, 'Cards','pythia_card.dat')
4523 self.paths['pythia8'] = pjoin(self.me_dir, 'Cards','pythia8_card.dat')
4524 self.paths['pythia8_default'] = pjoin(self.me_dir, 'Cards','pythia8_card_default.dat')
4525 self.paths['madspin_default'] = pjoin(self.me_dir,'Cards/madspin_card_default.dat')
4526 self.paths['madspin'] = pjoin(self.me_dir,'Cards/madspin_card.dat')
4527 self.paths['reweight'] = pjoin(self.me_dir,'Cards','reweight_card.dat')
4528 self.paths['delphes'] = pjoin(self.me_dir,'Cards','delphes_card.dat')
4529 self.paths['plot'] = pjoin(self.me_dir,'Cards','plot_card.dat')
4530 self.paths['plot_default'] = pjoin(self.me_dir,'Cards','plot_card_default.dat')
4531 self.paths['madanalysis5_parton'] = pjoin(self.me_dir,'Cards','madanalysis5_parton_card.dat')
4532 self.paths['madanalysis5_hadron'] = pjoin(self.me_dir,'Cards','madanalysis5_hadron_card.dat')
4533 self.paths['madanalysis5_parton_default'] = pjoin(self.me_dir,'Cards','madanalysis5_parton_card_default.dat')
4534 self.paths['madanalysis5_hadron_default'] = pjoin(self.me_dir,'Cards','madanalysis5_hadron_card_default.dat')
4535 self.paths['FO_analyse'] = pjoin(self.me_dir,'Cards', 'FO_analyse_card.dat')
4536
4537
4538
4539
4540 - def __init__(self, question, cards=[], from_banner=None, banner=None, mode='auto', *args, **opt):
4541
4542
4543 self.load_default()
4544 self.define_paths(**opt)
4545 self.last_editline_pos = 0
4546
4547 if 'allow_arg' not in opt or not opt['allow_arg']:
4548
4549 opt['allow_arg'] = list(range(self.integer_bias, self.integer_bias+len(cards)))
4550
4551 self.param_consistency = True
4552 if 'param_consistency' in opt:
4553 self.param_consistency = opt['param_consistency']
4554
4555 cmd.OneLinePathCompletion.__init__(self, question, *args, **opt)
4556
4557 self.conflict = set()
4558 self.mode = mode
4559 self.cards = cards
4560 self.all_vars = set()
4561 self.modified_card = set()
4562
4563 self.init_from_banner(from_banner, banner)
4564 self.writting_card = True
4565 if 'write_file' in opt:
4566 if not opt['write_file']:
4567 self.writting_card = False
4568 self.param_consistency = False
4569
4570
4571 for card in cards:
4572 if os.path.exists(card) and os.path.sep in cards:
4573 card_name = CommonRunCmd.detect_card_type(card)
4574 card_name = card_name.split('_',1)[0]
4575 self.paths[card_name] = card
4576
4577
4578 for name in self.to_init_card:
4579 new_vars = set(getattr(self, 'init_%s' % name)(cards))
4580 new_conflict = self.all_vars.intersection(new_vars)
4581 self.conflict.union(new_conflict)
4582 self.all_vars.union(new_vars)
4583
4584
4586 """ defined card that need to be initialized from the banner file
4587 from_banner should be a list of card to load from the banner object
4588 """
4589
4590 if from_banner is None:
4591 self.from_banner = {}
4592 return
4593
4594 self.from_banner = {}
4595 try:
4596 for card in from_banner:
4597 self.from_banner[card] = banner.charge_card(card)
4598 except KeyError:
4599 if from_banner == ['param', 'run'] and list(banner.keys()) == ['mgversion']:
4600 if self.mother_interface:
4601 results = self.mother_interface.results
4602 run_name = self.mother_interface.run_name
4603 run_tag = self.mother_interface.run_tag
4604 banner = banner_mod.recover_banner(results, 'parton', run_name, run_tag)
4605 self.mother_interface.banner = banner
4606 return self.init_from_banner(from_banner, banner)
4607 else:
4608 raise
4609
4610 return self.from_banner
4611
4612
4614 """initialise the path if requested"""
4615
4616 defname = '%s_default' % name
4617
4618 if name in self.from_banner:
4619 return self.from_banner[name]
4620
4621 if isinstance(cards, list):
4622 if name in cards:
4623 return True
4624 elif '%s_card.dat' % name in cards:
4625 return True
4626 elif name in self.paths and self.paths[name] in cards:
4627 return True
4628 else:
4629 cardnames = [os.path.basename(p) for p in cards]
4630 if '%s_card.dat' % name in cardnames:
4631 return True
4632 else:
4633 return False
4634
4635 elif isinstance(cards, dict) and name in cards:
4636 self.paths[name]= cards[name]
4637 if defname in cards:
4638 self.paths[defname] = cards[defname]
4639 elif os.path.isfile(cards[name].replace('.dat', '_default.dat')):
4640 self.paths[defname] = cards[name].replace('.dat', '_default.dat')
4641 else:
4642 self.paths[defname] = self.paths[name]
4643
4644 return True
4645 else:
4646 return False
4647
4649 """check if we need to load the param_card"""
4650
4651 self.pname2block = {}
4652 self.restricted_value = {}
4653 self.param_card = {}
4654
4655 is_valid_path = self.get_path('param', cards)
4656 if not is_valid_path:
4657 self.param_consistency = False
4658 return []
4659 if isinstance(is_valid_path, param_card_mod.ParamCard):
4660 self.param_card = is_valid_path
4661 self.param_consistency = False
4662 return []
4663
4664 try:
4665 self.param_card = param_card_mod.ParamCard(self.paths['param'])
4666 except (param_card_mod.InvalidParamCard, ValueError) as e:
4667 logger.error('Current param_card is not valid. We are going to use the default one.')
4668 logger.error('problem detected: %s' % e)
4669 files.cp(self.paths['param_default'], self.paths['param'])
4670 self.param_card = param_card_mod.ParamCard(self.paths['param'])
4671
4672
4673
4674
4675 if os.path.exists(self.paths['param_default']):
4676 default_param = param_card_mod.ParamCard(self.paths['param_default'])
4677 else:
4678 default_param = param_card_mod.ParamCard(self.param_card)
4679 self.pname2block, self.restricted_value = default_param.analyze_param_card()
4680 self.param_card_default = default_param
4681 return list(self.pname2block.keys())
4682
4684
4685 self.run_set = []
4686 is_valid_path = self.get_path('run', cards)
4687 if not is_valid_path:
4688 return []
4689 if isinstance(is_valid_path, banner_mod.RunCard):
4690 self.run_card = is_valid_path
4691 return []
4692
4693
4694 try:
4695 self.run_card = banner_mod.RunCard(self.paths['run'], consistency='warning')
4696 except IOError:
4697 self.run_card = {}
4698 try:
4699 run_card_def = banner_mod.RunCard(self.paths['run_default'])
4700 except IOError:
4701 run_card_def = {}
4702
4703
4704 if run_card_def:
4705 if self.run_card:
4706 self.run_set = list(run_card_def.keys()) + self.run_card.hidden_param
4707 else:
4708 self.run_set = list(run_card_def.keys()) + run_card_def.hidden_param
4709 elif self.run_card:
4710 self.run_set = list(self.run_card.keys())
4711 else:
4712 self.run_set = []
4713
4714 if self.run_set:
4715 self.special_shortcut.update(
4716 {'ebeam':([float],['run_card ebeam1 %(0)s', 'run_card ebeam2 %(0)s']),
4717 'lpp': ([int],['run_card lpp1 %(0)s', 'run_card lpp2 %(0)s' ]),
4718 'lhc': ([int],['run_card lpp1 1', 'run_card lpp2 1', 'run_card ebeam1 %(0)s*1000/2', 'run_card ebeam2 %(0)s*1000/2']),
4719 'lep': ([int],['run_card lpp1 0', 'run_card lpp2 0', 'run_card ebeam1 %(0)s/2', 'run_card ebeam2 %(0)s/2']),
4720 'ilc': ([int],['run_card lpp1 0', 'run_card lpp2 0', 'run_card ebeam1 %(0)s/2', 'run_card ebeam2 %(0)s/2']),
4721 'lcc': ([int],['run_card lpp1 1', 'run_card lpp2 1', 'run_card ebeam1 %(0)s*1000/2', 'run_card ebeam2 %(0)s*1000/2']),
4722 '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']),
4723 'no_parton_cut':([],['run_card nocut T']),
4724 'cm_velocity':([float], [lambda self :self.set_CM_velocity]),
4725 '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']),
4726 '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' ]),
4727 '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']),
4728 })
4729
4730 self.special_shortcut_help.update({
4731 'ebeam' : 'syntax: set ebeam VALUE:\n This parameter sets the energy to both beam to the value in GeV',
4732 'lpp' : 'syntax: set ebeam VALUE:\n'+\
4733 ' Set the type of beam to a given value for both beam\n'+\
4734 ' 0 : means no PDF\n'+\
4735 ' 1 : means proton PDF\n'+\
4736 ' -1 : means antiproton PDF\n'+\
4737 ' 2 : means PDF for elastic photon emited from a proton\n'+\
4738 ' 3 : means PDF for elastic photon emited from an electron',
4739 'lhc' : 'syntax: set lhc VALUE:\n Set for a proton-proton collision with that given center of mass energy (in TeV)',
4740 'lep' : 'syntax: set lep VALUE:\n Set for a electron-positron collision with that given center of mass energy (in GeV)',
4741 'fixed_scale' : 'syntax: set fixed_scale VALUE:\n Set all scales to the give value (in GeV)',
4742 'no_parton_cut': 'remove all cut (but BW_cutoff)',
4743 'cm_velocity': 'set sqrts to have the above velocity for the incoming particles',
4744 'pbpb': 'setup heavy ion configuration for lead-lead collision',
4745 'pbp': 'setup heavy ion configuration for lead-proton collision',
4746 'pp': 'remove setup of heavy ion configuration to set proton-proton collision',
4747 })
4748
4749 self.update_block += [b.name for b in self.run_card.blocks]
4750
4751 return self.run_set
4752
4754
4755 self.has_mw = False
4756 if not self.get_path('madweight', cards):
4757 return []
4758
4759
4760 self.do_change_tf = self.mother_interface.do_define_transfer_fct
4761 self.complete_change_tf = self.mother_interface.complete_define_transfer_fct
4762 self.help_change_tf = self.mother_interface.help_define_transfer_fct
4763 if not os.path.exists(self.paths['transfer']):
4764 logger.warning('No transfer function currently define. Please use the change_tf command to define one.')
4765
4766 self.has_mw = True
4767 try:
4768 import madgraph.madweight.Cards as mwcards
4769 except:
4770 import internal.madweight.Cards as mwcards
4771 self.mw_card = mwcards.Card(self.paths['MadWeight'])
4772 self.mw_card = self.mw_card.info
4773 self.mw_vars = []
4774 for key in self.mw_card:
4775 if key == 'comment':
4776 continue
4777 for key2 in self.mw_card.info[key]:
4778 if isinstance(key2, str) and not key2.isdigit():
4779 self.mw_vars.append(key2)
4780 return self.mw_vars
4781
4783
4784 if isinstance(cards, dict):
4785 for key in ['ML', 'madloop','MadLoop']:
4786 if key in cards:
4787 self.paths['ML'] = cards[key]
4788
4789 self.has_ml = False
4790 if os.path.isfile(self.paths['ML']):
4791 self.has_ml = True
4792 self.MLcard = banner_mod.MadLoopParam(self.paths['ML'])
4793 self.MLcardDefault = banner_mod.MadLoopParam()
4794 self.ml_vars = [k.lower() for k in self.MLcard.keys()]
4795 return self.ml_vars
4796 return []
4797
4799
4800 self.has_shower = False
4801 if not self.get_path('shower', cards):
4802 return []
4803 self.has_shower = True
4804 self.shower_card = shower_card_mod.ShowerCard(self.paths['shower'])
4805 self.shower_vars = list(self.shower_card.keys())
4806 return self.shower_vars
4807
4809
4810 self.has_PY8 = False
4811 if not self.get_path('pythia8', cards):
4812 return []
4813
4814 self.has_PY8 = True
4815 self.PY8Card = self.PY8Card_class(self.paths['pythia8'])
4816 self.PY8CardDefault = self.PY8Card_class()
4817
4818 self.py8_vars = [k.lower() for k in self.PY8Card.keys()]
4819
4820 self.special_shortcut.update({
4821 'simplepy8':([],['pythia8_card hadronlevel:all False',
4822 'pythia8_card partonlevel:mpi False',
4823 'pythia8_card BeamRemnants:primordialKT False',
4824 'pythia8_card PartonLevel:Remnants False',
4825 'pythia8_card Check:event False',
4826 'pythia8_card TimeShower:QEDshowerByQ False',
4827 'pythia8_card TimeShower:QEDshowerByL False',
4828 'pythia8_card SpaceShower:QEDshowerByQ False',
4829 'pythia8_card SpaceShower:QEDshowerByL False',
4830 'pythia8_card PartonLevel:FSRinResonances False',
4831 'pythia8_card ProcessLevel:resonanceDecays False',
4832 ]),
4833 'mpi':([bool],['pythia8_card partonlevel:mpi %(0)s']),
4834 })
4835 self.special_shortcut_help.update({
4836 'simplepy8' : 'Turn off non-perturbative slow features of Pythia8.',
4837 'mpi' : 'syntax: set mpi value: allow to turn mpi in Pythia8 on/off',
4838 })
4839 return []
4840
4842
4843 if not self.get_path('madspin', cards):
4844 return []
4845
4846 self.special_shortcut.update({
4847 'spinmode':([str], ['add madspin_card --before_line="launch" set spinmode %(0)s']),
4848 'nodecay':([], ['edit madspin_card --comment_line="decay"'])
4849 })
4850 self.special_shortcut_help.update({
4851 '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.',
4852 'nodecay': 'remove all decay previously defined in madspin',
4853 })
4854 return []
4855
4857
4858 self.has_delphes = False
4859 if not self.get_path('pythia8', cards):
4860 return []
4861 self.has_delphes = True
4862 return []
4863
4864
4866 """compute sqrts from the velocity in the center of mass frame"""
4867
4868 v = banner_mod.ConfigFile.format_variable(line, float, 'velocity')
4869
4870 self.mother_interface.get_characteristics()
4871 proc_info = self.mother_interface.proc_characteristics
4872 if 'pdg_initial1' not in proc_info:
4873 logger.warning('command not supported')
4874
4875 if len(proc_info['pdg_initial1']) == 1 == len(proc_info['pdg_initial2']) and\
4876 abs(proc_info['pdg_initial1'][0]) == abs(proc_info['pdg_initial2'][0]):
4877
4878 m = self.param_card.get_value('mass', abs(proc_info['pdg_initial1'][0]))
4879 sqrts = 2*m/ math.sqrt(1-v**2)
4880 self.do_set('run_card ebeam1 %s' % (sqrts/2.0))
4881 self.do_set('run_card ebeam2 %s' % (sqrts/2.0))
4882 self.do_set('run_card lpp 0')
4883 else:
4884 logger.warning('This is only possible for a single particle in the initial state')
4885
4886
4887
4888 - def do_help(self, line, conflict_raise=False, banner=True):
4889
4890
4891
4892 if banner:
4893 logger.info('*** HELP MESSAGE ***', '$MG:BOLD')
4894
4895 args = self.split_arg(line)
4896
4897 if len(args)==0 or (len(args) == 1 and hasattr(self, 'do_%s' % args[0])):
4898 out = cmd.BasicCmd.do_help(self, line)
4899 if len(args)==0:
4900 print('Allowed Argument')
4901 print('================')
4902 print('\t'.join(self.allow_arg))
4903 print()
4904 print('Special shortcut: (type help <name>)')
4905 print('====================================')
4906 print(' syntax: set <name> <value>')
4907 print('\t'.join(self.special_shortcut))
4908 print()
4909 if banner:
4910 logger.info('*** END HELP ***', '$MG:BOLD')
4911 return out
4912
4913
4914 if args[0] in self.special_shortcut:
4915 if args[0] in self.special_shortcut_help:
4916 print(self.special_shortcut_help[args[0]])
4917 if banner:
4918 logger.info('*** END HELP ***', '$MG:BOLD')
4919 return
4920
4921 start = 0
4922 card = ''
4923 if args[0]+'_card' in self.all_card_name+ self.cards:
4924 args[0] += '_card'
4925 elif args[0]+'.dat' in self.all_card_name+ self.cards:
4926 args[0] += '.dat'
4927 elif args[0]+'_card.dat' in self.all_card_name+ self.cards:
4928 args[0] += '_card.dat'
4929 if args[0] in self.all_card_name + self.cards:
4930 start += 1
4931 card = args[0]
4932 if len(args) == 1:
4933 if args[0] == 'pythia8_card':
4934 args[0] = 'PY8Card'
4935 if args[0] == 'param_card':
4936 logger.info("Param_card information: ", '$MG:color:BLUE')
4937 print("File to define the various model parameter")
4938 logger.info("List of the Block defined:",'$MG:color:BLUE')
4939 print("\t".join(list(self.param_card.keys())))
4940 elif args[0].startswith('madanalysis5'):
4941 print('This card allow to make plot with the madanalysis5 package')
4942 print('An example card is provided. For more information about the ')
4943 print('syntax please refer to: https://madanalysis.irmp.ucl.ac.be/')
4944 print('or to the user manual [arXiv:1206.1599]')
4945 if args[0].startswith('madanalysis5_hadron'):
4946 print()
4947 print('This card also allow to make recasting analysis')
4948 print('For more detail, see: arXiv:1407.3278')
4949 elif hasattr(self, args[0]):
4950 logger.info("%s information: " % args[0], '$MG:color:BLUE')
4951 print((eval('self.%s' % args[0]).__doc__))
4952 logger.info("List of parameter associated", '$MG:color:BLUE')
4953 print("\t".join(list(eval('self.%s' % args[0]).keys())))
4954 if banner:
4955 logger.info('*** END HELP ***', '$MG:BOLD')
4956 return card
4957
4958
4959 if args[start] in [l.lower() for l in self.run_card.keys()] and card in ['', 'run_card']:
4960 if args[start] not in self.run_set:
4961 args[start] = [l for l in self.run_set if l.lower() == args[start]][0]
4962
4963 if args[start] in self.conflict and not conflict_raise:
4964 conflict_raise = True
4965 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
4966 if card == '':
4967 logger.info('** If not explicitely speficy this parameter will modif the run_card file', '$MG:BOLD')
4968
4969 self.run_card.do_help(args[start])
4970
4971 elif (args[start] in self.param_card or args[start] == 'width') \
4972 and card in ['','param_card']:
4973 if args[start] in self.conflict and not conflict_raise:
4974 conflict_raise = True
4975 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
4976 if card == '':
4977 logger.info('** If not explicitely speficy this parameter will modif the param_card file', '$MG:BOLD')
4978
4979 if args[start] == 'width':
4980 args[start] = 'decay'
4981
4982 if len(args) == start+1:
4983 self.param_card.do_help(args[start], tuple())
4984 key = None
4985 elif args[start+1] in self.pname2block:
4986 all_var = self.pname2block[args[start+1]]
4987 key = None
4988 for bname, lhaid in all_var:
4989 if bname == args[start]:
4990 key = lhaid
4991 break
4992 else:
4993 logger.warning('%s is not part of block "%s" but "%s". please correct.' %
4994 (args[start+1], args[start], bname))
4995 else:
4996 try:
4997 key = tuple([int(i) for i in args[start+1:]])
4998 except ValueError:
4999 logger.warning('Failed to identify LHA information')
5000 return card
5001
5002 if key in self.param_card[args[start]].param_dict:
5003 self.param_card.do_help(args[start], key, default=self.param_card_default)
5004 elif key:
5005 logger.warning('invalid information: %s not defined in the param_card' % (key,))
5006
5007 elif args[start] in self.pname2block and card in ['','param_card']:
5008 if args[start] in self.conflict and not conflict_raise:
5009 conflict_raise = True
5010 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
5011 if card == '':
5012 logger.info('** If not explicitely speficy this parameter will modif the param_card file', '$MG:BOLD')
5013
5014 all_var = self.pname2block[args[start]]
5015 for bname, lhaid in all_var:
5016 new_line = 'param_card %s %s %s' % (bname,
5017 ' '.join([ str(i) for i in lhaid]), ' '.join(args[start+1:]))
5018 self.do_help(new_line, conflict_raise=True, banner=False)
5019
5020
5021 elif self.has_ml and args[start] in self.ml_vars \
5022 and card in ['', 'MadLoop_card']:
5023
5024 if args[start] in self.conflict and not conflict_raise:
5025 conflict_raise = True
5026 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
5027 if card == '':
5028 logger.info('** If not explicitely speficy this parameter will modif the madloop_card file', '$MG:BOLD')
5029
5030 self.MLcard.do_help(args[start])
5031
5032
5033 elif self.has_PY8 and args[start] in self.PY8Card:
5034 if args[start] in self.conflict and not conflict_raise:
5035 conflict_raise = True
5036 logger.info('** AMBIGUOUS NAME: %s **', args[start], '$MG:BOLD')
5037 if card == '':
5038 logger.info('** If not explicitely speficy this parameter will modif the pythia8_card file', '$MG:BOLD')
5039
5040 self.PY8Card.do_help(args[start])
5041 elif card.startswith('madanalysis5'):
5042 print('MA5')
5043
5044
5045 elif banner:
5046 print("no help available")
5047
5048 if banner:
5049 logger.info('*** END HELP ***', '$MG:BOLD')
5050
5051 return card
5052
5053
5054
5055
5056
5057
5059 prev_timer = signal.alarm(0)
5060 if prev_timer:
5061 nb_back = len(line)
5062 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
5063 self.stdout.write(line)
5064 self.stdout.flush()
5065
5066 possibilities = self.complete_set(text, line, begidx, endidx,formatting=False)
5067 if line[:begidx].strip() == 'help':
5068 possibilities['Defined command'] = cmd.BasicCmd.completenames(self, text, line)
5069 possibilities.update(self.complete_add(text, line, begidx, endidx,formatting=False))
5070 return self.deal_multiple_categories(possibilities)
5071
5072
5073
5074
5075
5077 prev_timer = signal.alarm(0)
5078 if prev_timer:
5079 nb_back = len(line)
5080 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
5081 self.stdout.write(line)
5082 self.stdout.flush()
5083
5084 valid = ['dependent', 'missing', 'to_slha1', 'to_slha2', 'to_full']
5085 valid += self.update_block
5086
5087 arg = line[:begidx].split()
5088 if len(arg) <=1:
5089 return self.list_completion(text, valid, line)
5090 elif arg[0] == 'to_full':
5091 return self.list_completion(text, self.cards , line)
5092
5093 - def complete_set(self, text, line, begidx, endidx, formatting=True):
5094 """ Complete the set command"""
5095
5096 prev_timer = signal.alarm(0)
5097 if prev_timer:
5098 nb_back = len(line)
5099 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
5100 self.stdout.write(line)
5101 self.stdout.flush()
5102
5103 possibilities = {}
5104 allowed = {}
5105 args = self.split_arg(line[0:begidx])
5106 if args[-1] in ['Auto', 'default']:
5107 return
5108
5109 if len(args) == 1:
5110 allowed = {'category':'', 'run_card':'', 'block':'all', 'param_card':'','shortcut':''}
5111 if self.has_mw:
5112 allowed['madweight_card'] = ''
5113 allowed['mw_block'] = 'all'
5114 if self.has_shower:
5115 allowed['shower_card'] = ''
5116 if self.has_ml:
5117 allowed['madloop_card'] = ''
5118 if self.has_PY8:
5119 allowed['pythia8_card'] = ''
5120 if self.has_delphes:
5121 allowed['delphes_card'] = ''
5122
5123 elif len(args) == 2:
5124 if args[1] == 'run_card':
5125 allowed = {'run_card':'default'}
5126 elif args[1] == 'param_card':
5127 allowed = {'block':'all', 'param_card':'default'}
5128 elif self.param_card and args[1] in list(self.param_card.keys()):
5129 allowed = {'block':args[1]}
5130 elif args[1] == 'width':
5131 allowed = {'block': 'decay'}
5132 elif args[1] == 'MadWeight_card':
5133 allowed = {'madweight_card':'default', 'mw_block': 'all'}
5134 elif args[1] == 'MadLoop_card':
5135 allowed = {'madloop_card':'default'}
5136 elif args[1] == 'pythia8_card':
5137 allowed = {'pythia8_card':'default'}
5138 elif self.has_mw and args[1] in list(self.mw_card.keys()):
5139 allowed = {'mw_block':args[1]}
5140 elif args[1] == 'shower_card':
5141 allowed = {'shower_card':'default'}
5142 elif args[1] == 'delphes_card':
5143 allowed = {'delphes_card':'default'}
5144 else:
5145 allowed = {'value':''}
5146
5147 else:
5148 start = 1
5149 if args[1] in ['run_card', 'param_card', 'MadWeight_card', 'shower_card',
5150 'MadLoop_card','pythia8_card','delphes_card','plot_card',
5151 'madanalysis5_parton_card','madanalysis5_hadron_card']:
5152 start = 2
5153
5154 if args[-1] in list(self.pname2block.keys()):
5155 allowed['value'] = 'default'
5156 elif args[start] in list(self.param_card.keys()) or args[start] == 'width':
5157 if args[start] == 'width':
5158 args[start] = 'decay'
5159
5160 if args[start+1:]:
5161 allowed = {'block':(args[start], args[start+1:])}
5162 else:
5163 allowed = {'block':args[start]}
5164 elif self.has_mw and args[start] in list(self.mw_card.keys()):
5165 if args[start+1:]:
5166 allowed = {'mw_block':(args[start], args[start+1:])}
5167 else:
5168 allowed = {'mw_block':args[start]}
5169
5170
5171 else:
5172 allowed['value'] = ''
5173
5174 if 'category' in list(allowed.keys()):
5175 categories = ['run_card', 'param_card']
5176 if self.has_mw:
5177 categories.append('MadWeight_card')
5178 if self.has_shower:
5179 categories.append('shower_card')
5180 if self.has_ml:
5181 categories.append('MadLoop_card')
5182 if self.has_PY8:
5183 categories.append('pythia8_card')
5184 if self.has_delphes:
5185 categories.append('delphes_card')
5186
5187 possibilities['category of parameter (optional)'] = \
5188 self.list_completion(text, categories)
5189
5190 if 'shortcut' in list(allowed.keys()):
5191 possibilities['special values'] = self.list_completion(text, list(self.special_shortcut.keys())+['qcut', 'showerkt'])
5192
5193 if 'run_card' in list(allowed.keys()):
5194 opts = self.run_set
5195 if allowed['run_card'] == 'default':
5196 opts.append('default')
5197
5198
5199 possibilities['Run Card'] = self.list_completion(text, opts)
5200
5201 if 'param_card' in list(allowed.keys()):
5202 opts = list(self.pname2block.keys())
5203 if allowed['param_card'] == 'default':
5204 opts.append('default')
5205 possibilities['Param Card'] = self.list_completion(text, opts)
5206
5207 if 'madweight_card' in list(allowed.keys()):
5208 opts = self.mw_vars + [k for k in self.mw_card.keys() if k !='comment']
5209 if allowed['madweight_card'] == 'default':
5210 opts.append('default')
5211 possibilities['MadWeight Card'] = self.list_completion(text, opts)
5212
5213 if 'madloop_card' in list(allowed.keys()):
5214 opts = self.ml_vars
5215 if allowed['madloop_card'] == 'default':
5216 opts.append('default')
5217 possibilities['MadLoop Parameter'] = self.list_completion(text, opts)
5218
5219 if 'pythia8_card' in list(allowed.keys()):
5220 opts = self.py8_vars
5221 if allowed['pythia8_card'] == 'default':
5222 opts.append('default')
5223 possibilities['Pythia8 Parameter'] = self.list_completion(text, opts)
5224
5225 if 'shower_card' in list(allowed.keys()):
5226 opts = self.shower_vars + [k for k in self.shower_card.keys() if k !='comment']
5227 if allowed['shower_card'] == 'default':
5228 opts.append('default')
5229 possibilities['Shower Card'] = self.list_completion(text, opts)
5230
5231 if 'delphes_card' in allowed:
5232 if allowed['delphes_card'] == 'default':
5233 opts = ['default', 'atlas', 'cms']
5234 possibilities['Delphes Card'] = self.list_completion(text, opts)
5235
5236 if 'value' in list(allowed.keys()):
5237 opts = ['default']
5238 if 'decay' in args:
5239 opts.append('Auto')
5240 opts.append('Auto@NLO')
5241 elif args[-1] in self.pname2block and self.pname2block[args[-1]][0][0] == 'decay':
5242 opts.append('Auto')
5243 opts.append('Auto@NLO')
5244 if args[-1] in self.run_set:
5245 allowed_for_run = []
5246 if args[-1].lower() in self.run_card.allowed_value:
5247 allowed_for_run = self.run_card.allowed_value[args[-1].lower()]
5248 if '*' in allowed_for_run:
5249 allowed_for_run.remove('*')
5250 elif isinstance(self.run_card[args[-1]], bool):
5251 allowed_for_run = ['True', 'False']
5252 opts += [str(i) for i in allowed_for_run]
5253
5254
5255 possibilities['Special Value'] = self.list_completion(text, opts)
5256
5257 if 'block' in list(allowed.keys()) and self.param_card:
5258 if allowed['block'] == 'all' and self.param_card:
5259 allowed_block = [i for i in self.param_card.keys() if 'qnumbers' not in i]
5260 allowed_block.append('width')
5261 possibilities['Param Card Block' ] = \
5262 self.list_completion(text, allowed_block)
5263
5264 elif isinstance(allowed['block'], six.string_types):
5265 block = self.param_card[allowed['block']].param_dict
5266 ids = [str(i[0]) for i in block
5267 if (allowed['block'], i) not in self.restricted_value]
5268 possibilities['Param Card id' ] = self.list_completion(text, ids)
5269 varname = [name for name, all_var in self.pname2block.items()
5270 if any((bname == allowed['block']
5271 for bname,lhaid in all_var))]
5272 possibilities['Param card variable'] = self.list_completion(text,
5273 varname)
5274 else:
5275 block = self.param_card[allowed['block'][0]].param_dict
5276 nb = len(allowed['block'][1])
5277 ids = [str(i[nb]) for i in block if len(i) > nb and \
5278 [str(a) for a in i[:nb]] == allowed['block'][1]]
5279
5280 if not ids:
5281 if tuple([int(i) for i in allowed['block'][1]]) in block:
5282 opts = ['default']
5283 if allowed['block'][0] == 'decay':
5284 opts.append('Auto')
5285 opts.append('Auto@NLO')
5286 possibilities['Special value'] = self.list_completion(text, opts)
5287 possibilities['Param Card id' ] = self.list_completion(text, ids)
5288
5289 if 'mw_block' in list(allowed.keys()):
5290 if allowed['mw_block'] == 'all':
5291 allowed_block = [i for i in self.mw_card.keys() if 'comment' not in i]
5292 possibilities['MadWeight Block' ] = \
5293 self.list_completion(text, allowed_block)
5294 elif isinstance(allowed['mw_block'], six.string_types):
5295 block = self.mw_card[allowed['mw_block']]
5296 ids = [str(i[0]) if isinstance(i, tuple) else str(i) for i in block]
5297 possibilities['MadWeight Card id' ] = self.list_completion(text, ids)
5298 else:
5299 block = self.mw_card[allowed['mw_block'][0]]
5300 nb = len(allowed['mw_block'][1])
5301 ids = [str(i[nb]) for i in block if isinstance(i, tuple) and\
5302 len(i) > nb and \
5303 [str(a) for a in i[:nb]] == allowed['mw_block'][1]]
5304
5305 if not ids:
5306 if tuple([i for i in allowed['mw_block'][1]]) in block or \
5307 allowed['mw_block'][1][0] in list(block.keys()):
5308 opts = ['default']
5309 possibilities['Special value'] = self.list_completion(text, opts)
5310 possibilities['MadWeight Card id' ] = self.list_completion(text, ids)
5311
5312 return self.deal_multiple_categories(possibilities, formatting)
5313
5315 """ edit the value of one parameter in the card"""
5316
5317
5318 args = self.split_arg(line)
5319
5320
5321 if len(args) == 0:
5322 logger.warning("No argument. For help type 'help set'.")
5323
5324 if len(args)==1 and '=' in args[-1]:
5325 arg1, arg2 = args.pop(-1).split('=',1)
5326 args += [arg1, arg2]
5327 if '=' in args:
5328 args.remove('=')
5329
5330 args[:-1] = [ a.lower() for a in args[:-1]]
5331 if len(args) == 1:
5332 args = [args[0].lower()]
5333
5334 if args[0] in self.special_shortcut:
5335 targettypes , cmd = self.special_shortcut[args[0]]
5336 if len(args) != len(targettypes) +1:
5337 logger.warning('shortcut %s requires %s argument' % (args[0], len(targettypes)))
5338 if len(args) < len(targettypes) +1:
5339 return
5340 else:
5341 logger.warning('additional argument will be ignored')
5342 values ={}
5343 for i, argtype in enumerate(targettypes):
5344 try:
5345 values = {str(i): banner_mod.ConfigFile.format_variable(args[i+1], argtype, args[0])}
5346 except ValueError as e:
5347 logger.warning("Wrong argument: The entry #%s should be of type %s.", i+1, argtype)
5348 return
5349 except InvalidCmd as e:
5350 logger.warning(str(e))
5351 return
5352
5353
5354
5355 for arg in cmd:
5356 if isinstance(arg, str):
5357 try:
5358 text = arg % values
5359 except KeyError:
5360 logger.warning("This command requires one argument")
5361 return
5362 except Exception as e:
5363 logger.warning(str(e))
5364 return
5365 else:
5366 split = text.split()
5367 if hasattr(self, 'do_%s' % split[0]):
5368 getattr(self, 'do_%s' % split[0])(' '.join(split[1:]))
5369 else:
5370 self.do_set(text)
5371
5372 else:
5373 val = [values[str(i)] for i in range(len(values))]
5374 try:
5375 arg(self)(*val)
5376 except Exception as e:
5377 logger.warning(str(e))
5378 return
5379
5380 start = 0
5381 if len(args) < 2:
5382 logger.warning('Invalid set command %s (need two arguments)' % line)
5383 return
5384
5385
5386 if args[0].lower() == 'qcut':
5387 pythia_path = self.paths['pythia']
5388 if os.path.exists(pythia_path):
5389 logger.info('add line QCUT = %s in pythia_card.dat' % args[1])
5390 p_card = open(pythia_path,'r').read()
5391 p_card, n = re.subn('''^\s*QCUT\s*=\s*[\de\+\-\.]*\s*$''',
5392 ''' QCUT = %s ''' % args[1], \
5393 p_card, flags=(re.M+re.I))
5394 if n==0:
5395 p_card = '%s \n QCUT= %s' % (p_card, args[1])
5396 with open(pythia_path, 'w') as fsock:
5397 fsock.write(p_card)
5398 return
5399
5400 if args[0].lower() == 'showerkt':
5401 pythia_path = self.paths['pythia']
5402 if os.path.exists(pythia_path):
5403 logger.info('add line SHOWERKT = %s in pythia_card.dat' % args[1].upper())
5404 p_card = open(pythia_path,'r').read()
5405 p_card, n = re.subn('''^\s*SHOWERKT\s*=\s*[default\de\+\-\.]*\s*$''',
5406 ''' SHOWERKT = %s ''' % args[1].upper(), \
5407 p_card, flags=(re.M+re.I))
5408 if n==0:
5409 p_card = '%s \n SHOWERKT= %s' % (p_card, args[1].upper())
5410 with open(pythia_path, 'w') as fsock:
5411 fsock.write(p_card)
5412 return
5413
5414 card = ''
5415 if args[0] == 'madweight_card':
5416 if not self.mw_card:
5417 logger.warning('Invalid Command: No MadWeight card defined.')
5418 return
5419 args[0] = 'MadWeight_card'
5420
5421 if args[0] == 'shower_card':
5422 if not self.shower_card:
5423 logger.warning('Invalid Command: No Shower card defined.')
5424 return
5425 args[0] = 'shower_card'
5426
5427 if args[0] == "madloop_card":
5428 if not self.has_ml:
5429 logger.warning('Invalid Command: No MadLoopParam card defined.')
5430 return
5431 args[0] = 'MadLoop_card'
5432
5433 if args[0] == "pythia8_card":
5434 if not self.has_PY8:
5435 logger.warning('Invalid Command: No Pythia8 card defined.')
5436 return
5437 args[0] = 'pythia8_card'
5438
5439 if args[0] == 'delphes_card':
5440 if not self.has_delphes:
5441 logger.warning('Invalid Command: No Delphes card defined.')
5442 return
5443 if args[1] == 'atlas':
5444 logger.info("set default ATLAS configuration for Delphes", '$MG:BOLD')
5445 files.cp(pjoin(self.me_dir,'Cards', 'delphes_card_ATLAS.dat'),
5446 pjoin(self.me_dir,'Cards', 'delphes_card.dat'))
5447 return
5448 elif args[1] == 'cms':
5449 logger.info("set default CMS configuration for Delphes",'$MG:BOLD')
5450 files.cp(pjoin(self.me_dir,'Cards', 'delphes_card_CMS.dat'),
5451 pjoin(self.me_dir,'Cards', 'delphes_card.dat'))
5452 return
5453
5454 if args[0] in ['run_card', 'param_card', 'MadWeight_card', 'shower_card',
5455 'delphes_card','madanalysis5_hadron_card','madanalysis5_parton_card']:
5456
5457 if args[1] == 'default':
5458 logger.info('replace %s by the default card' % args[0],'$MG:BOLD')
5459 files.cp(self.paths['%s_default' %args[0][:-5]], self.paths[args[0][:-5]])
5460 if args[0] == 'param_card':
5461 self.param_card = param_card_mod.ParamCard(self.paths['param'])
5462 elif args[0] == 'run_card':
5463 self.run_card = banner_mod.RunCard(self.paths['run'])
5464 elif args[0] == 'shower_card':
5465 self.shower_card = shower_card_mod.ShowerCard(self.paths['shower'])
5466 return
5467 else:
5468 card = args[0]
5469 start=1
5470 if len(args) < 3:
5471 logger.warning('Invalid set command: %s (not enough arguments)' % line)
5472 return
5473
5474 elif args[0] in ['MadLoop_card']:
5475 if args[1] == 'default':
5476 logger.info('replace MadLoopParams.dat by the default card','$MG:BOLD')
5477 self.MLcard = banner_mod.MadLoopParam(self.MLcardDefault)
5478 self.MLcard.write(self.paths['ML'],
5479 commentdefault=True)
5480 return
5481 else:
5482 card = args[0]
5483 start=1
5484 if len(args) < 3:
5485 logger.warning('Invalid set command: %s (not enough arguments)' % line)
5486 return
5487 elif args[0] in ['pythia8_card']:
5488 if args[1] == 'default':
5489 logger.info('replace pythia8_card.dat by the default card','$MG:BOLD')
5490 self.PY8Card = self.PY8Card_class(self.PY8CardDefault)
5491 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'),
5492 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'),
5493 print_only_visible=True)
5494 return
5495 else:
5496 card = args[0]
5497 start=1
5498 if len(args) < 3:
5499 logger.warning('Invalid set command: %s (not enough arguments)' % line)
5500 return
5501 elif args[0] in ['madspin_card']:
5502 if args[1] == 'default':
5503 logger.info('replace madspin_card.dat by the default card','$MG:BOLD')
5504 files.cp(self.paths['MS_default'], self.paths['madspin'])
5505 return
5506 else:
5507 logger.warning("""Command set not allowed for modifying the madspin_card.
5508 Check the command \"decay\" instead.""")
5509 return
5510
5511
5512 if args[start] in [l.lower() for l in self.run_card.keys()] and card in ['', 'run_card']:
5513
5514 if args[start] not in self.run_set:
5515 if card in self.from_banner or 'run' in self.from_banner:
5516 raise Exception("change not allowed for this card: event already generated!")
5517 args[start] = [l for l in self.run_set if l.lower() == args[start]][0]
5518
5519 if args[start] in self.conflict and card == '':
5520 text = 'Ambiguous name (present in more than one card). Will assume it to be referred to run_card.\n'
5521 text += 'If this is not intended, please reset it in the run_card and specify the relevant card to \n'
5522 text += 'edit, in the format < set card parameter value >'
5523 logger.warning(text)
5524
5525 if args[start+1] == 'default':
5526 default = banner_mod.RunCard(self.paths['run_default'])
5527 if args[start] in list(default.keys()):
5528 self.setR(args[start],default[args[start]])
5529 else:
5530 logger.info('remove information %s from the run_card' % args[start],'$MG:BOLD')
5531 del self.run_card[args[start]]
5532 else:
5533 lower_name = args[0].lower()
5534 if lower_name.startswith('sys_') or \
5535 lower_name in self.run_card.list_parameter or \
5536 lower_name in self.run_card.dict_parameter:
5537 val = ' '.join(args[start+1:])
5538 val = val.split('#')[0]
5539 else:
5540 val = ' '.join(args[start+1:])
5541 self.setR(args[start], val)
5542 self.modified_card.add('run')
5543
5544 elif card == 'run_card' and args[start] in ['nocut', 'no_cut']:
5545 logger.info("Going to remove all cuts from the run_card", '$MG:BOLD')
5546 self.run_card.remove_all_cut()
5547 self.modified_card.add('run')
5548
5549 elif self.param_card and (args[start] in self.param_card or args[start] == 'width') \
5550 and card in ['','param_card']:
5551
5552 if any(t.startswith('scan') for t in args):
5553 index = [i for i,t in enumerate(args) if t.startswith('scan')][0]
5554 args = args[:index] + [' '.join(args[index:])]
5555
5556 if args[start] in self.conflict and card == '':
5557 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5558 text += ' in the format < set card parameter value>'
5559 logger.warning(text)
5560 return
5561
5562 if args[start] == 'width':
5563 args[start] = 'decay'
5564
5565 if args[start+1] in self.pname2block:
5566 all_var = self.pname2block[args[start+1]]
5567 key = None
5568 for bname, lhaid in all_var:
5569 if bname == args[start]:
5570 key = lhaid
5571 break
5572 else:
5573 logger.warning('%s is not part of block "%s" but "%s". please correct.' %
5574 (args[start+1], args[start], bname))
5575 return
5576 else:
5577 try:
5578 key = tuple([int(i) for i in args[start+1:-1]])
5579 except ValueError:
5580 if args[start+1:-1] == ['all']:
5581 for key in self.param_card[args[start]].param_dict:
5582 if (args[start], key) in self.restricted_value:
5583 continue
5584 else:
5585 self.setP(args[start], key, args[-1])
5586 self.modified_card.add('param')
5587 return
5588 logger.warning('invalid set command %s (failed to identify LHA information)' % line)
5589 return
5590
5591 if key in self.param_card[args[start]].param_dict:
5592 if (args[start], key) in self.restricted_value:
5593 text = "Note that this parameter seems to be ignore by MG.\n"
5594 text += "MG will use instead the expression: %s\n" % \
5595 self.restricted_value[(args[start], key)]
5596 text += "You need to match this expression for external program (such pythia)."
5597 logger.warning(text)
5598
5599 if args[-1].lower() in ['default', 'auto', 'auto@nlo'] or args[-1].startswith('scan'):
5600 self.setP(args[start], key, args[-1])
5601 else:
5602 try:
5603 value = float(args[-1])
5604 except Exception:
5605 logger.warning('Invalid input: Expected number and not \'%s\'' \
5606 % args[-1])
5607 return
5608 self.setP(args[start], key, value)
5609 else:
5610 logger.warning('invalid set command %s' % line)
5611 return
5612 self.modified_card.add('param')
5613
5614
5615 elif args[start] in self.pname2block and card in ['','param_card']:
5616 if args[start] in self.conflict and card == '':
5617 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5618 text += ' in the format < set card parameter value>'
5619 logger.warning(text)
5620 return
5621
5622 all_var = self.pname2block[args[start]]
5623 for bname, lhaid in all_var:
5624 new_line = 'param_card %s %s %s' % (bname,
5625 ' '.join([ str(i) for i in lhaid]), ' '.join(args[start+1:]))
5626 self.do_set(new_line)
5627 if len(all_var) > 1:
5628 logger.warning('This variable correspond to more than one parameter in the param_card.')
5629 for bname, lhaid in all_var:
5630 logger.warning(' %s %s' % (bname, ' '.join([str(i) for i in lhaid])))
5631 logger.warning('all listed variables have been modified')
5632
5633
5634 elif self.has_mw and (args[start] in self.mw_card and args[start] != 'comment') \
5635 and card in ['','MadWeight_card']:
5636
5637 if args[start] in self.conflict and card == '':
5638 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5639 text += ' in the format < set card parameter value>'
5640 logger.warning(text)
5641 return
5642
5643 block = args[start]
5644 name = args[start+1]
5645 value = args[start+2:]
5646 self.setM(block, name, value)
5647 self.mw_card.write(self.paths['MadWeight'])
5648
5649
5650 elif self.has_mw and args[start] in self.mw_vars \
5651 and card in ['', 'MadWeight_card']:
5652
5653 if args[start] in self.conflict and card == '':
5654 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5655 text += ' in the format < set card parameter value>'
5656 logger.warning(text)
5657 return
5658
5659 block = [b for b, data in self.mw_card.items() if args[start] in data]
5660 if len(block) > 1:
5661 logger.warning('%s is define in more than one block: %s.Please specify.'
5662 % (args[start], ','.join(block)))
5663 return
5664
5665 block = block[0]
5666 name = args[start]
5667 value = args[start+1:]
5668 self.setM(block, name, value)
5669 self.mw_card.write(self.paths['MadWeight'])
5670
5671
5672 elif self.has_mw and args[start].startswith('mw_') and len(args[start:]) == 3\
5673 and card == 'MadWeight_card':
5674 block = args[start]
5675 name = args[start+1]
5676 value = args[start+2]
5677 self.setM(block, name, value)
5678 self.mw_card.write(self.paths['MadWeight'])
5679
5680
5681 elif self.has_shower and args[start].lower() in [l.lower() for l in \
5682 self.shower_card.keys()] and card in ['', 'shower_card']:
5683 if args[start] not in self.shower_card:
5684 args[start] = [l for l in self.shower_card if l.lower() == args[start].lower()][0]
5685
5686 if args[start] in self.conflict and card == '':
5687 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5688 text += ' in the format < set card parameter value>'
5689 logger.warning(text)
5690 return
5691
5692 if args[start+1].lower() == 'default':
5693 default = shower_card_mod.ShowerCard(self.paths['shower_default'])
5694 if args[start] in list(default.keys()):
5695 self.shower_card.set_param(args[start],default[args[start]], self.paths['shower'])
5696 else:
5697 logger.info('remove information %s from the shower_card' % args[start],'$MG:BOLD')
5698 del self.shower_card[args[start]]
5699 elif args[start+1].lower() in ['t','.true.','true']:
5700 self.shower_card.set_param(args[start],'.true.',self.paths['shower'])
5701 elif args[start+1].lower() in ['f','.false.','false']:
5702 self.shower_card.set_param(args[start],'.false.',self.paths['shower'])
5703 elif args[start] in ['analyse', 'extralibs', 'extrapaths', 'includepaths'] or\
5704 args[start].startswith('dm_'):
5705
5706 args = line.split()
5707 args_str = ' '.join(str(a) for a in args[start+1:len(args)])
5708 self.shower_card.set_param(args[start],args_str,pjoin(self.me_dir,'Cards','shower_card.dat'))
5709 else:
5710 args_str = ' '.join(str(a) for a in args[start+1:len(args)])
5711 self.shower_card.set_param(args[start],args_str,self.paths['shower'])
5712
5713
5714 elif self.has_ml and args[start] in self.ml_vars \
5715 and card in ['', 'MadLoop_card']:
5716
5717 if args[start] in self.conflict and card == '':
5718 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5719 logger.warning(text)
5720 return
5721
5722 if args[start+1] == 'default':
5723 value = self.MLcardDefault[args[start]]
5724 default = True
5725 else:
5726 value = args[start+1]
5727 default = False
5728 self.setML(args[start], value, default=default)
5729 self.MLcard.write(self.paths['ML'],
5730 commentdefault=True)
5731
5732
5733 elif self.has_PY8 and (card == 'pythia8_card' or (card == '' and \
5734 args[start] in self.PY8Card)):
5735
5736 if args[start] in self.conflict and card == '':
5737 text = 'ambiguous name (present in more than one card). Please specify which card to edit'
5738 logger.warning(text)
5739 return
5740
5741 if args[start+1] == 'default':
5742 value = self.PY8CardDefault[args[start]]
5743 default = True
5744 else:
5745 value = ' '.join(args[start+1:])
5746 default = False
5747 self.setPY8(args[start], value, default=default)
5748 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'),
5749 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'),
5750 print_only_visible=True)
5751
5752
5753 else:
5754 logger.warning('invalid set command %s ' % line)
5755 arg = args[start].lower()
5756 if self.has_PY8:
5757 close_opts = [name for name in self.PY8Card if name.lower().startswith(arg[:3]) or arg in name.lower()]
5758 if close_opts:
5759 logger.info('Did you mean one of the following PY8 options:\n%s' % '\t'.join(close_opts))
5760 if self.run_card:
5761 close_opts = [name for name in self.run_card if name.lower().startswith(arg[:3]) or arg in name.lower()]
5762 if close_opts:
5763 logger.info('Did you mean one of the following run_card options:\n%s' % '\t'.join(close_opts))
5764
5765 return
5766
5767 - def setM(self, block, name, value):
5768
5769 if isinstance(value, list) and len(value) == 1:
5770 value = value[0]
5771
5772 if block not in self.mw_card:
5773 logger.warning('block %s was not present in the current MadWeight card. We are adding it' % block)
5774 self.mw_card[block] = {}
5775 elif name not in self.mw_card[block]:
5776 logger.info('name %s was not present in the block %s for the current MadWeight card. We are adding it' % (name,block),'$MG:BOLD')
5777 if value == 'default':
5778 import madgraph.madweight.Cards as mwcards
5779 mw_default = mwcards.Card(self.paths['MadWeight_default'])
5780 try:
5781 value = mw_default[block][name]
5782 except KeyError:
5783 logger.info('removing id "%s" from Block "%s" '% (name, block),'$MG:BOLD')
5784 if name in self.mw_card[block]:
5785 del self.mw_card[block][name]
5786 return
5787 if value:
5788 logger.info('modify madweight_card information BLOCK "%s" with id "%s" set to %s',
5789 block, name, value, '$MG:BOLD')
5790 else:
5791 logger.warning("Invalid command: No value. To set default value. Use \"default\" as value")
5792 return
5793
5794 self.mw_card[block][name] = value
5795
5796 - def setR(self, name, value):
5797
5798 if self.mother_interface.inputfile:
5799 self.run_card.set(name, value, user=True, raiseerror=True)
5800 else:
5801 self.run_card.set(name, value, user=True)
5802 new_value = self.run_card.get(name)
5803 logger.info('modify parameter %s of the run_card.dat to %s' % (name, new_value),'$MG:BOLD')
5804
5805
5806 - def setML(self, name, value, default=False):
5807
5808 try:
5809 self.MLcard.set(name, value, user=True)
5810 except Exception as error:
5811 logger.warning("Fail to change parameter. Please Retry. Reason: %s." % error)
5812 return
5813 logger.info('modify parameter %s of the MadLoopParam.dat to %s' % (name, value),'$MG:BOLD')
5814 if default and name.lower() in self.MLcard.user_set:
5815 self.MLcard.user_set.remove(name.lower())
5816
5817 - def setPY8(self, name, value, default=False):
5826
5827 - def setP(self, block, lhaid, value):
5828 if isinstance(value, str):
5829 value = value.lower()
5830 if value == 'default':
5831 default = param_card_mod.ParamCard(self.paths['param_default'])
5832 value = default[block].param_dict[lhaid].value
5833
5834 elif value in ['auto', 'auto@nlo']:
5835 if 'nlo' in value:
5836 value = 'Auto@NLO'
5837 else:
5838 value = 'Auto'
5839 if block != 'decay':
5840 logger.warning('Invalid input: \'Auto\' value only valid for DECAY')
5841 return
5842 elif value.startswith('scan'):
5843 if ':' not in value:
5844 logger.warning('Invalid input: \'scan\' mode requires a \':\' before the definition.')
5845 return
5846 tag = value.split(':')[0]
5847 tag = tag[4:].strip()
5848 if tag and not tag.isdigit():
5849 logger.warning('Invalid input: scan tag need to be integer and not "%s"' % tag)
5850 return
5851
5852
5853 pass
5854 else:
5855 try:
5856 value = float(value)
5857 except ValueError:
5858 logger.warning('Invalid input: \'%s\' not valid intput.'% value)
5859
5860 logger.info('modify param_card information BLOCK %s with id %s set to %s' %\
5861 (block, lhaid, value), '$MG:BOLD')
5862 self.param_card[block].param_dict[lhaid].value = value
5863
5865 """This is run on quitting the class. Apply here all the self-consistency
5866 rule that you want. Do the modification via the set command."""
5867
5868
5869
5870
5871 if isinstance(self.run_card,banner_mod.RunCardLO):
5872
5873 proc_charac = self.mother_interface.proc_characteristics
5874 if proc_charac['grouped_matrix'] and \
5875 abs(self.run_card['lpp1']) == 1 == abs(self.run_card['lpp2']) and \
5876 (self.run_card['nb_proton1'] != self.run_card['nb_proton2'] or
5877 self.run_card['nb_neutron1'] != self.run_card['nb_neutron2'] or
5878 self.run_card['mass_ion1'] != self.run_card['mass_ion2']):
5879 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\".")
5880
5881
5882 for param in self.param_card['decay']:
5883 width = param.value
5884 if width == 0 or isinstance(width,str):
5885 continue
5886 try:
5887 mass = self.param_card['mass'].get(param.lhacode).value
5888 except Exception:
5889 continue
5890 if isinstance(mass,str):
5891 continue
5892
5893 if mass:
5894 to_sleep = True
5895 if abs(width/mass) < self.run_card['small_width_treatment']:
5896 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",
5897 param.lhacode[0], width)
5898 elif abs(width/mass) < 1e-12:
5899 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)
5900 else:
5901 to_sleep = False
5902 if CommonRunCmd.sleep_for_error and to_sleep:
5903 time.sleep(5)
5904 CommonRunCmd.sleep_for_error = False
5905
5906
5907 if 'pythia_card.dat' in self.cards and 'run' in self.allow_arg:
5908 if self.run_card['event_norm'] != 'sum':
5909 logger.info('Pythia6 needs a specific normalisation of the events. We will change it accordingly.', '$MG:BOLD' )
5910 self.do_set('run_card event_norm sum')
5911
5912 elif 'pythia8_card.dat' in self.cards:
5913 if self.run_card['event_norm'] == 'sum':
5914 logger.info('Pythia8 needs a specific normalisation of the events. We will change it accordingly.', '$MG:BOLD' )
5915 self.do_set('run_card event_norm average')
5916
5917 if 'MLM' in proc_charac['limitations']:
5918 if self.run_card['dynamical_scale_choice'] == -1:
5919 raise InvalidCmd("Your model is identified as not fully supported within MG5aMC.\n" +\
5920 "As your process seems to be impacted by the issue,\n"+\
5921 "You can NOT run with CKKW dynamical scale for this model. Please choose another one.")
5922 if self.run_card['ickkw']:
5923 raise InvalidCmd("Your model is identified as not fully supported within MG5aMC.\n" +\
5924 "As your process seems to be impacted by the issue,\n" +\
5925 "You can NOT run with MLM matching/merging. Please check if merging outside MG5aMC are suitable or refrain to use merging with this model")
5926
5927
5928
5929
5930
5931
5932 if isinstance(self.run_card,banner_mod.RunCardNLO):
5933
5934 try:
5935 proc_charac = self.mother_interface.proc_characteristics
5936 except:
5937 proc_charac = None
5938
5939 if proc_charac and 'MLM' in proc_charac['limitations']:
5940 if self.run_card['ickkw']:
5941 raise Exception( "Your model is identified as not fully supported within MG5aMC.\n" +\
5942 "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")
5943
5944 for pdg in set(list(self.run_card['pt_min_pdg'].keys())+list(self.run_card['pt_max_pdg'].keys())+
5945 list(self.run_card['mxx_min_pdg'].keys())):
5946
5947 if int(pdg)<0:
5948 raise Exception("For PDG specific cuts, always use positive PDG codes: the cuts are applied to both particles and anti-particles")
5949 if self.param_card.get_value('mass', int(pdg), default=0) ==0:
5950 raise Exception("For NLO runs, you can use PDG specific cuts only for massive particles: (failed for %s)" % pdg)
5951
5952
5953 if 'reweight' in self.allow_arg and 'run' in self.allow_arg and \
5954 not self.run_card['store_rwgt_info']:
5955
5956 re_pattern = re.compile(r'''^\s*change\s*mode\s* (LO\+NLO|LO|NLO|NLO_tree)\s*(?:#|$)''', re.M+re.I)
5957 text = open(self.paths['reweight']).read()
5958 options = re_pattern.findall(text)
5959 if any(o in ['NLO', 'LO+NLO'] for o in options):
5960 logger.info('NLO reweighting is on ON. Automatically set store_rwgt_info to True', '$MG:BOLD' )
5961 self.do_set('run_card store_rwgt_info True')
5962
5963
5964
5965 if 'run' in self.allow_arg and \
5966 self.run_card['systematics_program'] == 'systematics' and \
5967 not self.run_card['store_rwgt_info']:
5968 logger.warning('To be able to run systematics program, we set store_rwgt_info to True')
5969 self.do_set('run_card store_rwgt_info True')
5970
5971
5972
5973
5974 if self.has_shower and isinstance(self.run_card, banner_mod.RunCardNLO):
5975 modify_extralibs, modify_extrapaths = False,False
5976 extralibs = self.shower_card['extralibs'].split()
5977 extrapaths = self.shower_card['extrapaths'].split()
5978
5979 if self.run_card['parton_shower'] in ['PYTHIA8', 'HERWIGPP', 'HW7']:
5980 if 'stdhep' in self.shower_card['extralibs']:
5981 extralibs.remove('stdhep')
5982 modify_extralibs = True
5983 if 'Fmcfio' in self.shower_card['extralibs']:
5984 extralibs.remove('Fmcfio')
5985 modify_extralibs = True
5986 if self.run_card['parton_shower'] == 'PYTHIA8':
5987
5988 if not self.mother_interface.options['pythia8_path']:
5989 raise self.mother_interface.InvalidCmd('Pythia8 is not correctly specified to MadGraph5_aMC@NLO')
5990 executable = pjoin(self.mother_interface.options['pythia8_path'], 'bin', 'pythia8-config')
5991 if not os.path.exists(executable):
5992 raise self.mother.InvalidCmd('Pythia8 is not correctly specified to MadGraph5_aMC@NLO')
5993
5994
5995 libs , paths = [], []
5996 p = misc.subprocess.Popen([executable, '--libs'], stdout=subprocess.PIPE)
5997 stdout, _ = p. communicate()
5998 libs = [x[2:] for x in stdout.decode().split() if x.startswith('-l') or paths.append(x[2:])]
5999
6000
6001 p = misc.subprocess.Popen([executable, '--config'], stdout=subprocess.PIPE)
6002 stdout, _ = p. communicate()
6003 for lib in ['-ldl','-lstdc++','-lc++']:
6004 if lib in stdout.decode():
6005 libs.append(lib[2:])
6006
6007
6008
6009 supports_HEPMCHACK = '-DHEPMC2HACK' in stdout
6010
6011
6012 for L in paths:
6013 if L not in extrapaths:
6014 modify_extrapaths = True
6015 extrapaths.append(L)
6016 for l in libs:
6017 if l == 'boost_iostreams':
6018
6019 for L in paths + extrapaths:
6020 if misc.glob('*boost_iostreams*', L):
6021 break
6022 else:
6023 continue
6024 if l not in extralibs:
6025 modify_extralibs = True
6026 extralibs.append(l)
6027
6028 if modify_extralibs:
6029 if extralibs:
6030 self.do_set('shower_card extralibs %s ' % ' '.join(extralibs))
6031 else:
6032 self.do_set('shower_card extralibs None ')
6033 if modify_extrapaths:
6034 if extrapaths:
6035 self.do_set('shower_card extrapaths %s ' % ' '.join(extrapaths))
6036 else:
6037 self.do_set('shower_card extrapaths None ')
6038
6039
6040 if self.writting_card:
6041 for key in list(self.modified_card):
6042 self.write_card(key)
6043
6044
6045 - def reask(self, *args, **opt):
6046
6047 cmd.OneLinePathCompletion.reask(self,*args, **opt)
6048 if self.has_mw and not os.path.exists(pjoin(self.me_dir,'Cards','transfer_card.dat')):
6049 logger.warning('No transfer function currently define. Please use the change_tf command to define one.')
6050
6051 fail_due_to_format = 0
6052 - def postcmd(self, stop, line):
6053
6054 if line not in [None, '0', 'done', '']:
6055 ending_question = cmd.OneLinePathCompletion.postcmd(self,stop,line)
6056 else:
6057 ending_question = True
6058
6059 if ending_question:
6060 self.check_card_consistency()
6061 if self.param_consistency:
6062 try:
6063 self.do_update('dependent', timer=20)
6064 except MadGraph5Error as error:
6065 if 'Missing block:' in str(error):
6066 self.fail_due_to_format +=1
6067 if self.fail_due_to_format == 10:
6068 missing, unknow = str(error).split('\n')[-2:]
6069 logger.warning("Invalid param_card:\n%s\n%s\n" % (missing, unknow))
6070 logger.info("Type \"update missing\" to use default value.\n ", '$MG:BOLD')
6071 self.value = False
6072 return self.reask(True)
6073 else:
6074 raise
6075
6076 return ending_question
6077
6078
6079
6080
6081
6083 """ syntax: update dependent: Change the mass/width of particles which are not free parameter for the model.
6084 update missing: add to the current param_card missing blocks/parameters.
6085 update to_slha1: pass SLHA2 card to SLHA1 convention. (beta)
6086 update to_slha2: pass SLHA1 card to SLHA2 convention. (beta)
6087 update to_full [run_card]
6088 update XXX [where XXX correspond to a hidden block of the run_card]
6089 """
6090 args = self.split_arg(line)
6091 if len(args)==0:
6092 logger.warning('miss an argument (dependent or missing). Please retry')
6093 return
6094
6095 if args[0] == 'dependent':
6096 if not self.mother_interface:
6097 logger.warning('Failed to update dependent parameter. This might create trouble for external program (like MadSpin/shower/...)')
6098
6099 pattern_width = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I)
6100 pattern_scan = re.compile(r'''^(decay)?[\s\d]*scan''', re.I+re.M)
6101 param_text= open(self.paths['param']).read()
6102
6103 if pattern_scan.search(param_text):
6104
6105
6106
6107 return
6108 elif pattern_width.search(param_text):
6109 self.do_compute_widths('')
6110 self.param_card = param_card_mod.ParamCard(self.paths['param'])
6111
6112
6113 self.update_dependent(self.mother_interface, self.me_dir, self.param_card,
6114 self.paths['param'], timer)
6115
6116 elif args[0] == 'missing':
6117 self.update_missing()
6118 return
6119
6120 elif args[0] == 'to_slha2':
6121 try:
6122 param_card_mod.convert_to_mg5card(self.paths['param'])
6123 logger.info('card updated')
6124 except Exception as error:
6125 logger.warning('failed to update to slha2 due to %s' % error)
6126 self.param_card = param_card_mod.ParamCard(self.paths['param'])
6127 elif args[0] == 'to_slha1':
6128 try:
6129 param_card_mod.convert_to_slha1(self.paths['param'])
6130 logger.info('card updated')
6131 except Exception as error:
6132 logger.warning('failed to update to slha1 due to %s' % error)
6133 self.param_card = param_card_mod.ParamCard(self.paths['param'])
6134 elif args[0] == 'to_full':
6135 return self.update_to_full(args[1:])
6136 elif args[0] in self.update_block:
6137 self.run_card.display_block.append(args[0].lower())
6138 self.modified_card.add('run')
6139 logger.info('add optional block %s to the run_card', args[0])
6140 else:
6141 self.help_update()
6142 logger.warning('unvalid options for update command. Please retry')
6143
6144
6146 """ trigger via update to_full LINE"""
6147
6148 logger.info("update the run_card by including all the hidden parameter")
6149 self.run_card.write(self.paths['run'], self.paths['run_default'], write_hidden=True)
6150 if 'run' in self.modified_card:
6151 self.modified_card.remove('run')
6152
6154 """proxy on how to write any card"""
6155
6156 if hasattr(self, 'write_card_%s' % name):
6157 getattr(self, 'write_card_%s' % name)()
6158 if name in self.modified_card:
6159 self.modified_card.remove(name)
6160 else:
6161 raise Exception("Need to add the associate writter proxy for %s" % name)
6162
6164 """ write the run_card """
6165 self.run_card.write(self.paths['run'], self.paths['run_default'])
6166
6168 """ write the param_card """
6169
6170 self.param_card.write(self.paths['param'])
6171
6172 @staticmethod
6174 """static method which can also be called from outside the class
6175 usefull in presence of scan.
6176 return if the param_card was updated or not
6177 """
6178
6179 if not param_card:
6180 return False
6181
6182 logger.info('Update the dependent parameter of the param_card.dat')
6183 modify = True
6184 class TimeOutError(Exception):
6185 pass
6186 def handle_alarm(signum, frame):
6187 raise TimeOutError
6188 signal.signal(signal.SIGALRM, handle_alarm)
6189 if timer:
6190 signal.alarm(timer)
6191 log_level=30
6192 else:
6193 log_level=20
6194
6195 try:
6196 model = mecmd.get_model()
6197 signal.alarm(0)
6198 except TimeOutError:
6199 logger.warning('The model takes too long to load so we bypass the updating of dependent parameter.\n'+\
6200 'This might create trouble for external program (like MadSpin/shower/...)\n'+\
6201 'The update can be forced without timer by typing \'update dependent\' at the time of the card edition')
6202 modify =False
6203 except Exception as error:
6204 logger.debug(str(error))
6205 logger.warning('Failed to update dependent parameter. This might create trouble for external program (like MadSpin/shower/...)')
6206 signal.alarm(0)
6207 else:
6208 restrict_card = pjoin(me_dir,'Source','MODEL','param_card_rule.dat')
6209 if not os.path.exists(restrict_card):
6210 restrict_card = None
6211
6212 if model:
6213 modify = param_card.update_dependent(model, restrict_card, log_level)
6214 if modify and path:
6215 param_card.write(path)
6216 else:
6217 logger.warning('missing MG5aMC code. Fail to update dependent parameter. This might create trouble for program like MadSpin/shower/...')
6218
6219 if log_level==20:
6220 logger.info('param_card up to date.')
6221
6222 return modify
6223
6224
6225
6227
6228 def check_block(self, blockname):
6229 add_entry = 0
6230 if blockname.lower() not in self.param_card_default:
6231 logger.info('unknow block %s: block will be ignored', blockname)
6232 return add_entry
6233 block = self.param_card_default[blockname]
6234 for key in block.keys():
6235 if key not in input_in_block:
6236 param = block.get(key)
6237 if blockname != 'decay':
6238 text.append('\t%s\t%s # %s\n' % (' \t'.join([repr(i) for i in param.lhacode]), param.value, param.comment))
6239 else:
6240 text.append('DECAY \t%s\t%s # %s\n' % (' \t'.join([repr(i) for i in param.lhacode]), param.value, param.comment))
6241 add_entry += 1
6242 if add_entry:
6243 text.append('\n')
6244 if add_entry:
6245 logger.info("Adding %s parameter(s) to block %s", add_entry, blockname)
6246 return add_entry
6247
6248
6249 current_block = ''
6250 input_in_block = set()
6251 defined_blocks = set()
6252 decay = set()
6253 text = []
6254 add_entry = 0
6255 for line in open(self.paths['param']):
6256
6257 new_block = re.findall(r'^\s*(block|decay)\s*(\w*)', line, re.I)
6258 if new_block:
6259 new_block = new_block[0]
6260 defined_blocks.add(new_block[1].lower())
6261 if current_block:
6262 add_entry += check_block(self, current_block)
6263
6264 current_block= new_block[1]
6265 input_in_block = set()
6266 if new_block[0].lower() == 'decay':
6267 decay.add((int(new_block[1]),))
6268 current_block = ''
6269 if new_block[1].lower() == 'qnumbers':
6270 current_block = ''
6271
6272 text.append(line)
6273 if not current_block:
6274 continue
6275
6276
6277
6278 line = line.split('#',1)[0]
6279 split = line.split()
6280 if not split:
6281 continue
6282 else:
6283 try:
6284 lhacode = [int(i) for i in split[:-1]]
6285 except:
6286 continue
6287 input_in_block.add(tuple(lhacode))
6288
6289 if current_block:
6290 add_entry += check_block(self, current_block)
6291
6292
6293 for block in self.param_card_default:
6294
6295 if block.startswith(('qnumbers', 'decay')):
6296 continue
6297
6298 if block not in defined_blocks:
6299 nb_entry = len(self.param_card_default[block])
6300 logger.info("Block %s was missing. Adding the %s associated parameter(s)", block,nb_entry)
6301 add_entry += nb_entry
6302 text.append(str(self.param_card_default[block]))
6303
6304
6305 input_in_block = decay
6306 add_entry += check_block(self, 'decay')
6307
6308 if add_entry:
6309 logger.info('write new param_card with %s new parameter(s).', add_entry, '$MG:BOLD')
6310 open(self.paths['param'],'w').write(''.join(text))
6311 self.reload_card(self.paths['param'])
6312 else:
6313 logger.info('No missing parameter detected.', '$MG:BOLD')
6314
6315
6320
6348
6350
6351 line = line.strip()
6352 args = line.split()
6353
6354 if not args:
6355 return line
6356 if not hasattr(self, 'trigger_%s' % args[0]):
6357 return line
6358
6359 triggerfct = getattr(self, 'trigger_%s' % args[0])
6360
6361
6362 outline = triggerfct(' '.join(args[1:]))
6363 if not outline:
6364 return 'repeat'
6365 return outline
6366
6368 """Default action if line is not recognized"""
6369
6370
6371 line = self.trigger(line)
6372
6373
6374 line = line.strip()
6375 args = line.split()
6376 if line == '' and self.default_value is not None:
6377 self.value = self.default_value
6378
6379 elif hasattr(self, 'do_%s' % args[0]):
6380 self.do_set(' '.join(args[1:]))
6381 elif line.strip() != '0' and line.strip() != 'done' and \
6382 str(line) != 'EOF' and line.strip() in self.allow_arg:
6383 self.open_file(line)
6384 self.value = 'repeat'
6385 elif os.path.isfile(line):
6386 self.copy_file(line)
6387 self.value = 'repeat'
6388 elif self.me_dir and os.path.exists(pjoin(self.me_dir, line)):
6389 self.copy_file(pjoin(self.me_dir,line))
6390 self.value = 'repeat'
6391 elif line.strip().startswith(('http:','www', 'https')):
6392 self.value = 'repeat'
6393 import tempfile
6394 fsock, path = tempfile.mkstemp()
6395 try:
6396 text = six.moves.urllib.request.urlopen(line.strip())
6397 url = line.strip()
6398 except Exception:
6399 logger.error('fail to load the file')
6400 else:
6401 for line in text:
6402 os.write(fsock, line)
6403 os.close(fsock)
6404 self.copy_file(path, pathname=url)
6405 os.remove(path)
6406
6407
6408 else:
6409 self.value = line
6410
6411 return line
6412
6413
6415 """edit the madspin_card to define the decay of the associate particle"""
6416 signal.alarm(0)
6417 path = self.paths['madspin']
6418
6419 if 'madspin_card.dat' not in self.cards or not os.path.exists(path):
6420 logger.warning("Command decay not valid. Since MadSpin is not available.")
6421 return
6422
6423 if ">" not in line:
6424 logger.warning("invalid command for decay. Line ignored")
6425 return
6426
6427 if "-add" in line:
6428
6429 particle = line.split('>')[0].strip()
6430 text = open(path).read()
6431 line = line.replace('--add', '').replace('-add','')
6432 logger.info("change madspin_card to add one decay to %s: %s" %(particle, line.strip()), '$MG:BOLD')
6433 if 'launch' in text:
6434 text = text.replace('launch', "\ndecay %s\nlaunch\n" % line,1)
6435 else:
6436 text += '\ndecay %s\n launch \n' % line
6437 else:
6438
6439
6440 particle = line.split('>')[0].strip()
6441 logger.info("change madspin_card to define the decay of %s: %s" %(particle, line.strip()), '$MG:BOLD')
6442 particle = particle.replace('+','\+').replace('-','\-')
6443 decay_pattern = re.compile(r"^\s*decay\s+%s\s*>[\s\w+-~]*?$" % particle, re.I+re.M)
6444 text= open(path).read()
6445 text = decay_pattern.sub('', text)
6446 if 'launch' in text:
6447 text = text.replace('launch', "\ndecay %s\nlaunch\n" % line,1)
6448 else:
6449 text += '\ndecay %s\n launch \n' % line
6450
6451 with open(path,'w') as fsock:
6452 fsock.write(text)
6453 self.reload_card(path)
6454
6455
6456
6458 signal.alarm(0)
6459
6460
6461 if 'param' in self.modified_card:
6462 self.write_card('param')
6463 self.modified_card.discard('param')
6464
6465 path = self.paths['param']
6466 pattern = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I)
6467 text = open(path).read()
6468 pdg_info = pattern.findall(text)
6469 has_nlo = any("@nlo"==nlo.lower() for _, nlo in pdg_info)
6470 pdg = [p for p,_ in pdg_info]
6471
6472
6473 line = '%s %s' % (line, ' '.join(pdg))
6474 if not '--path' in line:
6475 line += ' --path=%s' % path
6476 if has_nlo:
6477 line += ' --nlo'
6478
6479 try:
6480 out = self.mother_interface.do_compute_widths(line)
6481 except InvalidCmd as error:
6482 logger.error("Invalid command: %s " % error)
6483 else:
6484 if hasattr(self, 'run_card'):
6485 for pid, info in out.items():
6486 total = 0
6487 for key, partial in info:
6488 total += partial
6489 mass = self.param_card.get_value('mass', pid)
6490 try:
6491 small_width_treatment = self.run_card['small_width_treatment']
6492 except Exception:
6493 small_width_treatment = 0
6494
6495 if total and total/mass < small_width_treatment:
6496 text = "Particle %s with very small width (%g): Learn about special handling here: https://answers.launchpad.net/mg5amcnlo/+faq/3053"
6497 logger.warning(text,pid,total)
6498 elif total and total/mass < 1e-11:
6499 text = "Particle %s with very small width (%g): Numerical inaccuracies can occur if that particle is in a s-channel"
6500 logger.critical(text,pid,total)
6501
6502
6503 return out
6504
6505
6509
6511 """help for command decay which modifies MadSpin_card"""
6512
6513 signal.alarm(0)
6514 print('--syntax: decay PROC [--add]')
6515 print(' ')
6516 print(' modify the madspin_card to modify the decay of the associate particle.')
6517 print(' and define it to PROC.')
6518 print(' if --add is present, just add a new decay for the associate particle.')
6519
6521 prev_timer = signal.alarm(0)
6522 if prev_timer:
6523 nb_back = len(line)
6524 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
6525 self.stdout.write(line)
6526 self.stdout.flush()
6527 return self.mother_interface.complete_compute_widths(text, line, begidx, endidx,**opts)
6528
6529
6531 """help for add command"""
6532
6533 logger.info('********************* HELP ADD ***************************')
6534 logger.info( '-- syntax: add pythia8_card NAME VALUE')
6535 logger.info( " add a definition of name in the pythia8_card with the given value")
6536 logger.info( " Do not work for the param_card" )
6537 logger.info('')
6538 return self.help_edit(prefix=False)
6539
6541 """help for edit command"""
6542
6543 if prefix: logger.info('********************* HELP ADD|EDIT ***************************')
6544 logger.info( '-- syntax: add filename [OPTION] LINE')
6545 logger.info( '-- syntax: edit filename [OPTION] LINE')
6546 logger.info( ' add the given LINE to the end of the associate file (all file supported).')
6547 logger.info( '')
6548 logger.info( ' OPTION parameter allows to change the position where to write in the file')
6549 logger.info( ' --after_line=banner : write the line at the end of the banner')
6550 logger.info( ' --line_position=X : insert the line before line X (starts at 0)')
6551 logger.info( ' --line_position=afterlast : insert the line after the latest inserted/modified line.')
6552 logger.info( ' --after_line="<regular-expression>" write the line after the first line matching the regular expression')
6553 logger.info( ' --before_line="<regular-expression>" write the line before the first line matching the regular expression')
6554 logger.info( ' --replace_line="<regular-expression>" replace the line matching the regular expression')
6555 logger.info( ' --clean remove all previously existing line in the file')
6556 logger.info( ' --comment_line="<regular-expression>" comment all lines matching the regular expression')
6557 logger.info('')
6558 logger.info(' Note: all regular-expression will be prefixed by ^\s*')
6559 logger.info('')
6560 logger.info( ' example: edit reweight --after_line="change mode\b" change model heft')
6561 logger.info( ' edit madspin --after_line="banner" change model XXXX')
6562 logger.info('********************* HELP ADD|EDIT ***************************')
6563
6564
6565 - def complete_add(self, text, line, begidx, endidx, formatting=True):
6566 """ auto-completion for add command"""
6567
6568 prev_timer = signal.alarm(0)
6569 if prev_timer:
6570 nb_back = len(line)
6571 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
6572 self.stdout.write(line)
6573 self.stdout.flush()
6574
6575 split = line[:begidx].split()
6576 if len(split)==1:
6577 possibilities = {}
6578 cards = [c.rsplit('.',1)[0] for c in self.cards]
6579 possibilities['category of parameter (optional)'] = \
6580 self.list_completion(text, cards)
6581 elif len(split) == 2:
6582 possibilities = {}
6583 options = ['--line_position=','--line_position=afterlast','--after_line=banner', '--after_line="','--before_line="']
6584 possibilities['category of parameter (optional)'] = \
6585 self.list_completion(text, options, line)
6586 else:
6587 return
6588 return self.deal_multiple_categories(possibilities, formatting)
6589
6591 """ syntax: add filename NAME VALUE
6592 syntax: add filename LINE"""
6593
6594 args = self.split_arg(line)
6595 if len(args) == 3 and args[0] in ['pythia8_card', 'pythia8_card.dat'] and self.has_PY8:
6596 name= args[1]
6597 value = args[2]
6598 self.PY8Card.userSet(name, value)
6599 self.PY8Card.write(pjoin(self.me_dir,'Cards','pythia8_card.dat'),
6600 pjoin(self.me_dir,'Cards','pythia8_card_default.dat'),
6601 print_only_visible=True)
6602 logger.info("add in the pythia8_card the parameter \"%s\" with value \"%s\"" % (name, value), '$MG:BOLD')
6603 elif len(args) > 0:
6604 if args[0] in self.cards:
6605 card = args[0]
6606 elif "%s.dat" % args[0] in self.cards:
6607 card = "%s.dat" % args[0]
6608 elif "%s_card.dat" % args[0] in self.cards:
6609 card = "%s_card.dat" % args[0]
6610 elif self.has_ml and args[0].lower() == "madloop":
6611 card = "MadLoopParams.dat"
6612 else:
6613 logger.error("unknow card %s. Please retry." % args[0])
6614 return
6615
6616 if card in self.modified_card:
6617 self.write_card(card)
6618 self.modified_card.discard(card)
6619
6620 if card in self.paths:
6621 path = self.paths[card]
6622 elif os.path.exists(card):
6623 path = card
6624 elif os.path.exists(pjoin(self.me_dir,'Cards',card)):
6625 path = pjoin(self.me_dir,'Cards',card)
6626 else:
6627 raise Exception('unknow path')
6628
6629
6630 if args[1] == '--clean':
6631 ff = open(path,'w')
6632 ff.write("# %s \n" % card)
6633 ff.write("%s \n" % line.split(None,2)[2])
6634 ff.close()
6635 logger.info("writing the line in %s (empty file) the line: \"%s\"" %(card, line.split(None,2)[2] ),'$MG:BOLD')
6636 elif args[1].startswith('--line_position=afterlast'):
6637
6638 text = open(path).read()
6639 split = text.split('\n')
6640 if self.last_editline_pos > 0:
6641 pos = self.last_editline_pos +1
6642 newline = line.split(None,2)[2]
6643 split.insert(pos, newline)
6644 ff = open(path,'w')
6645 ff.write('\n'.join(split))
6646 logger.info("writting at line %d of the file %s the line: \"%s\"" %(pos, card, line.split(None,2)[2] ),'$MG:BOLD')
6647 self.last_editline_pos = pos
6648 elif args[1].startswith('--line_position='):
6649
6650 text = open(path).read()
6651 split = text.split('\n')
6652 pos = int(args[1].split('=',1)[1])
6653 newline = line.split(None,2)[2]
6654 split.insert(pos, newline)
6655 ff = open(path,'w')
6656 ff.write('\n'.join(split))
6657 logger.info("writting at line %d of the file %s the line: \"%s\"" %(pos, card, line.split(None,2)[2] ),'$MG:BOLD')
6658 self.last_editline_pos = pos
6659
6660 elif args[1].startswith(('--after_line=banner','--after_line=\'banner\'','--after_line=\"banner\"')):
6661
6662 text = open(path).read()
6663 split = text.split('\n')
6664 for posline,l in enumerate(split):
6665 if not l.startswith('#'):
6666 break
6667 split.insert(posline, line.split(None,2)[2])
6668 ff = open(path,'w')
6669 ff.write('\n'.join(split))
6670 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline, card, line.split(None,2)[2] ),'$MG:BOLD')
6671 self.last_editline_pos = posline
6672
6673 elif args[1].startswith('--replace_line='):
6674
6675
6676 text = open(path).read()
6677 split = text.split('\n')
6678 search_pattern=r'''replace_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6679 pattern = '^\s*' + re.search(search_pattern, line).group()[14:-1]
6680 for posline,l in enumerate(split):
6681 if re.search(pattern, l):
6682 break
6683 else:
6684 new_line = re.split(search_pattern,line)[-1].strip()
6685 if new_line.startswith(('--before_line=','--after_line')):
6686 return self.do_add('%s %s' % (args[0], new_line))
6687 raise Exception('invalid regular expression: not found in file')
6688
6689
6690 new_line = re.split(search_pattern,line)[-1].strip()
6691 if new_line.startswith(('--before_line=','--after_line')):
6692 search_pattern=r'''(?:before|after)_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6693 new_line = re.split(search_pattern,new_line)[-1]
6694
6695 old_line = split[posline]
6696 split[posline] = new_line
6697 ff = open(path,'w')
6698 ff.write('\n'.join(split))
6699 logger.info("Replacing the line \"%s\" [line %d of %s] by \"%s\"" %
6700 (old_line, posline, card, new_line ),'$MG:BOLD')
6701 self.last_editline_pos = posline
6702
6703 elif args[1].startswith('--comment_line='):
6704
6705
6706 text = open(path).read()
6707 split = text.split('\n')
6708 search_pattern=r'''comment_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6709 pattern = '^\s*' + re.search(search_pattern, line).group()[14:-1]
6710 nb_mod = 0
6711 for posline,l in enumerate(split):
6712 if re.search(pattern, l):
6713 split[posline] = '#%s' % l
6714 nb_mod +=1
6715 logger.info("Commenting line \"%s\" [line %d of %s]" %
6716 (l, posline, card ),'$MG:BOLD')
6717
6718 if not nb_mod:
6719 logger.warning('no line commented (no line matching)')
6720 ff = open(path,'w')
6721 ff.write('\n'.join(split))
6722
6723 self.last_editline_pos = posline
6724
6725
6726 elif args[1].startswith('--before_line='):
6727
6728 text = open(path).read()
6729 split = text.split('\n')
6730 search_pattern=r'''before_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6731 pattern = '^\s*' + re.search(search_pattern, line).group()[13:-1]
6732 for posline,l in enumerate(split):
6733 if re.search(pattern, l):
6734 break
6735 else:
6736 raise Exception('invalid regular expression: not found in file')
6737 split.insert(posline, re.split(search_pattern,line)[-1])
6738 ff = open(path,'w')
6739 ff.write('\n'.join(split))
6740 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline, card, line.split(None,2)[2] ),'$MG:BOLD')
6741 self.last_editline_pos = posline
6742
6743 elif args[1].startswith('--after_line='):
6744
6745 text = open(path).read()
6746 split = text.split('\n')
6747 search_pattern = r'''after_line=(?P<quote>["'])(?:(?=(\\?))\2.)*?\1'''
6748 pattern = '^\s*' + re.search(search_pattern, line).group()[12:-1]
6749 for posline,l in enumerate(split):
6750 if re.search(pattern, l):
6751 break
6752 else:
6753 posline=len(split)
6754 split.insert(posline+1, re.split(search_pattern,line)[-1])
6755 ff = open(path,'w')
6756 ff.write('\n'.join(split))
6757
6758 logger.info("writting at line %d of the file %s the line: \"%s\"" %(posline+1, card, line.split(None,2)[2] ),'$MG:BOLD')
6759 self.last_editline_pos = posline+1
6760
6761 else:
6762 ff = open(path,'a')
6763 ff.write("%s \n" % line.split(None,1)[1])
6764 ff.close()
6765 logger.info("adding at the end of the file %s the line: \"%s\"" %(card, line.split(None,1)[1] ),'$MG:BOLD')
6766 self.last_editline_pos = -1
6767
6768 self.reload_card(path)
6769
6770 do_edit = do_add
6771 complete_edit = complete_add
6772
6774 """Help associated to the asperge command"""
6775 signal.alarm(0)
6776
6777 print('-- syntax: asperge [options]')
6778 print(' Call ASperGe to diagonalize all mass matrices in the model.')
6779 print(' This works only if the ASperGE module is part of the UFO model (a subdirectory).')
6780 print(' If you specify some names after the command (i.e. asperge m1 m2) then ASperGe will only')
6781 print(' diagonalize the associate mass matrices (here m1 and m2).')
6782
6784 prev_timer = signal.alarm(0)
6785 if prev_timer:
6786 nb_back = len(line)
6787 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
6788 self.stdout.write(line)
6789 self.stdout.flush()
6790 blockname = list(self.pname2block.keys())
6791
6792 wrong = ['decay', 'mass', 'sminput']
6793 valid = [k for k in blockname if 'mix' in k]
6794 potential = [k for k in blockname if k not in valid+wrong]
6795 output = {'Mixing matrices': self.list_completion(text, valid, line),
6796 'Other potential valid input': self.list_completion(text, potential, line)}
6797
6798 return self.deal_multiple_categories(output, formatting)
6799
6800
6802 """Running ASperGe"""
6803 signal.alarm(0)
6804
6805
6806 if 'param' in self.modified_card:
6807 self.write_card('param')
6808 self.modified_card.discard('param')
6809
6810
6811 path = pjoin(self.me_dir,'bin','internal','ufomodel','ASperGE')
6812 if not os.path.exists(path):
6813 logger.error('ASperge has not been detected in the current model, therefore it will not be run.')
6814 return
6815 elif not os.path.exists(pjoin(path,'ASperGe')):
6816 logger.info('ASperGe has been detected but is not compiled. Running the compilation now.')
6817 try:
6818 misc.compile(cwd=path,shell=True)
6819 except MadGraph5Error as error:
6820 logger.error('''ASperGe failed to compile. Note that gsl is needed
6821 for this compilation to go trough. More information on how to install this package on
6822 http://www.gnu.org/software/gsl/
6823 Full compilation log is available at %s''' % pjoin(self.me_dir, 'ASperge_compilation.log'))
6824 open(pjoin(self.me_dir, 'ASperge_compilation.log'),'w').write(str(error))
6825 return
6826
6827 opts = line.split()
6828 card = self.paths['param']
6829 logger.info('running ASperGE')
6830 returncode = misc.call([pjoin(path,'ASperGe'), card, '%s.new' % card] + opts)
6831 if returncode:
6832 logger.error('ASperGE fails with status %s' % returncode)
6833 else:
6834 logger.info('AsPerGe creates the file succesfully')
6835 files.mv(card, '%s.beforeasperge' % card)
6836 files.mv('%s.new' % card, card)
6837
6838
6839
6841 """detect the type of the file and overwritte the current file"""
6842
6843 if not pathname:
6844 pathname = path
6845
6846 if path.endswith('.lhco'):
6847
6848
6849 self.do_set('mw_run inputfile %s' % os.path.relpath(path, self.mother_interface.me_dir))
6850 return
6851 elif path.endswith('.lhco.gz'):
6852
6853
6854 self.do_set('mw_run inputfile %s' % os.path.relpath(path, self.mother_interface.me_dir))
6855 return
6856 else:
6857 card_name = self.detect_card_type(path)
6858
6859 if card_name == 'unknown':
6860 logger.warning('Fail to determine the type of the file. Not copied')
6861 if card_name != 'banner':
6862 logger.info('copy %s as %s' % (pathname, card_name))
6863 files.cp(path, self.paths[card_name.rsplit('_',1)[0]])
6864 self.reload_card(self.paths[card_name.rsplit('_',1)[0]])
6865 elif card_name == 'banner':
6866 banner_mod.split_banner(path, self.mother_interface.me_dir, proc_card=False)
6867 logger.info('Splitting the banner in it\'s component')
6868 if not self.mode == 'auto':
6869 self.mother_interface.keep_cards(self.cards)
6870 for card_name in self.cards:
6871 self.reload_card(pjoin(self.me_dir, 'Cards', card_name))
6872
6877
6879 """open the file"""
6880
6881 try:
6882 me_dir = self.mother_interface.me_dir
6883 except:
6884 me_dir = None
6885
6886 if answer.isdigit():
6887 if answer == '9':
6888 answer = 'plot'
6889 else:
6890 answer = self.cards[int(answer)-self.integer_bias]
6891
6892 if 'madweight' in answer:
6893 answer = answer.replace('madweight', 'MadWeight')
6894 elif 'MadLoopParams' in answer:
6895 answer = self.paths['ML']
6896 elif 'pythia8_card' in answer:
6897 answer = self.paths['pythia8']
6898 if os.path.exists(answer):
6899 path = answer
6900 else:
6901 if not '.dat' in answer and not '.lhco' in answer:
6902 if answer != 'trigger':
6903 path = self.paths[answer]
6904 else:
6905 path = self.paths['delphes']
6906 elif not '.lhco' in answer:
6907 if '_' in answer:
6908 path = self.paths['_'.join(answer.split('_')[:-1])]
6909 else:
6910 path = pjoin(me_dir, 'Cards', answer)
6911 else:
6912 path = pjoin(me_dir, self.mw_card['mw_run']['inputfile'])
6913 if not os.path.exists(path):
6914 logger.info('Path in MW_card not existing')
6915 path = pjoin(me_dir, 'Events', answer)
6916
6917 path = path.replace('_card_card','_card')
6918
6919 if answer in self.modified_card:
6920 self.write_card(answer)
6921 elif os.path.basename(answer.replace('_card.dat','')) in self.modified_card:
6922 self.write_card(os.path.basename(answer.replace('_card.dat','')))
6923
6924 try:
6925 self.mother_interface.exec_cmd('open %s' % path)
6926 except InvalidCmd as error:
6927 if str(error) != 'No default path for this file':
6928 raise
6929 if answer == 'transfer_card.dat':
6930 logger.warning('You have to specify a transfer function first!')
6931 elif answer == 'input.lhco':
6932 path = pjoin(me_dir,'Events', 'input.lhco')
6933 ff = open(path,'w')
6934 ff.write('''No LHCO information imported at current time.
6935 To import a lhco file: Close this file and type the path of your file.
6936 You can also copy/paste, your event file here.''')
6937 ff.close()
6938 self.open_file(path)
6939 else:
6940 raise
6941 self.reload_card(path)
6942
6944 """reload object to have it in sync"""
6945
6946 if path == self.paths['param']:
6947 try:
6948 self.param_card = param_card_mod.ParamCard(path)
6949 except (param_card_mod.InvalidParamCard, ValueError) as e:
6950 logger.error('Current param_card is not valid. We are going to use the default one.')
6951 logger.error('problem detected: %s' % e)
6952 logger.error('Please re-open the file and fix the problem.')
6953 logger.warning('using the \'set\' command without opening the file will discard all your manual change')
6954 elif path == self.paths['run']:
6955 self.run_card = banner_mod.RunCard(path)
6956 elif path == self.paths['shower']:
6957 self.shower_card = shower_card_mod.ShowerCard(path)
6958 elif path == self.paths['ML']:
6959 self.MLcard = banner_mod.MadLoopParam(path)
6960 elif path == self.paths['pythia8']:
6961
6962
6963 if not self.PY8Card:
6964 self.PY8Card = self.PY8Card_class(self.paths['pythia8_default'])
6965
6966 self.PY8Card.read(self.paths['pythia8'], setter='user')
6967 self.py8_vars = [k.lower() for k in self.PY8Card.keys()]
6968 elif path == self.paths['MadWeight']:
6969 try:
6970 import madgraph.madweight.Cards as mwcards
6971 except:
6972 import internal.madweight.Cards as mwcards
6973 self.mw_card = mwcards.Card(path)
6974 else:
6975 logger.debug('not keep in sync: %s', path)
6976 return path
6977
6978
6979
6980 -def scanparamcardhandling(input_path=lambda obj: pjoin(obj.me_dir, 'Cards', 'param_card.dat'),
6981 store_for_scan=lambda obj: obj.store_scan_result,
6982 get_run_name=lambda obj: obj.run_name,
6983 set_run_name=lambda obj: obj.set_run_name,
6984 result_path=lambda obj: pjoin(obj.me_dir, 'Events', 'scan_%s.txt' ),
6985 ignoreerror=ZeroResult,
6986 iteratorclass=param_card_mod.ParamCardIterator,
6987 summaryorder=lambda obj: lambda:None,
6988 check_card=lambda obj: CommonRunCmd.static_check_param_card,
6989 ):
6990 """ This is a decorator for customizing/using scan over the param_card (or technically other)
6991 This should be use like this:
6992
6993 @scanparamcardhandling(arguments)
6994 def run_launch(self, *args, **opts)
6995
6996 possible arguments are listed above and should be function who takes a single
6997 argument the instance of intereset. those return
6998 input_path -> function that return the path of the card to read
6999 store_for_scan -> function that return a dict of entry to keep in memory
7000 get_run_name -> function that return the string with the current run_name
7001 set_run_name -> function that return the function that allow the set the next run_name
7002 result_path -> function that return the path of the summary result to write
7003 ignoreerror -> one class of error which are not for the error
7004 IteratorClass -> class to use for the iterator
7005 summaryorder -> function that return the function to call to get the order
7006
7007 advanced:
7008 check_card -> function that return the function to read the card and init stuff (compute auto-width/init self.iterator/...)
7009 This function should define the self.param_card_iterator if a scan exists
7010 and the one calling the auto-width functionalities/...
7011
7012 All the function are taking a single argument (an instance of the class on which the decorator is used)
7013 and they can either return themself a function or a string.
7014
7015 Note:
7016 1. the link to auto-width is not fully trivial due to the model handling
7017 a. If you inherit from CommonRunCmd (or if the self.mother is). Then
7018 everything should be automatic.
7019
7020 b. If you do not you can/should create the funtion self.get_model().
7021 Which returns the appropriate MG model (like the one from import_ufo.import_model)
7022
7023 c. You can also have full control by defining your own do_compute_widths(self, line)
7024 functions.
7025 """
7026 class restore_iterator(object):
7027 """ensure that the original card is always restore even for crash"""
7028 def __init__(self, iterator, path):
7029 self.iterator = iterator
7030 self.path = path
7031
7032 def __enter__(self):
7033 return self.iterator
7034
7035 def __exit__(self, ctype, value, traceback ):
7036 self.iterator.write(self.path)
7037
7038 def decorator(original_fct):
7039 def new_fct(obj, *args, **opts):
7040
7041 if isinstance(input_path, str):
7042 card_path = input_path
7043 else:
7044 card_path = input_path(obj)
7045
7046
7047
7048
7049
7050
7051
7052
7053 check_card(obj)(card_path, obj, iterator_class=iteratorclass)
7054
7055 param_card_iterator = None
7056 if obj.param_card_iterator:
7057 param_card_iterator = obj.param_card_iterator
7058 obj.param_card_iterator = []
7059
7060 if not param_card_iterator:
7061
7062 original_fct(obj, *args, **opts)
7063 return
7064
7065 with restore_iterator(param_card_iterator, card_path):
7066
7067
7068
7069 if not hasattr(obj, 'allow_notification_center'):
7070 obj.allow_notification_center = False
7071 with misc.TMP_variable(obj, 'allow_notification_center', False):
7072 orig_name = get_run_name(obj)
7073 next_name = orig_name
7074
7075 set_run_name(obj)(next_name)
7076
7077 original_fct(obj, *args, **opts)
7078 param_card_iterator.store_entry(next_name, store_for_scan(obj)(), param_card_path=card_path)
7079 for card in param_card_iterator:
7080 card.write(card_path)
7081
7082 check_card(obj)(card_path, obj, dependent=True)
7083 next_name = param_card_iterator.get_next_name(next_name)
7084 set_run_name(obj)(next_name)
7085 try:
7086 original_fct(obj, *args, **opts)
7087 except ignoreerror as error:
7088 param_card_iterator.store_entry(next_name, {'exception': error})
7089 else:
7090 param_card_iterator.store_entry(next_name, store_for_scan(obj)(), param_card_path=card_path)
7091
7092
7093 name = misc.get_scan_name(orig_name, next_name)
7094 path = result_path(obj) % name
7095 logger.info("write scan results in %s" % path ,'$MG:BOLD')
7096 order = summaryorder(obj)()
7097 param_card_iterator.write_summary(path, order=order)
7098 return new_fct
7099 return decorator
7100