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