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