1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """ How to import a UFO model to the MG5 format """
16
17
18 import fractions
19 import logging
20 import os
21 import re
22 import sys
23 import time
24
25
26 from madgraph import MadGraph5Error, MG5DIR, ReadWrite
27 import madgraph.core.base_objects as base_objects
28 import madgraph.loop.loop_base_objects as loop_base_objects
29 import madgraph.core.color_algebra as color
30 import madgraph.iolibs.files as files
31 import madgraph.iolibs.save_load_object as save_load_object
32 from madgraph.core.color_algebra import *
33 import madgraph.various.misc as misc
34
35
36 import aloha
37 import aloha.create_aloha as create_aloha
38 import aloha.aloha_fct as aloha_fct
39
40 import models as ufomodels
41 import models.model_reader as model_reader
42 logger = logging.getLogger('madgraph.model')
43 logger_mod = logging.getLogger('madgraph.model')
44
45 root_path = os.path.dirname(os.path.realpath( __file__ ))
46 sys.path.append(root_path)
47
48 sys.path.append(os.path.join(root_path, os.path.pardir, 'Template', 'bin', 'internal'))
49 import check_param_card
50
51 pjoin = os.path.join
52 logger = logging.getLogger("madgraph.model")
53
54
56 """ a error class for wrong import of UFO model"""
57
59 """ a class for invalid Model """
60
62 """ find the path to a model """
63
64
65 if model_name.startswith('./') and os.path.isdir(model_name):
66 model_path = model_name
67 elif os.path.isdir(os.path.join(MG5DIR, 'models', model_name)):
68 model_path = os.path.join(MG5DIR, 'models', model_name)
69 elif os.path.isdir(model_name):
70 model_path = model_name
71 else:
72 raise UFOImportError("Path %s is not a valid pathname" % model_name)
73
74 return model_path
75
76 -def import_model(model_name, decay=False, restrict=True, prefix='mdl_'):
77 """ a practical and efficient way to import a model"""
78
79
80 try:
81 model_path = find_ufo_path(model_name)
82 except UFOImportError:
83 if '-' not in model_name:
84 raise
85 split = model_name.split('-')
86 model_name = '-'.join([text for text in split[:-1]])
87 model_path = find_ufo_path(model_name)
88 restrict_name = split[-1]
89
90 restrict_file = os.path.join(model_path, 'restrict_%s.dat'% restrict_name)
91
92
93 if split[-1] == 'full':
94 restrict_file = None
95 else:
96
97 restrict_name = ""
98 if restrict and os.path.exists(os.path.join(model_path,'restrict_default.dat')):
99 restrict_file = os.path.join(model_path,'restrict_default.dat')
100 else:
101 restrict_file = None
102
103 if isinstance(restrict, str):
104 if os.path.exists(os.path.join(model_path, restrict)):
105 restrict_file = os.path.join(model_path, restrict)
106 elif os.path.exists(restrict):
107 restrict_file = restrict
108 else:
109 raise Exception, "%s is not a valid path for restrict file" % restrict
110
111
112 model = import_full_model(model_path, decay, prefix)
113
114 if os.path.exists(pjoin(model_path, "README")):
115 logger.info("Please read carefully the README of the model file for instructions/restrictions of the model.",'$MG:color:BLACK')
116
117 if restrict_name:
118 model["name"] += '-' + restrict_name
119
120
121 if restrict_file:
122 try:
123 logger.info('Restrict model %s with file %s .' % (model_name, os.path.relpath(restrict_file)))
124 except OSError:
125
126 logger.info('Restrict model %s with file %s .' % (model_name, restrict_file))
127
128 if logger_mod.getEffectiveLevel() > 10:
129 logger.info('Run \"set stdout_level DEBUG\" before import for more information.')
130
131 model = RestrictModel(model)
132
133 if model_name == 'mssm' or os.path.basename(model_name) == 'mssm':
134 keep_external=True
135 else:
136 keep_external=False
137 model.restrict_model(restrict_file, rm_parameter=not decay,
138 keep_external=keep_external)
139 model.path = model_path
140
141 return model
142
143
144 _import_once = []
146 """ a practical and efficient way to import one of those models
147 (no restriction file use)"""
148
149 assert model_path == find_ufo_path(model_path)
150
151 if prefix is True:
152 prefix='mdl_'
153
154
155 files_list_prov = ['couplings.py','lorentz.py','parameters.py',
156 'particles.py', 'vertices.py', 'function_library.py',
157 'propagators.py' ]
158
159 if decay:
160 files_list_prov.append('decays.py')
161
162 files_list = []
163 for filename in files_list_prov:
164 filepath = os.path.join(model_path, filename)
165 if not os.path.isfile(filepath):
166 if filename not in ['propagators.py', 'decays.py']:
167 raise UFOImportError, "%s directory is not a valid UFO model: \n %s is missing" % \
168 (model_path, filename)
169 files_list.append(filepath)
170
171
172 if aloha.unitary_gauge:
173 pickle_name = 'model.pkl'
174 else:
175 pickle_name = 'model_Feynman.pkl'
176 if decay:
177 pickle_name = 'dec_%s' % pickle_name
178
179 allow_reload = False
180 if files.is_uptodate(os.path.join(model_path, pickle_name), files_list):
181 allow_reload = True
182 try:
183 model = save_load_object.load_from_file( \
184 os.path.join(model_path, pickle_name))
185 except Exception, error:
186 logger.info('failed to load model from pickle file. Try importing UFO from File')
187 else:
188
189 if model.has_key('version_tag') and not model.get('version_tag') is None and \
190 model.get('version_tag').startswith(os.path.realpath(model_path)) and \
191 model.get('version_tag').endswith('##' + str(misc.get_pkg_info())):
192
193 for key in model.get('parameters'):
194 for param in model['parameters'][key]:
195 value = param.name.lower()
196 if value in ['as','mu_r', 'zero','aewm1']:
197 continue
198 if prefix:
199 if value.startswith(prefix):
200 _import_once.append((model_path, aloha.unitary_gauge, prefix, decay))
201 return model
202 else:
203 logger.info('reload from .py file')
204 break
205 else:
206 if value.startswith('mdl_'):
207 logger.info('reload from .py file')
208 break
209 else:
210 _import_once.append((model_path, aloha.unitary_gauge, prefix, decay))
211 return model
212 else:
213 continue
214 break
215 else:
216 logger.info('reload from .py file')
217
218 if (model_path, aloha.unitary_gauge, prefix, decay) in _import_once and not allow_reload:
219 raise MadGraph5Error, 'This model %s is modified on disk. To reload it you need to quit/relaunch MG5_aMC ' % model_path
220
221
222 ufo_model = ufomodels.load_model(model_path, decay)
223 ufo2mg5_converter = UFOMG5Converter(ufo_model)
224 model = ufo2mg5_converter.load_model()
225 if model_path[-1] == '/': model_path = model_path[:-1]
226 model.set('name', os.path.split(model_path)[-1])
227
228
229 parameters, couplings = OrganizeModelExpression(ufo_model).main(\
230 additional_couplings =(ufo2mg5_converter.wavefunction_CT_couplings if ufo2mg5_converter.perturbation_couplings else []))
231
232 model.set('parameters', parameters)
233 model.set('couplings', couplings)
234 model.set('functions', ufo_model.all_functions)
235
236
237
238
239 if decay and hasattr(ufo_model, 'all_decays') and ufo_model.all_decays:
240 start = time.time()
241 for ufo_part in ufo_model.all_particles:
242 name = ufo_part.name
243 if not model['case_sensitive']:
244 name = name.lower()
245 p = model['particles'].find_name(name)
246 if hasattr(ufo_part, 'partial_widths'):
247 p.partial_widths = ufo_part.partial_widths
248 elif p and not hasattr(p, 'partial_widths'):
249 p.partial_widths = {}
250
251 logger.debug("load width takes %s", time.time()-start)
252
253 if prefix:
254 start = time.time()
255 model.change_parameter_name_with_prefix()
256 logger.debug("model prefixing takes %s", time.time()-start)
257
258 path = os.path.dirname(os.path.realpath(model_path))
259 path = os.path.join(path, model.get('name'))
260 model.set('version_tag', os.path.realpath(path) +'##'+ str(misc.get_pkg_info()))
261
262
263 if ReadWrite:
264 save_load_object.save_to_file(os.path.join(model_path, pickle_name),
265 model, log=False)
266
267
268
269
270
271
272 return model
273
275 """Convert a UFO model to the MG5 format"""
276
278 """ initialize empty list for particles/interactions """
279
280 self.particles = base_objects.ParticleList()
281 self.interactions = base_objects.InteractionList()
282 self.wavefunction_CT_couplings = []
283
284
285
286
287 self.perturbation_couplings = {}
288 try:
289 for order in model.all_orders:
290 if(order.perturbative_expansion>0):
291 self.perturbation_couplings[order.name]=order.perturbative_expansion
292 except AttributeError,error:
293 pass
294
295 if self.perturbation_couplings!={}:
296 self.model = loop_base_objects.LoopModel({'perturbation_couplings':\
297 self.perturbation_couplings.keys()})
298 else:
299 self.model = base_objects.Model()
300 self.model.set('particles', self.particles)
301 self.model.set('interactions', self.interactions)
302 self.conservecharge = set(['charge'])
303
304 self.ufomodel = model
305 self.checked_lor = set()
306
307 if auto:
308 self.load_model()
309
311 """load the different of the model first particles then interactions"""
312
313
314
315 def_name = []
316 for param in self.ufomodel.all_parameters:
317 if param.nature == "external":
318 if len(param.lhablock.split())>1:
319 raise InvalidModel, '''LHABlock should be single word which is not the case for
320 \'%s\' parameter with lhablock \'%s\' ''' % (param.name, param.lhablock)
321 if param.name in def_name:
322 raise InvalidModel, "name %s define multiple time. Please correct the UFO model!" \
323 % (param.name)
324 else:
325 def_name.append(param.name)
326
327
328 if hasattr(self.ufomodel, 'gauge'):
329 self.model.set('gauge', self.ufomodel.gauge)
330 logger.info('load particles')
331
332
333 if len(set([p.name for p in self.ufomodel.all_particles] + \
334 [p.antiname for p in self.ufomodel.all_particles])) == \
335 len(set([p.name.lower() for p in self.ufomodel.all_particles] + \
336 [p.antiname.lower() for p in self.ufomodel.all_particles])):
337 self.model['case_sensitive'] = False
338
339
340
341 self.detect_incoming_fermion()
342
343 for particle_info in self.ufomodel.all_particles:
344 self.add_particle(particle_info)
345
346
347 color_info = self.find_color_anti_color_rep()
348
349
350 self.model.set('lorentz', self.ufomodel.all_lorentz)
351
352 logger.info('load vertices')
353 for interaction_info in self.ufomodel.all_vertices:
354 self.add_interaction(interaction_info, color_info)
355
356 if self.perturbation_couplings:
357 try:
358 self.ufomodel.add_NLO()
359 except Exception, error:
360 pass
361 for interaction_info in self.ufomodel.all_CTvertices:
362 self.add_CTinteraction(interaction_info, color_info)
363
364 self.model.set('conserved_charge', self.conservecharge)
365
366
367
368
369 all_orders = []
370 try:
371 all_orders = self.ufomodel.all_orders
372 except AttributeError:
373 if self.perturbation_couplings:
374 raise MadGraph5Error, "The loop model MG5 attemps to import does not specify the attribute 'all_order'."
375 else:
376 pass
377
378 hierarchy={}
379 try:
380 for order in all_orders:
381 hierarchy[order.name]=order.hierarchy
382 except AttributeError:
383 if self.perturbation_couplings:
384 raise MadGraph5Error, 'The loop model MG5 attemps to import does not specify an order hierarchy.'
385 else:
386 pass
387 else:
388 self.model.set('order_hierarchy', hierarchy)
389
390
391 expansion_order={}
392
393 coupling_order_counterterms={}
394 try:
395 for order in all_orders:
396 expansion_order[order.name]=order.expansion_order
397 coupling_order_counterterms[order.name]=order.expansion_order
398 except AttributeError:
399 if self.perturbation_couplings:
400 raise MadGraph5Error, 'The loop model MG5 attemps to import does not specify an expansion_order for all coupling orders.'
401 else:
402 pass
403 else:
404 self.model.set('expansion_order', expansion_order)
405 self.model.set('expansion_order', expansion_order)
406
407
408 del self.checked_lor
409
410 return self.model
411
412
413 - def add_particle(self, particle_info):
414 """ convert and add a particle in the particle list """
415
416 loop_particles = [[[]]]
417 counterterms = {}
418
419
420
421 pdg = particle_info.pdg_code
422 if pdg in self.incoming or (pdg not in self.outcoming and pdg <0):
423 return
424
425
426 if not self.perturbation_couplings and particle_info.spin < 0:
427 return
428
429 if (aloha.unitary_gauge and 0 in self.model['gauge']) \
430 or (1 not in self.model['gauge']):
431
432
433 if hasattr(particle_info, 'GoldstoneBoson') and particle_info.GoldstoneBoson:
434 return
435 elif hasattr(particle_info, 'goldstone') and particle_info.goldstone:
436 return
437
438 particle = base_objects.Particle()
439
440 nb_property = 0
441
442 for key,value in particle_info.__dict__.items():
443
444 if key in base_objects.Particle.sorted_keys and not key=='counterterm':
445 nb_property +=1
446 if key in ['name', 'antiname']:
447 if not self.model['case_sensitive']:
448 particle.set(key, value.lower())
449 else:
450 particle.set(key, value)
451 elif key == 'charge':
452 particle.set(key, float(value))
453 elif key in ['mass','width']:
454 particle.set(key, str(value))
455 elif key == 'spin':
456
457
458 particle.set(key,abs(value))
459 if value<0:
460 particle.set('ghost',True)
461 elif key == 'propagator':
462 if value:
463 if aloha.unitary_gauge:
464 particle.set(key, str(value[0]))
465 else:
466 particle.set(key, str(value[1]))
467 else:
468 particle.set(key, '')
469 else:
470 particle.set(key, value)
471 elif key == 'loop_particles':
472 loop_particles = value
473 elif key == 'counterterm':
474 counterterms = value
475 elif key.lower() not in ('ghostnumber','selfconjugate','goldstone',
476 'goldstoneboson','partial_widths'):
477
478 self.conservecharge.add(key)
479 particle.set(key,value, force=True)
480
481 if not hasattr(particle_info, 'propagator'):
482 nb_property += 1
483 if particle.get('spin') >= 3:
484 if particle.get('mass').lower() == 'zero':
485 particle.set('propagator', 0)
486 elif particle.get('spin') == 3 and not aloha.unitary_gauge:
487 particle.set('propagator', 0)
488
489 assert(13 == nb_property)
490
491
492 if particle_info.name == particle_info.antiname:
493 particle.set('self_antipart', True)
494
495
496
497 if not self.perturbation_couplings or counterterms=={}:
498 self.particles.append(particle)
499 return
500
501
502
503
504
505
506 particle_counterterms = {}
507 for key, counterterm in counterterms.items():
508
509 if len([1 for k in key[:-1] if k==1])==1 and \
510 not any(k>1 for k in key[:-1]):
511 newParticleCountertermKey=[None,\
512
513
514
515
516
517 tuple([tuple(loop_parts) for\
518 loop_parts in loop_particles[key[-1]]])]
519 for i, order in enumerate(self.ufomodel.all_orders[:-1]):
520 if key[i]==1:
521 newParticleCountertermKey[0]=order.name
522 newCouplingName='UVWfct_'+particle_info.name+'_'+str(key[-1])
523 particle_counterterms[tuple(newParticleCountertermKey)]=\
524 dict([(key,newCouplingName+('' if key==0 else '_'+str(-key)+'eps'))\
525 for key in counterterm])
526
527
528 self.ufomodel.object_library.Coupling(\
529 name = newCouplingName,
530 value = counterterm,
531 order = {newParticleCountertermKey[0]:2})
532 self.wavefunction_CT_couplings.append(self.ufomodel.all_couplings.pop())
533
534 particle.set('counterterm',particle_counterterms)
535 self.particles.append(particle)
536 return
537
539 """ Split this interaction in order to call add_interaction for
540 interactions for each element of the loop_particles list. Also it
541 is necessary to unfold here the contributions to the different laurent
542 expansion orders of the couplings."""
543
544
545 interaction_info=copy.copy(interaction)
546
547 intType=''
548 if interaction_info.type not in ['UV','UVloop','UVtree','UVmass','R2']:
549 raise MadGraph5Error, 'MG5 only supports the following types of'+\
550 ' vertices, R2, UV and UVmass. %s is not in this list.'%interaction_info.type
551 else:
552 intType=interaction_info.type
553
554 if interaction_info.type=='UV':
555 if len(interaction_info.particles)==2 and interaction_info.\
556 particles[0].name==interaction_info.particles[1].name:
557 intType='UVmass'
558 else:
559 intType='UVloop'
560
561
562
563
564
565
566
567
568
569
570
571 new_couplings=[[{} for j in range(0,3)] for i in \
572 range(0,max(1,len(interaction_info.loop_particles)))]
573
574
575 for key, coupling in interaction_info.couplings.items():
576 for poleOrder in range(0,3):
577 if coupling.pole(poleOrder)!='ZERO':
578 newCoupling=copy.copy(coupling)
579 if poleOrder!=0:
580 newCoupling.name=newCoupling.name+"_"+str(poleOrder)+"eps"
581 newCoupling.value=coupling.pole(poleOrder)
582 new_couplings[key[2]][poleOrder][(key[0],key[1])] = newCoupling
583
584
585 for i, all_couplings in enumerate(new_couplings):
586 loop_particles=[[]]
587 if len(interaction_info.loop_particles)>0:
588 loop_particles=[[part.pdg_code for part in loop_parts] \
589 for loop_parts in interaction_info.loop_particles[i]]
590 for poleOrder in range(0,3):
591 if all_couplings[poleOrder]!={}:
592 interaction_info.couplings=all_couplings[poleOrder]
593 self.add_interaction(interaction_info, color_info,\
594 (intType if poleOrder==0 else (intType+str(poleOrder)+\
595 'eps')),loop_particles)
596
597
599 """find which color are in the 3/3bar states"""
600
601
602
603
604 if not output:
605 output = {}
606
607 for interaction_info in self.ufomodel.all_vertices:
608 if len(interaction_info.particles) != 3:
609 continue
610 colors = [abs(p.color) for p in interaction_info.particles]
611 if colors[:2] == [3,3]:
612 if 'T(3,2,1)' in interaction_info.color:
613 color, anticolor, other = interaction_info.particles
614 elif 'T(3,1,2)' in interaction_info.color:
615 anticolor, color, _ = interaction_info.particles
616 elif 'Identity(1,2)' in interaction_info.color or \
617 'Identity(2,1)' in interaction_info.color:
618 first, second, _ = interaction_info.particles
619 if first.pdg_code in output:
620 if output[first.pdg_code] == 3:
621 color, anticolor = first, second
622 else:
623 color, anticolor = second, first
624 elif second.pdg_code in output:
625 if output[second.pdg_code] == 3:
626 color, anticolor = second, first
627 else:
628 color, anticolor = first, second
629 else:
630 continue
631 else:
632 continue
633 elif colors[1:] == [3,3]:
634 if 'T(1,2,3)' in interaction_info.color:
635 other, anticolor, color = interaction_info.particles
636 elif 'T(1,3,2)' in interaction_info.color:
637 other, color, anticolor = interaction_info.particles
638 elif 'Identity(2,3)' in interaction_info.color or \
639 'Identity(3,2)' in interaction_info.color:
640 _, first, second = interaction_info.particles
641 if first.pdg_code in output:
642 if output[first.pdg_code] == 3:
643 color, anticolor = first, second
644 else:
645 color, anticolor = second, first
646 elif second.pdg_code in output:
647 if output[second.pdg_code] == 3:
648 color, anticolor = second, first
649 else:
650 color, anticolor = first, second
651 else:
652 continue
653 else:
654 continue
655
656 elif colors.count(3) == 2:
657 if 'T(2,3,1)' in interaction_info.color:
658 color, other, anticolor = interaction_info.particles
659 elif 'T(2,1,3)' in interaction_info.color:
660 anticolor, other, color = interaction_info.particles
661 elif 'Identity(1,3)' in interaction_info.color or \
662 'Identity(3,1)' in interaction_info.color:
663 first, _, second = interaction_info.particles
664 if first.pdg_code in output:
665 if output[first.pdg_code] == 3:
666 color, anticolor = first, second
667 else:
668 color, anticolor = second, first
669 elif second.pdg_code in output:
670 if output[second.pdg_code] == 3:
671 color, anticolor = second, first
672 else:
673 color, anticolor = first, second
674 else:
675 continue
676 else:
677 continue
678 else:
679 continue
680
681
682 if color.pdg_code in output:
683 if output[color.pdg_code] == -3:
684 raise InvalidModel, 'Particles %s is sometimes in the 3 and sometimes in the 3bar representations' \
685 % color.name
686 else:
687 output[color.pdg_code] = 3
688
689
690 if anticolor.pdg_code in output:
691 if output[anticolor.pdg_code] == 3:
692 raise InvalidModel, 'Particles %s is sometimes set as in the 3 and sometimes in the 3bar representations' \
693 % anticolor.name
694 else:
695 output[anticolor.pdg_code] = -3
696
697 return output
698
700 """define which fermion should be incoming
701 for that we look at F F~ X interactions
702 """
703 self.incoming = []
704 self.outcoming = []
705 for interaction_info in self.ufomodel.all_vertices:
706
707 pdg = [p.pdg_code for p in interaction_info.particles if p.spin in [2,4]]
708 if len(pdg) % 2:
709 raise InvalidModel, 'Odd number of fermion in vertex: %s' % [p.pdg_code for p in interaction_info.particles]
710 for i in range(0, len(pdg),2):
711 if pdg[i] == - pdg[i+1]:
712 if pdg[i] in self.outcoming:
713 raise InvalidModel, '%s has not coherent incoming/outcoming status between interactions' %\
714 [p for p in interaction_info.particles if p.spin in [2,4]][i].name
715
716 elif not pdg[i] in self.incoming:
717 self.incoming.append(pdg[i])
718 self.outcoming.append(pdg[i+1])
719
720 - def add_interaction(self, interaction_info, color_info, type='base', loop_particles=None):
721 """add an interaction in the MG5 model. interaction_info is the
722 UFO vertices information."""
723
724 particles = [self.model.get_particle(particle.pdg_code) \
725 for particle in interaction_info.particles]
726 if None in particles:
727
728 return
729 particles = base_objects.ParticleList(particles)
730
731
732 lorentz = [helas for helas in interaction_info.lorentz]
733
734
735 nb_fermion = sum([ 1 if p.is_fermion() else 0 for p in particles])
736 try:
737 if nb_fermion == 2:
738
739 [aloha_fct.check_flow_validity(helas.structure, nb_fermion) \
740 for helas in interaction_info.lorentz
741 if helas.name not in self.checked_lor]
742 self.checked_lor.update(set([helas.name for helas in interaction_info.lorentz]))
743 elif nb_fermion:
744 if any(p.selfconjugate for p in interaction_info.particles if p.spin % 2 == 0):
745 text = "Majorana can not be dealt in 4/6/... fermion interactions"
746 raise InvalidModel, text
747 except aloha_fct.WrongFermionFlow, error:
748 text = 'Fermion Flow error for interactions %s: %s: %s\n %s' % \
749 (', '.join([p.name for p in interaction_info.particles]),
750 helas.name, helas.structure, error)
751 raise InvalidModel, text
752
753
754
755
756 lorentz = [helas.name for helas in lorentz]
757
758 colors = [self.treat_color(color_obj, interaction_info, color_info)
759 for color_obj in interaction_info.color]
760
761
762 order_to_int={}
763
764 for key, couplings in interaction_info.couplings.items():
765 if not isinstance(couplings, list):
766 couplings = [couplings]
767 if interaction_info.lorentz[key[1]].name not in lorentz:
768 continue
769
770 if nb_fermion > 2:
771 flow = aloha_fct.get_fermion_flow(interaction_info.lorentz[key[1]].structure,
772 nb_fermion)
773 coupling_sign = self.get_sign_flow(flow, nb_fermion)
774 else:
775 coupling_sign = ''
776 for coupling in couplings:
777 order = tuple(coupling.order.items())
778 if '1' in order:
779 raise InvalidModel, '''Some couplings have \'1\' order.
780 This is not allowed in MG.
781 Please defines an additional coupling to your model'''
782 if order in order_to_int:
783 order_to_int[order].get('couplings')[key] = '%s%s' % \
784 (coupling_sign,coupling.name)
785 else:
786
787 interaction = base_objects.Interaction({'id':len(self.interactions)+1})
788 interaction.set('particles', particles)
789 interaction.set('lorentz', lorentz)
790 interaction.set('couplings', {key:
791 '%s%s' %(coupling_sign,coupling.name)})
792 interaction.set('orders', coupling.order)
793 interaction.set('color', colors)
794 interaction.set('type', type)
795 interaction.set('loop_particles', loop_particles)
796 order_to_int[order] = interaction
797
798 self.interactions.append(interaction)
799
800
801
802 for charge in list(self.conservecharge):
803 total = 0
804 for part in interaction_info.particles:
805 try:
806 total += getattr(part, charge)
807 except AttributeError:
808 pass
809 if abs(total) > 1e-12:
810 logger.info('The model has interaction violating the charge: %s' % charge)
811 self.conservecharge.discard(charge)
812
813
815 """ensure that the flow of particles/lorentz are coherent with flow
816 and return a correct version if needed"""
817
818 if not flow or nb_fermion < 4:
819 return ''
820
821 expected = {}
822 for i in range(nb_fermion//2):
823 expected[i+1] = i+2
824
825 if flow == expected:
826 return ''
827
828 switch = {}
829 for i in range(1, nb_fermion+1):
830 if not i in flow:
831 continue
832 switch[i] = len(switch)
833 switch[flow[i]] = len(switch)
834
835
836 sign = 1
837 done = []
838
839
840
841 new_order = []
842 for id in range(nb_fermion):
843 nid = switch[id+1]-1
844
845 new_order.append(nid)
846
847
848 sign =1
849 for k in range(len(new_order)-1):
850 for l in range(k+1,len(new_order)):
851 if new_order[l] < new_order[k]:
852 sign *= -1
853
854 return '' if sign ==1 else '-'
855
856
857
858
860 """ Add a Lorentz expression which is not present in the UFO """
861
862 new = self.model['lorentz'][0].__class__(name = name,
863 spins = spins,
864 structure = expr)
865
866 self.model['lorentz'].append(new)
867 self.model.create_lorentz_dict()
868 return name
869
870 _pat_T = re.compile(r'T\((?P<first>\d*),(?P<second>\d*)\)')
871 _pat_id = re.compile(r'Identity\((?P<first>\d*),(?P<second>\d*)\)')
872
873 - def treat_color(self, data_string, interaction_info, color_info):
874 """ convert the string to ColorString"""
875
876
877
878
879
880 output = []
881 factor = 1
882 for term in data_string.split('*'):
883 pattern = self._pat_id.search(term)
884 if pattern:
885 particle = interaction_info.particles[int(pattern.group('first'))-1]
886 particle2 = interaction_info.particles[int(pattern.group('second'))-1]
887 if particle.color == particle2.color and particle.color in [-6, 6]:
888 error_msg = 'UFO model have inconsistency in the format:\n'
889 error_msg += 'interactions for particles %s has color information %s\n'
890 error_msg += ' but both fermion are in the same representation %s'
891 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
892 if particle.color == particle2.color and particle.color in [-3, 3]:
893 if particle.pdg_code in color_info and particle2.pdg_code in color_info:
894 if color_info[particle.pdg_code] == color_info[particle2.pdg_code]:
895 error_msg = 'UFO model have inconsistency in the format:\n'
896 error_msg += 'interactions for particles %s has color information %s\n'
897 error_msg += ' but both fermion are in the same representation %s'
898 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
899 elif particle.pdg_code in color_info:
900 color_info[particle2.pdg_code] = -particle.pdg_code
901 elif particle2.pdg_code in color_info:
902 color_info[particle.pdg_code] = -particle2.pdg_code
903 else:
904 error_msg = 'UFO model have inconsistency in the format:\n'
905 error_msg += 'interactions for particles %s has color information %s\n'
906 error_msg += ' but both fermion are in the same representation %s'
907 raise InvalidModel, error_msg % (', '.join([p.name for p in interaction_info.particles]),data_string, particle.color)
908
909
910 if particle.color == 6:
911 output.append(self._pat_id.sub('color.T6(\g<first>,\g<second>)', term))
912 elif particle.color == -6 :
913 output.append(self._pat_id.sub('color.T6(\g<second>,\g<first>)', term))
914 elif particle.color == 8:
915 output.append(self._pat_id.sub('color.Tr(\g<first>,\g<second>)', term))
916 factor *= 2
917 elif particle.color in [-3,3]:
918 if particle.pdg_code not in color_info:
919
920 logger.debug('fail to find 3/3bar representation: Retry to find it')
921 color_info = self.find_color_anti_color_rep(color_info)
922 if particle.pdg_code not in color_info:
923 logger.debug('Not able to find the 3/3bar rep from the interactions for particle %s' % particle.name)
924 color_info[particle.pdg_code] = particle.color
925 else:
926 logger.debug('succeed')
927 if particle2.pdg_code not in color_info:
928
929 logger.debug('fail to find 3/3bar representation: Retry to find it')
930 color_info = self.find_color_anti_color_rep(color_info)
931 if particle2.pdg_code not in color_info:
932 logger.debug('Not able to find the 3/3bar rep from the interactions for particle %s' % particle2.name)
933 color_info[particle2.pdg_code] = particle2.color
934 else:
935 logger.debug('succeed')
936
937 if color_info[particle.pdg_code] == 3 :
938 output.append(self._pat_id.sub('color.T(\g<second>,\g<first>)', term))
939 elif color_info[particle.pdg_code] == -3:
940 output.append(self._pat_id.sub('color.T(\g<first>,\g<second>)', term))
941 else:
942 raise MadGraph5Error, \
943 "Unknown use of Identity for particle with color %d" \
944 % particle.color
945 else:
946 output.append(term)
947 data_string = '*'.join(output)
948
949
950 p = re.compile(r'\'\w(?P<number>\d+)\'')
951 data_string = p.sub('-\g<number>', data_string)
952
953
954 new_indices = {}
955 new_indices = dict([(j,i) for (i,j) in \
956 enumerate(range(1,
957 len(interaction_info.particles)+1))])
958
959
960 output = data_string.split('*')
961 output = color.ColorString([eval(data) \
962 for data in output if data !='1'])
963 output.coeff = fractions.Fraction(factor)
964 for col_obj in output:
965 col_obj.replace_indices(new_indices)
966
967 return output
968
970 """Organize the cou plings/parameters of a model"""
971
972 track_dependant = ['aS','aEWM1','MU_R']
973
974
975
976
977 complex_number = re.compile(r'''complex\((?P<real>[^,\(\)]+),(?P<imag>[^,\(\)]+)\)''')
978 expo_expr = re.compile(r'''(?P<expr>[\w.]+)\s*\*\*\s*(?P<expo>[\d.+-]+)''')
979 cmath_expr = re.compile(r'''cmath.(?P<operation>\w+)\((?P<expr>\w+)\)''')
980
981 conj_expr = re.compile(r'''complexconjugate\((?P<expr>\w+)\)''')
982
983
984 separator = re.compile(r'''[+,\-*/()\s]*''')
985
987
988 self.model = model
989 self.perturbation_couplings = {}
990 try:
991 for order in model.all_orders:
992 if(order.perturbative_expansion>0):
993 self.perturbation_couplings[order.name]=order.perturbative_expansion
994 except AttributeError:
995 pass
996 self.params = {}
997 self.couplings = {}
998 self.all_expr = {}
999
1000 - def main(self, additional_couplings = []):
1001 """Launch the actual computation and return the associate
1002 params/couplings. Possibly consider additional_couplings in addition
1003 to those defined in the UFO model attribute all_couplings """
1004
1005 self.analyze_parameters()
1006 self.analyze_couplings(additional_couplings = additional_couplings)
1007 return self.params, self.couplings
1008
1009
1011 """ separate the parameters needed to be recomputed events by events and
1012 the others"""
1013
1014
1015
1016 present_aEWM1 = any(param.name == 'aEWM1' for param in
1017 self.model.all_parameters if param.nature == 'external')
1018
1019 if not present_aEWM1:
1020 self.track_dependant = ['aS','Gf','MU_R']
1021
1022 for param in self.model.all_parameters:
1023 if param.nature == 'external':
1024 parameter = base_objects.ParamCardVariable(param.name, param.value, \
1025 param.lhablock, param.lhacode)
1026
1027 else:
1028 expr = self.shorten_expr(param.value)
1029 depend_on = self.find_dependencies(expr)
1030 parameter = base_objects.ModelVariable(param.name, expr, param.type, depend_on)
1031
1032 self.add_parameter(parameter)
1033
1034
1036 """ add consistently the parameter in params and all_expr.
1037 avoid duplication """
1038
1039 assert isinstance(parameter, base_objects.ModelVariable)
1040
1041 if parameter.name in self.all_expr:
1042 return
1043
1044 self.all_expr[parameter.name] = parameter
1045 try:
1046 self.params[parameter.depend].append(parameter)
1047 except:
1048 self.params[parameter.depend] = [parameter]
1049
1051 """ add consistently the coupling in couplings and all_expr.
1052 avoid duplication """
1053
1054 assert isinstance(coupling, base_objects.ModelVariable)
1055
1056 if coupling.name in self.all_expr:
1057 return
1058 self.all_expr[coupling.value] = coupling
1059 try:
1060 self.coupling[coupling.depend].append(coupling)
1061 except:
1062 self.coupling[coupling.depend] = [coupling]
1063
1064
1065
1067 """creates the shortcut for all special function/parameter
1068 separate the couplings dependent of track variables of the others"""
1069
1070
1071
1072 if self.perturbation_couplings:
1073 couplings_list=[]
1074 for coupling in self.model.all_couplings + additional_couplings:
1075 for poleOrder in range(0,3):
1076 newCoupling=copy.deepcopy(coupling)
1077 if poleOrder!=0:
1078 newCoupling.name=newCoupling.name+"_"+str(poleOrder)+"eps"
1079 if newCoupling.pole(poleOrder)!='ZERO':
1080 newCoupling.value=newCoupling.pole(poleOrder)
1081 couplings_list.append(newCoupling)
1082 else:
1083 couplings_list = self.model.all_couplings + additional_couplings
1084 couplings_list = [c for c in couplings_list if not isinstance(c.value, dict)]
1085
1086 for coupling in couplings_list:
1087
1088 expr = self.shorten_expr(coupling.value)
1089 depend_on = self.find_dependencies(expr)
1090 parameter = base_objects.ModelVariable(coupling.name, expr, 'complex', depend_on)
1091
1092 try:
1093 self.couplings[depend_on].append(parameter)
1094 except KeyError:
1095 self.couplings[depend_on] = [parameter]
1096 self.all_expr[coupling.value] = parameter
1097
1099 """check if an expression should be evaluated points by points or not
1100 """
1101 depend_on = set()
1102
1103
1104
1105
1106
1107
1108
1109 expr = self.separator.split(expr)
1110
1111
1112 for subexpr in expr:
1113 if subexpr in self.track_dependant:
1114 depend_on.add(subexpr)
1115
1116 elif subexpr in self.all_expr and self.all_expr[subexpr].depend:
1117 [depend_on.add(value) for value in self.all_expr[subexpr].depend
1118 if self.all_expr[subexpr].depend != ('external',)]
1119 if depend_on:
1120 return tuple(depend_on)
1121 else:
1122 return tuple()
1123
1124
1137
1138
1140 """add the short expression, and return the nice string associate"""
1141
1142 float_real = float(eval(matchobj.group('real')))
1143 float_imag = float(eval(matchobj.group('imag')))
1144 if float_real == 0 and float_imag ==1:
1145 new_param = base_objects.ModelVariable('complexi', 'complex(0,1)', 'complex')
1146 self.add_parameter(new_param)
1147 return 'complexi'
1148 else:
1149 return 'complex(%s, %s)' % (matchobj.group('real'), matchobj.group('imag'))
1150
1151
1153 """add the short expression, and return the nice string associate"""
1154
1155 expr = matchobj.group('expr')
1156 exponent = matchobj.group('expo')
1157 new_exponent = exponent.replace('.','_').replace('+','').replace('-','_m_')
1158 output = '%s__exp__%s' % (expr, new_exponent)
1159 old_expr = '%s**%s' % (expr,exponent)
1160
1161 if expr.startswith('cmath'):
1162 return old_expr
1163
1164 if expr.isdigit():
1165 output = 'nb__' + output
1166 new_param = base_objects.ModelVariable(output, old_expr,'real')
1167 else:
1168 depend_on = self.find_dependencies(expr)
1169 type = self.search_type(expr)
1170 new_param = base_objects.ModelVariable(output, old_expr, type, depend_on)
1171 self.add_parameter(new_param)
1172 return output
1173
1190
1203
1204
1205
1207 """return the type associate to the expression if define"""
1208
1209 try:
1210 return self.all_expr[expr].type
1211 except:
1212 return 'complex'
1213
1215 """ A class for restricting a model for a given param_card.
1216 rules applied:
1217 - Vertex with zero couplings are throw away
1218 - external parameter with zero/one input are changed into internal parameter.
1219 - identical coupling/mass/width are replace in the model by a unique one
1220 """
1221
1228
1229 - def restrict_model(self, param_card, rm_parameter=True, keep_external=False):
1230 """apply the model restriction following param_card.
1231 rm_parameter defines if the Zero/one parameter are removed or not from
1232 the model.
1233 keep_external if the param_card need to be kept intact
1234 """
1235 if self.get('name') == "mssm" and not keep_external:
1236 raise Exception
1237 self.restrict_card = param_card
1238
1239 self.set('particles', self.get('particles'))
1240
1241
1242 self.set_parameters_and_couplings(param_card)
1243
1244 self.locate_coupling()
1245
1246 zero_couplings, iden_couplings = self.detect_identical_couplings()
1247
1248
1249 self.remove_interactions(zero_couplings)
1250
1251
1252 for iden_coups in iden_couplings:
1253 self.merge_iden_couplings(iden_coups)
1254
1255
1256 self.del_coup += zero_couplings
1257 self.remove_couplings(self.del_coup)
1258
1259
1260 parameters = self.detect_special_parameters()
1261 self.fix_parameter_values(*parameters, simplify=rm_parameter,
1262 keep_external=keep_external)
1263
1264
1265 if not keep_external:
1266 iden_parameters = self.detect_identical_parameters()
1267 for iden_param in iden_parameters:
1268 self.merge_iden_parameters(iden_param)
1269
1270 iden_parameters = self.detect_identical_parameters()
1271 for iden_param in iden_parameters:
1272 self.merge_iden_parameters(iden_param, keep_external)
1273
1274
1275
1276
1277 for name, value in self['parameter_dict'].items():
1278 if value == 9.999999e-1:
1279 self['parameter_dict'][name] = 1
1280 elif value == 0.000001e-99:
1281 self['parameter_dict'][name] = 0
1282
1283
1285 """ create a dict couplings_name -> vertex or (particle, counterterm_key) """
1286
1287 self.coupling_pos = {}
1288 for vertex in self['interactions']:
1289 for key, coupling in vertex['couplings'].items():
1290 if coupling in self.coupling_pos:
1291 if vertex not in self.coupling_pos[coupling]:
1292 self.coupling_pos[coupling].append(vertex)
1293 else:
1294 self.coupling_pos[coupling] = [vertex]
1295
1296 for particle in self['particles']:
1297 for key, coupling_dict in particle['counterterm'].items():
1298 for LaurentOrder, coupling in coupling_dict.items():
1299 if coupling in self.coupling_pos:
1300 if (particle,key) not in self.coupling_pos[coupling]:
1301 self.coupling_pos[coupling].append((particle,key))
1302 else:
1303 self.coupling_pos[coupling] = [(particle,key)]
1304
1305 return self.coupling_pos
1306
1308 """return a list with the name of all vanishing couplings"""
1309
1310 dict_value_coupling = {}
1311 iden_key = set()
1312 zero_coupling = []
1313 iden_coupling = []
1314
1315 for name, value in self['coupling_dict'].items():
1316 if value == 0:
1317 zero_coupling.append(name)
1318 continue
1319 elif not strict_zero and abs(value) < 1e-13:
1320 logger.debug('coupling with small value %s: %s treated as zero' %
1321 (name, value))
1322 zero_coupling.append(name)
1323 elif not strict_zero and abs(value) < 1e-10:
1324 return self.detect_identical_couplings(strict_zero=True)
1325
1326
1327 if value in dict_value_coupling:
1328 iden_key.add(value)
1329 dict_value_coupling[value].append(name)
1330 else:
1331 dict_value_coupling[value] = [name]
1332
1333 for key in iden_key:
1334 iden_coupling.append(dict_value_coupling[key])
1335
1336 return zero_coupling, iden_coupling
1337
1338
1340 """ return the list of (name of) parameter which are zero """
1341
1342 null_parameters = []
1343 one_parameters = []
1344 for name, value in self['parameter_dict'].items():
1345 if value == 0 and name != 'ZERO':
1346 null_parameters.append(name)
1347 elif value == 1:
1348 one_parameters.append(name)
1349
1350 return null_parameters, one_parameters
1351
1353 """ return the list of tuple of name of parameter with the same
1354 input value """
1355
1356
1357 external_parameters = self['parameters'][('external',)]
1358
1359
1360 block_value_to_var={}
1361 mult_param = set([])
1362
1363
1364
1365 for param in external_parameters[:]:
1366 value = self['parameter_dict'][param.name]
1367 if value in [0,1,0.000001e-99,9.999999e-1]:
1368 continue
1369 if param.lhablock.lower() == 'decay':
1370 continue
1371
1372 key = (param.lhablock, value)
1373 mkey = (param.lhablock, -value)
1374 if key in block_value_to_var:
1375 block_value_to_var[key].append((param,1))
1376 mult_param.add(key)
1377 elif mkey in block_value_to_var:
1378 block_value_to_var[mkey].append((param,-1))
1379 mult_param.add(mkey)
1380 else:
1381 block_value_to_var[key] = [(param,1)]
1382
1383 output=[]
1384 for key in mult_param:
1385 output.append(block_value_to_var[key])
1386
1387 return output
1388
1389
1391 """merge the identical couplings in the interactions and particle
1392 counterterms"""
1393
1394
1395 logger_mod.debug(' Fuse the Following coupling (they have the same value): %s '% \
1396 ', '.join([obj for obj in couplings]))
1397
1398 main = couplings[0]
1399 self.del_coup += couplings[1:]
1400
1401 for coupling in couplings[1:]:
1402
1403 if coupling not in self.coupling_pos:
1404 continue
1405
1406 vertices = [ vert for vert in self.coupling_pos[coupling] if
1407 isinstance(vert, base_objects.Interaction)]
1408 for vertex in vertices:
1409 for key, value in vertex['couplings'].items():
1410 if value == coupling:
1411 vertex['couplings'][key] = main
1412
1413
1414 particles_ct = [ pct for pct in self.coupling_pos[coupling] if
1415 isinstance(pct, tuple)]
1416 for pct in particles_ct:
1417 for key, value in pct[0]['counterterm'][pct[1]].items():
1418 if value == coupling:
1419 pct[0]['counterterm'][pct[1]][key] = main
1420
1421
1423 """ merge the identical parameters given in argument.
1424 keep external force to keep the param_card untouched (up to comment)"""
1425
1426 logger_mod.debug('Parameters set to identical values: %s '% \
1427 ', '.join(['%s*%s' % (f, obj.name.replace('mdl_','')) for (obj,f) in parameters]))
1428
1429
1430 external_parameters = self['parameters'][('external',)]
1431 for i, (obj, factor) in enumerate(parameters):
1432
1433 if i == 0:
1434 obj.info = 'set of param :' + \
1435 ', '.join([str(f)+'*'+param.name.replace('mdl_','')
1436 for (param, f) in parameters])
1437 expr = obj.name
1438 continue
1439
1440 if factor ==1:
1441 self.rule_card.add_identical(obj.lhablock.lower(), obj.lhacode,
1442 parameters[0][0].lhacode )
1443 else:
1444 self.rule_card.add_opposite(obj.lhablock.lower(), obj.lhacode,
1445 parameters[0][0].lhacode )
1446 obj_name = obj.name
1447
1448 if not keep_external:
1449 external_parameters.remove(obj)
1450 elif obj.lhablock.upper() in ['MASS','DECAY']:
1451 external_parameters.remove(obj)
1452 else:
1453 obj.name = ''
1454 obj.info = 'MG5 will not use this value use instead %s*%s' %(factor,expr)
1455
1456 new_param = base_objects.ModelVariable(obj_name, '%s*%s' %(factor, expr), 'real')
1457 self['parameters'][()].insert(0, new_param)
1458
1459
1460
1461 if parameters[0][0].lhablock in ['MASS','DECAY']:
1462 new_name = parameters[0][0].name
1463 if parameters[0][0].lhablock == 'MASS':
1464 arg = 'mass'
1465 else:
1466 arg = 'width'
1467 change_name = [p.name for (p,f) in parameters[1:]]
1468 [p.set(arg, new_name) for p in self['particle_dict'].values()
1469 if p[arg] in change_name]
1470
1472 """ remove the interactions and particle counterterms
1473 associated to couplings"""
1474
1475
1476 mod_vertex = []
1477 mod_particle_ct = []
1478 for coup in zero_couplings:
1479
1480 if coup not in self.coupling_pos:
1481 continue
1482
1483
1484
1485 vertices = [ vert for vert in self.coupling_pos[coup] if
1486 isinstance(vert, base_objects.Interaction) ]
1487 for vertex in vertices:
1488 modify = False
1489 for key, coupling in vertex['couplings'].items():
1490 if coupling in zero_couplings:
1491 modify=True
1492 del vertex['couplings'][key]
1493 if modify:
1494 mod_vertex.append(vertex)
1495
1496
1497 particles_ct = [ pct for pct in self.coupling_pos[coup] if
1498 isinstance(pct, tuple)]
1499 for pct in particles_ct:
1500 modify = False
1501 for key, coupling in pct[0]['counterterm'][pct[1]].items():
1502 if coupling in zero_couplings:
1503 modify=True
1504 del pct[0]['counterterm'][pct[1]][key]
1505 if modify:
1506 mod_particle_ct.append(pct)
1507
1508
1509 for vertex in mod_vertex:
1510 part_name = [part['name'] for part in vertex['particles']]
1511 orders = ['%s=%s' % (order,value) for order,value in vertex['orders'].items()]
1512
1513 if not vertex['couplings']:
1514 logger_mod.debug('remove interactions: %s at order: %s' % \
1515 (' '.join(part_name),', '.join(orders)))
1516 self['interactions'].remove(vertex)
1517 else:
1518 logger_mod.debug('modify interactions: %s at order: %s' % \
1519 (' '.join(part_name),', '.join(orders)))
1520
1521
1522 for pct in mod_particle_ct:
1523 part_name = pct[0]['name']
1524 order = pct[1][0]
1525 loop_parts = ','.join(['('+','.join([\
1526 self.get_particle(p)['name'] for p in part])+')' \
1527 for part in pct[1][1]])
1528
1529 if not pct[0]['counterterm'][pct[1]]:
1530 logger_mod.debug('remove counterterm of particle %s'%part_name+\
1531 ' with loop particles (%s)'%loop_parts+\
1532 ' perturbing order %s'%order)
1533 del pct[0]['counterterm'][pct[1]]
1534 else:
1535 logger_mod.debug('Modify counterterm of particle %s'%part_name+\
1536 ' with loop particles (%s)'%loop_parts+\
1537 ' perturbing order %s'%order)
1538
1539 return
1540
1542
1543 for name, data in self['couplings'].items():
1544 for coupling in data[:]:
1545 if coupling.name in couplings:
1546 data.remove(coupling)
1547
1548
1549 - def fix_parameter_values(self, zero_parameters, one_parameters,
1550 simplify=True, keep_external=False):
1551 """ Remove all instance of the parameters in the model and replace it by
1552 zero when needed."""
1553
1554
1555
1556 for particle in self['particles']:
1557 if particle['mass'] in zero_parameters:
1558 particle['mass'] = 'ZERO'
1559 if particle['width'] in zero_parameters:
1560 particle['width'] = 'ZERO'
1561 if particle['width'] in one_parameters:
1562 one_parameters.remove(particle['width'])
1563
1564 for pdg, particle in self['particle_dict'].items():
1565 if particle['mass'] in zero_parameters:
1566 particle['mass'] = 'ZERO'
1567 if particle['width'] in zero_parameters:
1568 particle['width'] = 'ZERO'
1569
1570
1571
1572 external_parameters = self['parameters'][('external',)]
1573 for param in external_parameters[:]:
1574 value = self['parameter_dict'][param.name]
1575 block = param.lhablock.lower()
1576 if value == 0:
1577 self.rule_card.add_zero(block, param.lhacode)
1578 elif value == 1:
1579 self.rule_card.add_one(block, param.lhacode)
1580
1581 special_parameters = zero_parameters + one_parameters
1582
1583
1584
1585 if simplify:
1586
1587 re_str = '|'.join(special_parameters)
1588 if len(re_str) > 25000:
1589 split = len(special_parameters) // 2
1590 re_str = ['|'.join(special_parameters[:split]),
1591 '|'.join(special_parameters[split:])]
1592 else:
1593 re_str = [ re_str ]
1594 used = set()
1595 for expr in re_str:
1596 re_pat = re.compile(r'''\b(%s)\b''' % expr)
1597
1598 for name, coupling_list in self['couplings'].items():
1599 for coupling in coupling_list:
1600 for use in re_pat.findall(coupling.expr):
1601 used.add(use)
1602 else:
1603 used = set([i for i in special_parameters if i])
1604
1605
1606 re_str = '|'.join([param for param in special_parameters if param not in used])
1607 if len(re_str) > 25000:
1608 split = len(special_parameters) // 2
1609 re_str = ['|'.join(special_parameters[:split]),
1610 '|'.join(special_parameters[split:])]
1611 else:
1612 re_str = [ re_str ]
1613 for expr in re_str:
1614 re_pat = re.compile(r'''\b(%s)\b''' % expr)
1615
1616 param_info = {}
1617
1618 for dep, param_list in self['parameters'].items():
1619 for tag, parameter in enumerate(param_list):
1620
1621 if parameter.name in special_parameters:
1622 param_info[parameter.name]= {'dep': dep, 'tag': tag,
1623 'obj': parameter}
1624 continue
1625
1626
1627 if isinstance(parameter, base_objects.ParamCardVariable):
1628 continue
1629
1630 if simplify:
1631 for use in re_pat.findall(parameter.expr):
1632 used.add(use)
1633
1634
1635 for param in used:
1636 if not param:
1637 continue
1638 data = self['parameters'][param_info[param]['dep']]
1639 data.remove(param_info[param]['obj'])
1640 tag = param_info[param]['tag']
1641 data = self['parameters'][()]
1642 if param in zero_parameters:
1643 data.insert(0, base_objects.ModelVariable(param, '0.0', 'real'))
1644 else:
1645 data.insert(0, base_objects.ModelVariable(param, '1.0', 'real'))
1646
1647
1648 for param in special_parameters:
1649
1650 if param in used or \
1651 (keep_external and param_info[param]['dep'] == ('external',)):
1652 logger_mod.debug('fix parameter value: %s' % param)
1653 continue
1654 logger_mod.debug('remove parameters: %s' % (param))
1655 data = self['parameters'][param_info[param]['dep']]
1656 data.remove(param_info[param]['obj'])
1657