1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """Definitions of the objects needed for the implementation of MadFKS"""
17
18 import madgraph.core.base_objects as MG
19 import madgraph.core.helas_objects as helas_objects
20 import madgraph.core.diagram_generation as diagram_generation
21 import madgraph.core.color_amp as color_amp
22 import madgraph.core.color_algebra as color_algebra
23 import madgraph.loop.loop_diagram_generation as loop_diagram_generation
24 import madgraph.fks.fks_common as fks_common
25 import copy
26 import logging
27 import array
28 import madgraph.various.misc as misc
29 from madgraph import InvalidCmd
30
31 logger = logging.getLogger('madgraph.fks_base')
32
33
35
36
37
38
39
40
42 """A multi process class that contains informations on the born processes
43 and the reals.
44 """
45
55
57 """Return particle property names as a nicely sorted list."""
58 keys = super(FKSMultiProcess, self).get_sorted_keys()
59 keys += ['born_processes', 'real_amplitudes', 'real_pdgs', 'has_isr',
60 'has_fsr', 'spltting_types', 'OLP', 'ncores_for_proc_gen']
61 return keys
62
63 - def filter(self, name, value):
64 """Filter for valid leg property values."""
65
66 if name == 'born_processes':
67 if not isinstance(value, FKSProcessList):
68 raise self.PhysicsObjectError, \
69 "%s is not a valid list for born_processes " % str(value)
70
71 if name == 'real_amplitudes':
72 if not isinstance(value, diagram_generation.AmplitudeList):
73 raise self.PhysicsObjectError, \
74 "%s is not a valid list for real_amplitudes " % str(value)
75
76 if name == 'real_pdgs':
77 if not isinstance(value, list):
78 raise self.PhysicsObjectError, \
79 "%s is not a valid list for real_amplitudes " % str(value)
80
81 if name == 'OLP':
82 if not isinstance(value,str):
83 raise self.PhysicsObjectError, \
84 "%s is not a valid string for OLP " % str(value)
85
86 if name == 'ncores_for_proc_gen':
87 if not isinstance(value,int):
88 raise self.PhysicsObjectError, \
89 "%s is not a valid value for ncores_for_proc_gen " % str(value)
90
91 return super(FKSMultiProcess,self).filter(name, value)
92
93
95 """check that there is no duplicate FKS ij configuration"""
96 ijconfs_dict = {}
97 for born in self['born_processes']:
98
99 for real in copy.copy(born.real_amps):
100 pdgs = ' '.join([ '%d' % pdg for pdg in real.pdgs])
101 for info in copy.copy(real.fks_infos):
102 ij = [info['i'], info['j']]
103 try:
104 if ij in ijconfs_dict[pdgs]:
105 logger.debug('Duplicate FKS configuration found for %s : ij = %s' %
106 (real.process.nice_string(), str(ij)))
107
108 born.real_amps[born.real_amps.index(real)].fks_infos.remove(info)
109 else:
110 ijconfs_dict[pdgs].append(ij)
111 except KeyError:
112 ijconfs_dict[pdgs] = [ij]
113
114
115 if not born.real_amps[born.real_amps.index(real)].fks_infos:
116 logger.debug('Removing real %s from born %s' % \
117 (real.process.nice_string(), born.born_amp['process'].nice_string()))
118 born.real_amps.remove(real)
119
120
121 - def __init__(self, procdef=None, options={}):
122 """Initializes the original multiprocess, then generates the amps for the
123 borns, then generate the born processes and the reals.
124 Real amplitudes are stored in real_amplitudes according on the pdgs of their
125 legs (stored in pdgs, so that they need to be generated only once and then reicycled
126 """
127
128 loggers_off = [logging.getLogger('madgraph.diagram_generation'),
129 logging.getLogger('madgraph.loop_diagram_generation')]
130 old_levels = [logg.level for logg in loggers_off]
131 for logg in loggers_off:
132 logg.setLevel(logging.WARNING)
133
134 self['real_amplitudes'] = diagram_generation.AmplitudeList()
135 self['pdgs'] = []
136
137
138 olp='MadLoop'
139 if 'OLP' in options.keys():
140 olp = options['OLP']
141 del options['OLP']
142
143 self['init_lep_split']=False
144 if 'init_lep_split' in options.keys():
145 self['init_lep_split']=options['init_lep_split']
146 del options['init_lep_split']
147
148 ncores_for_proc_gen = 0
149
150
151
152
153 if 'ncores_for_proc_gen' in options.keys():
154 ncores_for_proc_gen = options['ncores_for_proc_gen']
155 del options['ncores_for_proc_gen']
156
157 try:
158
159 super(FKSMultiProcess, self).__init__(procdef, **options)
160
161 except diagram_generation.NoDiagramException as error:
162
163 raise NoBornException, "Born diagrams could not be generated for the "+\
164 self['process_definitions'][0].nice_string().replace('Process',\
165 'process')+". Notice that aMC@NLO does not handle loop-induced"+\
166 " processes yet, but you can still use MadLoop if you want to "+\
167 "only generate them."+\
168 " For this, use the 'virt=' mode, without multiparticle labels."
169
170 self['OLP'] = olp
171 self['ncores_for_proc_gen'] = ncores_for_proc_gen
172
173
174
175
176
177 perturbation = []
178 for procdef in self['process_definitions']:
179 soft_particles = []
180
181 if [ i['state'] for i in procdef['legs']].count(False) == 1:
182 continue
183 for pert in procdef['perturbation_couplings']:
184 if pert not in perturbation:
185 perturbation.append(pert)
186 soft_particles.extend(\
187 fks_common.find_pert_particles_interactions(\
188 procdef['model'], pert)['soft_particles'])
189 soft_particles_string = ', '.join( \
190 [procdef['model'].get('particle_dict')[id][\
191 {True:'name', False:'antiname'}[id >0] ] \
192 for id in sorted(soft_particles, reverse=True)])
193 for leg in procdef['legs']:
194 if any([id in soft_particles for id in leg['ids']]) \
195 and sorted(leg['ids']) != soft_particles:
196 logger.warning('Use of multiparticles is non-trivial for NLO '+ \
197 'process generation and depends on the orders included, '+ \
198 'the process considered, as well as the PDF set chosen. '+ \
199 'See appendix D of arXiv:1804.10017 [hep-ph] for some '+ \
200 'guidance.')
201 break
202
203 amps = self.get('amplitudes')
204
205
206
207 if self['process_definitions']:
208 leptons = self['process_definitions'][0]['model'].get_lepton_pdgs()
209 else:
210 leptons = []
211
212
213 for i, amp in enumerate(amps):
214
215 if not self['init_lep_split'] and \
216 all([l['id'] in leptons \
217 for l in [ll for ll in amp.get('process').get('legs') if not ll['state']]]):
218 logger.info(('Discarding process%s.\n If you want to include it, set the \n' + \
219 ' \'include_lepton_initiated_processes\' option to True') % \
220 amp.get('process').nice_string().replace('Process', ''))
221 continue
222
223 logger.info("Generating FKS-subtracted matrix elements for born process%s (%d / %d)" \
224 % (amp['process'].nice_string(print_weighted=False).replace('Process', ''),
225 i + 1, len(amps)))
226
227 born = FKSProcess(amp, ncores_for_proc_gen = self['ncores_for_proc_gen'], \
228 init_lep_split=self['init_lep_split'])
229 self['born_processes'].append(born)
230
231 born.generate_reals(self['pdgs'], self['real_amplitudes'], combine = False)
232
233
234 born.combine_real_amplitudes()
235
236 if not self['ncores_for_proc_gen']:
237
238
239 born_pdg_list = [[l['id'] for l in born.get_leglist()] \
240 for born in self['born_processes'] ]
241
242 for born in self['born_processes']:
243 for real in born.real_amps:
244 real.find_fks_j_from_i(born_pdg_list)
245 if amps:
246 if self['process_definitions'][0].get('NLO_mode') == 'all':
247 self.generate_virtuals()
248
249 elif not self['process_definitions'][0].get('NLO_mode') in ['all', 'real','LOonly']:
250 raise fks_common.FKSProcessError(\
251 "Not a valid NLO_mode for a FKSMultiProcess: %s" % \
252 self['process_definitions'][0].get('NLO_mode'))
253
254
255 n_diag_born = sum([len(amp.get('diagrams'))
256 for amp in self.get_born_amplitudes()])
257 n_diag_real = sum([len(amp.get('diagrams'))
258 for amp in self.get_real_amplitudes()])
259 n_diag_virt = sum([len(amp.get('loop_diagrams'))
260 for amp in self.get_virt_amplitudes()])
261
262 if n_diag_virt == 0 and n_diag_real ==0 and \
263 not self['process_definitions'][0].get('NLO_mode') == 'LOonly':
264 raise fks_common.FKSProcessError(
265 'This process does not have any correction up to NLO in %s'\
266 %','.join(perturbation))
267
268 logger.info(('Generated %d subprocesses with %d real emission diagrams, ' + \
269 '%d born diagrams and %d virtual diagrams') % \
270 (len(self['born_processes']), n_diag_real, n_diag_born, n_diag_virt))
271
272 for i, logg in enumerate(loggers_off):
273 logg.setLevel(old_levels[i])
274
275 self['has_isr'] = any([proc.isr for proc in self['born_processes']])
276 self['has_fsr'] = any([proc.fsr for proc in self['born_processes']])
277
278 - def add(self, other):
279 """combines self and other, extending the lists of born/real amplitudes"""
280 self['process_definitions'].extend(other['process_definitions'])
281 self['amplitudes'].extend(other['amplitudes'])
282 self['born_processes'].extend(other['born_processes'])
283 self['real_amplitudes'].extend(other['real_amplitudes'])
284 self['pdgs'].extend(other['pdgs'])
285 self['has_isr'] = self['has_isr'] or other['has_isr']
286 self['has_fsr'] = self['has_fsr'] or other['has_fsr']
287 self['OLP'] = other['OLP']
288 self['ncores_for_proc_gen'] = other['ncores_for_proc_gen']
289
290
292 """return an amplitudelist with the born amplitudes"""
293 return diagram_generation.AmplitudeList([
294 born.born_amp for \
295 born in self['born_processes']])
296
297
299 """return an amplitudelist with the virt amplitudes"""
300 return diagram_generation.AmplitudeList([born.virt_amp \
301 for born in self['born_processes'] if born.virt_amp])
302
303
305 """return an amplitudelist with the real amplitudes"""
306 return self.get('real_amplitudes')
307
308
310 """For each process among the born_processes, creates the corresponding
311 virtual amplitude"""
312
313
314
315
316 if self['OLP']!='MadLoop':
317 logger.info("The loop matrix elements will be generated by "+\
318 '%s at the output stage only.'%self['OLP'])
319 return
320
321
322
323
324
325
326
327
328
329
330 for i, born in enumerate(self['born_processes']):
331 myproc = copy.copy(born.born_amp['process'])
332
333
334 myproc['perturbation_couplings'] = myproc['model']['coupling_orders']
335
336
337 myproc['legs'] = fks_common.to_legs(copy.copy(myproc['legs']))
338 logger.info('Generating virtual matrix element with MadLoop for process%s (%d / %d)' \
339 % (myproc.nice_string(print_weighted = False).replace(\
340 'Process', ''),
341 i + 1, len(self['born_processes'])))
342 try:
343 myamp = loop_diagram_generation.LoopAmplitude(myproc)
344 born.virt_amp = myamp
345 except InvalidCmd:
346 pass
347
348
350 """Contains information about a real process:
351 -- fks_infos (list containing the possible fks configs for a given process
352 -- amplitude
353 -- is_to_integrate
354 """
355
356 - def __init__(self, born_proc, leglist, ij, ij_id, born_pdgs, splitting_type,
357 perturbed_orders = ['QCD']):
358 """Initializes the real process based on born_proc and leglist.
359 Stores the fks informations into the list of dictionaries fks_infos
360 """
361
362 assert type(splitting_type) == list and not type(splitting_type) == str
363 self.fks_infos = []
364 for leg in leglist:
365 if leg.get('fks') == 'i':
366 i_fks = leg.get('number')
367
368 need_color_links = leg.get('massless') \
369 and leg.get('spin') == 3 \
370 and leg.get('self_antipart') \
371 and leg.get('color') == 8
372 need_charge_links = leg.get('massless') \
373 and leg.get('spin') == 3 \
374 and leg.get('self_antipart') \
375 and leg.get('color') == 1
376 if leg.get('fks') == 'j':
377 j_fks = leg.get('number')
378 self.fks_infos.append({'i': i_fks,
379 'j': j_fks,
380 'ij': ij,
381 'ij_id': ij_id,
382 'underlying_born': born_pdgs,
383 'splitting_type': splitting_type,
384 'need_color_links': need_color_links,
385 'need_charge_links': need_charge_links,
386 'extra_cnt_index': -1})
387
388 self.process = copy.copy(born_proc)
389 self.process['perturbation_couplings'] = \
390 copy.copy(born_proc['perturbation_couplings'])
391 for o in splitting_type:
392 if o not in self.process['perturbation_couplings']:
393 self.process['perturbation_couplings'].append(o)
394
395 self.process['orders'] = copy.copy(born_proc['orders'])
396 self.process['orders'] = {}
397
398 legs = [(leg.get('id'), leg) for leg in leglist]
399 self.pdgs = array.array('i',[s[0] for s in legs])
400 self.colors = [leg['color'] for leg in leglist]
401 if not self.process['perturbation_couplings'] == ['QCD']:
402 self.charges = [leg['charge'] for leg in leglist]
403 else:
404 self.charges = [0.] * len(leglist)
405 self.perturbation = 'QCD'
406 self.process.set('legs', MG.LegList(leglist))
407 self.process.set('legs_with_decays', MG.LegList())
408 self.amplitude = diagram_generation.Amplitude()
409 self.is_to_integrate = True
410 self.is_nbody_only = False
411 self.fks_j_from_i = {}
412 self.missing_borns = []
413
414
416 """generates the real emission amplitude starting from self.process"""
417 self.amplitude = diagram_generation.Amplitude(self.process)
418 return self.amplitude
419
420
422 """Returns a dictionary with the entries i : [j_from_i], if the born pdgs are in
423 born_pdg_list"""
424 fks_j_from_i = {}
425 for i in self.process.get('legs'):
426 fks_j_from_i[i.get('number')] = []
427 if i.get('state'):
428 for j in [l for l in self.process.get('legs') if \
429 l.get('number') != i.get('number')]:
430 for pert_order in self.process.get('perturbation_couplings'):
431 ijlist = fks_common.combine_ij(i, j, self.process.get('model'), {},\
432 pert=pert_order)
433 for ij in ijlist:
434 born_leglist = fks_common.to_fks_legs(
435 copy.deepcopy(self.process.get('legs')),
436 self.process.get('model'))
437 born_leglist.remove(i)
438 born_leglist.remove(j)
439 born_leglist.insert(ij.get('number') - 1, ij)
440 born_leglist.sort(pert = self.perturbation)
441 if [leg['id'] for leg in born_leglist] in born_pdg_list \
442 and not j.get('number') in fks_j_from_i[i.get('number')]:
443 fks_j_from_i[i.get('number')].append(\
444 j.get('number'))
445
446 self.fks_j_from_i = fks_j_from_i
447 return fks_j_from_i
448
449
451 """Returns leg corresponding to i fks.
452 An error is raised if the fks_infos list has more than one entry"""
453 if len(self.fks_infos) > 1:
454 raise fks_common.FKSProcessError(\
455 'get_leg_i should only be called before combining processes')
456 return self.process.get('legs')[self.fks_infos[0]['i'] - 1]
457
459 """Returns leg corresponding to j fks.
460 An error is raised if the fks_infos list has more than one entry"""
461 if len(self.fks_infos) > 1:
462 raise fks_common.FKSProcessError(\
463 'get_leg_j should only be called before combining processes')
464 return self.process.get('legs')[self.fks_infos[0]['j'] - 1]
465
466
468 """Class to handle lists of FKSProcesses."""
469
471 """Test if object obj is a valid FKSProcess for the list."""
472 return isinstance(obj, FKSProcess)
473
474
476 """The class for a FKS process. Starts from the born process and finds
477 all the possible splittings."""
478
479
480
481
483 """return the list of color representations
484 for each leg in born_amp"""
485 return [leg.get('color') for \
486 leg in self.born_amp['process']['legs']]
487
488
490 """return the list of charges
491 for each leg in born_amp"""
492 return [leg.get('charge') for \
493 leg in self.born_amp['process']['legs']]
494
495
497 """return the number of born legs"""
498 return len(self.born_amp['process']['legs'])
499
500
502 """Return the nice string for the born process.
503 """
504 return self.born_amp['process'].nice_string()
505
506
508 """return the list of the pdg codes
509 of each leg in born_amp"""
510 return [leg.get('id') for \
511 leg in self.born_amp['process']['legs']]
512
513
515 """return the leg list
516 for the born amp"""
517 return fks_common.to_fks_legs( \
518 self.born_amp['process']['legs'], \
519 self.born_amp['process']['model'])
520
521
522
523
524 - def __init__(self, start_proc = None, remove_reals = True, ncores_for_proc_gen=0, init_lep_split = False):
525 """initialization: starts either from an amplitude or a process,
526 then init the needed variables.
527 remove_borns tells if the borns not needed for integration will be removed
528 from the born list (mainly used for testing)
529 ncores_for_proc_gen has the following meaning
530 0 : do things the old way
531 > 0 use ncores_for_proc_gen
532 -1 : use all cores
533 """
534
535 self.reals = []
536 self.myorders = {}
537 self.real_amps = []
538 self.remove_reals = remove_reals
539 self.init_lep_split = init_lep_split
540 self.nincoming = 0
541 self.virt_amp = None
542 self.perturbation = 'QCD'
543 self.born_amp = diagram_generation.Amplitude()
544 self.extra_cnt_amp_list = diagram_generation.AmplitudeList()
545 self.ncores_for_proc_gen = ncores_for_proc_gen
546
547 if not remove_reals in [True, False]:
548 raise fks_common.FKSProcessError(\
549 'Not valid type for remove_reals in FKSProcess')
550
551 if start_proc:
552
553 if isinstance(start_proc, MG.Process):
554 pertur = start_proc['perturbation_couplings']
555 if pertur:
556 self.perturbation = sorted(pertur)[0]
557 self.born_amp = diagram_generation.Amplitude(\
558 copy.copy(fks_common.sort_proc(\
559 start_proc, pert = self.perturbation)))
560
561 elif isinstance(start_proc, diagram_generation.Amplitude):
562 pertur = start_proc.get('process')['perturbation_couplings']
563 self.born_amp = diagram_generation.Amplitude(\
564 copy.copy(fks_common.sort_proc(\
565 start_proc['process'],
566 pert = self.perturbation)))
567 else:
568 raise fks_common.FKSProcessError(\
569 'Not valid start_proc in FKSProcess')
570 self.born_amp['process'].set('legs_with_decays', MG.LegList())
571
572
573
574
575
576 self.isr = False
577 self.fsr = False
578
579 self.nincoming = len([l for l in self.born_amp['process']['legs'] \
580 if not l['state']])
581
582 self.ndirs = 0
583
584
585
586 if self.born_amp['process']['NLO_mode'] != 'LOonly':
587 self.find_reals()
588
589
591 """generates the real amplitudes for all the real emission processes, using pdgs and real_amps
592 to avoid multiple generation of the same amplitude.
593 Amplitude without diagrams are discarded at this stage"""
594
595 no_diags_amps = []
596 for amp in self.real_amps:
597 try:
598 amp.amplitude = real_amp_list[pdg_list.index(amp.pdgs)]
599 except ValueError:
600 amplitude = amp.generate_real_amplitude()
601 if amplitude['diagrams']:
602 pdg_list.append(amp.pdgs)
603 real_amp_list.append(amplitude)
604 else:
605 no_diags_amps.append(amp)
606
607 for amp in no_diags_amps:
608 self.real_amps.remove(amp)
609
610
611
613 """combines real emission processes if the pdgs are the same, combining the lists
614 of fks_infos"""
615 pdgs = []
616 real_amps = []
617 old_real_amps = copy.copy(self.real_amps)
618 for amp in old_real_amps:
619 try:
620 real_amps[pdgs.index(amp.pdgs)].fks_infos.extend(amp.fks_infos)
621 except ValueError:
622 real_amps.append(amp)
623 pdgs.append(amp.pdgs)
624
625 self.real_amps = real_amps
626
627
629 """For all the possible splittings, creates an FKSRealProcess.
630 It removes double counted configorations from the ones to integrates and
631 sets the one which includes the bosn (is_nbody_only).
632 if combine is true, FKS_real_processes having the same pdgs (i.e. real amplitude)
633 are combined together
634 """
635
636 born_proc = copy.copy(self.born_amp['process'])
637 born_pdgs = self.get_pdg_codes()
638 leglist = self.get_leglist()
639 extra_cnt_pdgs = []
640 for i, real_list in enumerate(self.reals):
641
642
643
644 ij_id = leglist[i].get('id')
645 ij = leglist[i].get('number')
646 for real_dict in real_list:
647 nmom = 0
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663 cnt_amp = diagram_generation.Amplitude()
664 born_cnt_amp = diagram_generation.Amplitude()
665 mom_cnt = 0
666 cnt_ord = None
667
668
669 born_proc_coll_sing = copy.copy(born_proc)
670 born_proc_coll_sing['squared_orders'] = copy.copy(born_proc['squared_orders'])
671 if born_proc_coll_sing['squared_orders'][real_dict['perturbation'][0]] < 2:
672 has_coll_sing_born = False
673 else:
674 born_proc_coll_sing['squared_orders'][real_dict['perturbation'][0]] += -2
675 has_coll_sing_born = bool(diagram_generation.Amplitude(born_proc_coll_sing)['diagrams'])
676
677
678 allmothers = []
679 for order, mothers in real_dict['extra_mothers'].items():
680 allmothers += mothers
681 if mothers:
682 cnt_ord = order
683
684 if len(allmothers) > 1:
685 raise fks_common.FKSProcessError(\
686 'Error, more than one extra mother has been found: %d', len(allmothers))
687
688
689 has_coll_sing_cnt = False
690 if allmothers:
691 mom_cnt = allmothers[0]
692
693
694
695
696
697 cnt_process = copy.copy(born_proc)
698 cnt_process['legs'] = copy.deepcopy(born_proc['legs'])
699 cnt_process['legs'][i]['id'] = mom_cnt
700 cnt_process['legs'] = fks_common.to_fks_legs(
701 cnt_process['legs'], cnt_process['model'])
702 cnt_process['squared_orders'] = \
703 copy.copy(born_proc['squared_orders'])
704
705
706
707
708
709
710 cnt_process_for_amp = copy.copy(cnt_process)
711 cnt_process_for_amp['squared_orders'] = copy.copy(cnt_process['squared_orders'])
712 cnt_amp = diagram_generation.Amplitude(cnt_process_for_amp)
713
714 if bool(cnt_amp['diagrams']) and \
715 cnt_process['squared_orders'][cnt_ord] >= 2:
716
717
718
719 cnt_process['squared_orders'][cnt_ord] += -2
720 born_cnt_amp = diagram_generation.Amplitude(cnt_process)
721 has_coll_sing_cnt = bool(born_cnt_amp['diagrams'])
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743 if mom_cnt and mom_cnt < ij_id:
744 if ((not has_coll_sing_born and not has_coll_sing_cnt) or \
745 (has_coll_sing_born and has_coll_sing_cnt)):
746 continue
747
748
749 if has_coll_sing_cnt and not has_coll_sing_born:
750 continue
751
752
753 ij = leglist[i].get('number')
754 self.real_amps.append(FKSRealProcess( \
755 born_proc, real_dict['leglist'], ij, ij_id, \
756 [born_pdgs],
757 real_dict['perturbation'], \
758 perturbed_orders = born_proc['perturbation_couplings']))
759
760
761 if has_coll_sing_cnt:
762
763
764 try:
765 indx = extra_cnt_pdgs.index([l['id'] for l in cnt_process['legs']])
766 except ValueError:
767 extra_cnt_pdgs.append([l['id'] for l in cnt_process['legs']])
768 assert cnt_amp != None
769 self.extra_cnt_amp_list.append(cnt_amp)
770 indx = len(self.extra_cnt_amp_list) - 1
771
772
773 self.real_amps[-1].fks_infos[-1]['extra_cnt_index'] = indx
774 self.real_amps[-1].fks_infos[-1]['underlying_born'].append(\
775 [l['id'] for l in cnt_process['legs']])
776 self.real_amps[-1].fks_infos[-1]['splitting_type'].append(cnt_ord)
777
778 self.find_reals_to_integrate()
779 if combine:
780 self.combine_real_amplitudes()
781 if not self.ncores_for_proc_gen:
782 self.generate_real_amplitudes(pdg_list, real_amp_list)
783 self.link_born_reals()
784
785
787 """create the rb_links in the real matrix element to find
788 which configuration in the real correspond to which in the born
789 """
790
791 logger.debug('link_born_real: skipping')
792 return
793
794 for real in self.real_amps:
795 for info in real.fks_infos:
796 info['rb_links'] = fks_common.link_rb_configs(\
797 self.born_amp, real.amplitude,
798 info['i'], info['j'], info['ij'])
799
800
802 """finds the FKS real configurations for a given process.
803 self.reals[i] is a list of dictionaries corresponding to the real
804 emissions obtained splitting leg i.
805 The dictionaries contain the leglist, the type (order) of the
806 splitting and extra born particles which can give the same
807 splitting (e.g. gluon/photon -> qqbar).
808 If pert orders is empty, all the orders of the model will be used
809 """
810
811 model = self.born_amp['process']['model']
812 if not pert_orders:
813 pert_orders = model['coupling_orders']
814
815 leglist = self.get_leglist()
816 if range(len(leglist)) != [l['number']-1 for l in leglist]:
817 raise fks_common.FKSProcessError('Disordered numbers of leglist')
818
819 if [ i['state'] for i in leglist].count(False) == 1:
820 decay_process=True
821 else:
822 decay_process=False
823
824
825 ninit_lep = [l['id'] in model.get_lepton_pdgs() and not l['state'] for l in leglist].count(True)
826
827 for i in leglist:
828 i_i = i['number'] - 1
829 self.reals.append([])
830
831
832
833
834 if len(leglist) == 3 and not decay_process and i['state']:
835 continue
836 for pert_order in pert_orders:
837
838 if decay_process and not i['state']:
839 splittings=[]
840
841
842 elif not self.init_lep_split and ninit_lep >= 1 and \
843 (i['state'] or i['id'] not in model.get_lepton_pdgs()):
844 splittings=[]
845 else:
846 splittings = fks_common.find_splittings( \
847 i, model, {}, pert_order, \
848 include_init_leptons=self.init_lep_split)
849 for split in splittings:
850
851 extra_mothers = {}
852 for pert in pert_orders:
853 extra_mothers[pert] = fks_common.find_mothers(split[0], split[1], model, pert=pert,
854 mom_mass=model.get('particle_dict')[i['id']]['mass'].lower())
855
856
857 if i['state']:
858 extra_mothers[pert_order].remove(i['id'])
859 else:
860 extra_mothers[pert_order].remove(model.get('particle_dict')[i['id']].get_anti_pdg_code())
861
862 self.reals[i_i].append({
863 'leglist': fks_common.insert_legs(leglist, i, split ,pert=pert_order),
864 'perturbation': [pert_order],
865 'extra_mothers': extra_mothers})
866
867
869 """Finds double countings in the real emission configurations, sets the
870 is_to_integrate variable and if "self.remove_reals" is True removes the
871 not needed ones from the born list.
872 """
873
874 ninit = len(self.real_amps)
875 remove = self.remove_reals
876
877 for m in range(ninit):
878 for n in range(m + 1, ninit):
879 real_m = self.real_amps[m]
880 real_n = self.real_amps[n]
881 if len(real_m.fks_infos) > 1 or len(real_m.fks_infos) > 1:
882 raise fks_common.FKSProcessError(\
883 'find_reals_to_integrate should only be called before combining processes')
884
885 i_m = real_m.fks_infos[0]['i']
886 j_m = real_m.fks_infos[0]['j']
887 i_n = real_n.fks_infos[-1]['i']
888 j_n = real_n.fks_infos[0]['j']
889 ij_id_m = real_m.fks_infos[0]['ij_id']
890 ij_id_n = real_n.fks_infos[0]['ij_id']
891 if j_m > self.nincoming and j_n > self.nincoming:
892
893 if (ij_id_m != ij_id_n):
894 continue
895 if (real_m.get_leg_i()['id'] == real_n.get_leg_i()['id'] \
896 and \
897 real_m.get_leg_j()['id'] == real_n.get_leg_j()['id']) \
898 or \
899 (real_m.get_leg_i()['id'] == real_n.get_leg_j()['id'] \
900 and \
901 real_m.get_leg_j()['id'] == real_n.get_leg_i()['id']):
902 if i_m > i_n:
903 if real_m.get_leg_i()['id'] == -real_m.get_leg_j()['id']:
904 self.real_amps[m].is_to_integrate = False
905 else:
906 self.real_amps[n].is_to_integrate = False
907 elif i_m == i_n and j_m > j_n:
908 if real_m.get_leg_i()['id'] == -real_m.get_leg_j()['id']:
909 self.real_amps[m].is_to_integrate = False
910 else:
911 self.real_amps[n].is_to_integrate = False
912
913 elif i_m == i_n and j_m == j_n and \
914 not real_m.get_leg_j()['self_antipart'] and \
915 not real_m.get_leg_i()['self_antipart']:
916 if real_m.fks_infos[0]['ij'] > real_n.fks_infos[0]['ij']:
917 real_m.is_to_integrate = False
918 else:
919 real_n.is_to_integrate = False
920 else:
921 if real_m.get_leg_i()['id'] == -real_m.get_leg_j()['id']:
922 self.real_amps[n].is_to_integrate = False
923 else:
924 self.real_amps[m].is_to_integrate = False
925
926 elif j_m <= self.nincoming and j_n == j_m:
927 if real_m.get_leg_i()['id'] == real_n.get_leg_i()['id'] and \
928 real_m.get_leg_j()['id'] == real_n.get_leg_j()['id']:
929 if i_m > i_n:
930 self.real_amps[n].is_to_integrate = False
931 else:
932 self.real_amps[m].is_to_integrate = False
933 if remove:
934 newreal_amps = []
935 for real in self.real_amps:
936 if real.is_to_integrate:
937 newreal_amps.append(real)
938 self.real_amps = newreal_amps
939