~alifson/chiralityflow/trunk

« back to all changes in this revision

Viewing changes to tests/unit_tests/various/test_usermod.py

  • Committer: andrew.lifson at lu
  • Date: 2021-09-01 15:34:39 UTC
  • Revision ID: andrew.lifson@thep.lu.se-20210901153439-7fasjhav4cp4m88r
testing a new repository of a madgraph folder

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
################################################################################
 
2
#
 
3
# Copyright (c) 2009 The MadGraph Development team and Contributors
 
4
#
 
5
# This file is a part of the MadGraph 5 project, an application which 
 
6
# automatically generates Feynman diagrams and matrix elements for arbitrary
 
7
# high-energy processes in the Standard Model and beyond.
 
8
#
 
9
# It is subject to the MadGraph license which should accompany this 
 
10
# distribution.
 
11
#
 
12
# For more information, please visit: http://madgraph.phys.ucl.ac.be
 
13
#
 
14
################################################################################
 
15
"""Unit test Library for importing and restricting model"""
 
16
from __future__ import division
 
17
 
 
18
from __future__ import absolute_import
 
19
import copy
 
20
import os
 
21
import sys
 
22
import time
 
23
import tempfile 
 
24
import shutil 
 
25
 
 
26
import tests.unit_tests as unittest
 
27
import madgraph.core.base_objects as base_objects
 
28
import models
 
29
import models.import_ufo as import_ufo
 
30
import models.usermod as usermod
 
31
import models as ufomodels
 
32
import models.model_reader as model_reader
 
33
import madgraph.iolibs.export_v4 as export_v4
 
34
import madgraph.various.misc as misc
 
35
import six
 
36
from six.moves import range
 
37
from six.moves import zip
 
38
 
 
39
_file_path = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]
 
40
pjoin = os.path.join
 
41
 
 
42
import cmath
 
43
 
 
44
#
 
45
# UFO CLASS SINCE THEY WILL BE USEFULL!
 
46
#
 
47
 
 
48
class UFOBaseClass(object):
 
49
    """The class from which all FeynRules classes are derived."""
 
50
 
 
51
    require_args = []
 
52
 
 
53
    def __init__(self, *args, **options):
 
54
        assert(len(self.require_args) == len (args))
 
55
    
 
56
        for i, name in enumerate(self.require_args):
 
57
            setattr(self, name, args[i])
 
58
    
 
59
        for (option, value) in options.items():
 
60
            setattr(self, option, value)
 
61
 
 
62
    def get(self, name):
 
63
        return getattr(self, name)
 
64
    
 
65
    def set(self, name, value):
 
66
        setattr(self, name, value)
 
67
        
 
68
    def get_all(self):
 
69
        """Return a dictionary containing all the information of the object"""
 
70
        return self.__dict__
 
71
 
 
72
    def __str__(self):
 
73
        return self.name
 
74
 
 
75
    def nice_string(self):
 
76
        """ return string with the full information """
 
77
        return '\n'.join(['%s \t: %s' %(name, value) for name, value in self.__dict__.items()])
 
78
 
 
79
    def __repr__(self):
 
80
        replacements = [
 
81
            ('+','__plus__'),
 
82
            ('-','__minus__'),
 
83
            ('@','__at__'),
 
84
            ('!','__exclam__'),
 
85
            ('?','__quest__'),
 
86
            ('*','__star__'),
 
87
            ('~','__tilde__')
 
88
            ]
 
89
        text = self.name
 
90
        for orig,sub in replacements:
 
91
            text = text.replace(orig,sub)
 
92
        return text
 
93
 
 
94
 
 
95
 
 
96
all_particles = []
 
97
 
 
98
    
 
99
 
 
100
class Particle(UFOBaseClass):
 
101
    """A standard Particle"""
 
102
 
 
103
    require_args=['pdg_code', 'name', 'antiname', 'spin', 'color', 'mass', 'width', 'texname', 'antitexname', 'charge']
 
104
 
 
105
    require_args_all = ['pdg_code', 'name', 'antiname', 'spin', 'color', 'mass', 'width', 'texname', 'antitexname', 'charge', 'line', 'propagating', 'goldstoneboson']
 
106
 
 
107
    def __init__(self, pdg_code, name, antiname, spin, color, mass, width, texname,
 
108
                 antitexname, charge , line=None, propagating=True, goldstoneboson=False, **options):
 
109
 
 
110
        args= (pdg_code, name, antiname, spin, color, mass, width, texname,
 
111
                 antitexname, float(charge))
 
112
 
 
113
        UFOBaseClass.__init__(self, *args,  **options)
 
114
 
 
115
        global all_particles
 
116
        all_particles.append(self)
 
117
 
 
118
        self.propagating = propagating
 
119
        self.goldstoneboson= goldstoneboson
 
120
 
 
121
        self.selfconjugate = (name == antiname)
 
122
        if 1: #not line:
 
123
            self.line = self.find_line_type()
 
124
        else:
 
125
            self.line = line
 
126
 
 
127
 
 
128
 
 
129
 
 
130
    def find_line_type(self):
 
131
        """ find how we draw a line if not defined
 
132
        valid output: dashed/straight/wavy/curly/double/swavy/scurly
 
133
        """
 
134
        
 
135
        spin = self.spin
 
136
        color = self.color
 
137
        
 
138
        #use default
 
139
        if spin == 1:
 
140
            return 'dashed'
 
141
        elif spin == 2:
 
142
            if not self.selfconjugate:
 
143
                return 'straight'
 
144
            elif color == 1:
 
145
                return 'swavy'
 
146
            else:
 
147
                return 'scurly'
 
148
        elif spin == 3:
 
149
            if color == 1:
 
150
                return 'wavy'
 
151
            
 
152
            else:
 
153
                return 'curly'
 
154
        elif spin == 5:
 
155
            return 'double'
 
156
        elif spin == -1:
 
157
            return 'dotted'
 
158
        else:
 
159
            return 'dashed' # not supported yet
 
160
 
 
161
    def anti(self):
 
162
        if self.selfconjugate:
 
163
            raise Exception('%s has no anti particle.' % self.name) 
 
164
        outdic = {}
 
165
        for k,v in six.iteritems(self.__dict__):
 
166
            if k not in self.require_args_all:                
 
167
                outdic[k] = -v
 
168
        if self.color in [1,8]:
 
169
            newcolor = self.color
 
170
        else:
 
171
            newcolor = -self.color
 
172
                
 
173
        return Particle(-self.pdg_code, self.antiname, self.name, self.spin, newcolor, self.mass, self.width,
 
174
                        self.antitexname, self.texname, -self.charge, self.line, self.propagating, self.goldstoneboson, **outdic)
 
175
 
 
176
 
 
177
 
 
178
all_parameters = []
 
179
 
 
180
class Parameter(UFOBaseClass):
 
181
 
 
182
    require_args=['name', 'nature', 'type', 'value', 'texname']
 
183
 
 
184
    def __init__(self, name, nature, type, value, texname, lhablock=None, lhacode=None):
 
185
 
 
186
        args = (name,nature,type,value,texname)
 
187
 
 
188
        UFOBaseClass.__init__(self, *args)
 
189
 
 
190
        args=(name,nature,type,value,texname)
 
191
 
 
192
        global all_parameters
 
193
        all_parameters.append(self)
 
194
 
 
195
        if (lhablock is None or lhacode is None)  and nature == 'external':
 
196
            raise Exception('Need LHA information for external parameter "%s".' % name)
 
197
        self.lhablock = lhablock
 
198
        self.lhacode = lhacode
 
199
 
 
200
all_vertices = []
 
201
 
 
202
class Vertex(UFOBaseClass):
 
203
 
 
204
    require_args=['name', 'particles', 'color', 'lorentz', 'couplings']
 
205
 
 
206
    def __init__(self, name, particles, color, lorentz, couplings, **opt):
 
207
 
 
208
        args = (name, particles, color, lorentz, couplings)
 
209
 
 
210
        UFOBaseClass.__init__(self, *args, **opt)
 
211
 
 
212
        args=(particles,color,lorentz,couplings)
 
213
 
 
214
        global all_vertices
 
215
        all_vertices.append(self)
 
216
 
 
217
all_couplings = []
 
218
 
 
219
class Coupling(UFOBaseClass):
 
220
 
 
221
    require_args=['name', 'value', 'order']
 
222
 
 
223
    def __init__(self, name, value, order, **opt):
 
224
 
 
225
        args =(name, value, order)    
 
226
        UFOBaseClass.__init__(self, *args, **opt)
 
227
        global all_couplings
 
228
        all_couplings.append(self)
 
229
  
 
230
 
 
231
 
 
232
all_lorentz = []
 
233
 
 
234
class Lorentz(UFOBaseClass):
 
235
 
 
236
    require_args=['name','spins','structure']
 
237
    
 
238
    def __init__(self, name, spins, structure='external', **opt):
 
239
        args = (name, spins, structure)
 
240
        UFOBaseClass.__init__(self, *args, **opt)
 
241
 
 
242
        global all_lorentz
 
243
        all_lorentz.append(self)
 
244
 
 
245
 
 
246
all_functions = []
 
247
 
 
248
class Function(object):
 
249
 
 
250
    def __init__(self, name, arguments, expression):
 
251
 
 
252
        global all_functions
 
253
        all_functions.append(self)
 
254
 
 
255
        self.name = name
 
256
        self.arguments = arguments
 
257
        self.expr = expression
 
258
    
 
259
    def __call__(self, *opt):
 
260
 
 
261
        for i, arg in enumerate(self.arguments):
 
262
            exec('%s = %s' % (arg, opt[i] ))
 
263
 
 
264
        return eval(self.expr)
 
265
 
 
266
all_orders = []
 
267
 
 
268
class CouplingOrder(object):
 
269
 
 
270
    def __init__(self, name, expansion_order, hierarchy, perturbative_expansion = 0):
 
271
        
 
272
        global all_orders
 
273
        all_orders.append(self)
 
274
 
 
275
        self.name = name
 
276
        self.expansion_order = expansion_order
 
277
        self.hierarchy = hierarchy
 
278
 
 
279
all_decays = []
 
280
 
 
281
class Decay(UFOBaseClass):
 
282
    require_args = ['particle','partial_widths']
 
283
 
 
284
    def __init__(self, particle, partial_widths, **opt):
 
285
        args = (particle, partial_widths)
 
286
        UFOBaseClass.__init__(self, *args, **opt)
 
287
 
 
288
        global all_decays
 
289
        all_decays.append(self)
 
290
    
 
291
        # Add the information directly to the particle
 
292
        particle.partial_widths = partial_widths
 
293
 
 
294
all_form_factors = []
 
295
 
 
296
class FormFactor(UFOBaseClass):
 
297
    require_args = ['name','type','value']
 
298
 
 
299
    def __init__(self, name, type, value, **opt):
 
300
        args = (name, type, value)
 
301
        UFOBaseClass.__init__(self, *args, **opt)
 
302
 
 
303
        global all_form_factors
 
304
        all_form_factors.append(self)
 
305
 
 
306
class Model(object):
 
307
    """ """
 
308
    def __init__(self):
 
309
        global all_form_factors, all_particles, all_decays,all_orders, all_functions,\
 
310
               all_lorentz,all_couplings, all_vertices, all_parameters
 
311
               
 
312
        self.all_form_factors = all_form_factors
 
313
        self.all_particles = all_particles
 
314
        self.all_decays = all_decays
 
315
        self.all_orders = all_orders
 
316
        self.all_functions = all_functions
 
317
        self.all_lorentz = all_lorentz
 
318
        self.all_couplings = all_couplings
 
319
        self.all_vertices = all_vertices
 
320
        self.all_parameters = all_parameters
 
321
        
 
322
    
 
323
 
 
324
#===============================================================================
 
325
# Test The UFO usermod package 
 
326
#===============================================================================
 
327
class TestModUFO(unittest.TestCase):
 
328
    """Test class for the USERMOD object"""
 
329
 
 
330
 
 
331
    def setUp(self):
 
332
        self.debug=False
 
333
        if self.debug:
 
334
            self.path = "/tmp/"
 
335
        else:   
 
336
            self.path = tempfile.mkdtemp(prefix='unitest_usermod') 
 
337
 
 
338
        #Read the full SM
 
339
        self.sm_path = import_ufo.find_ufo_path('sm')
 
340
        self.base_model = usermod.UFOModel(self.sm_path)
 
341
        
 
342
    def tearDown(self):
 
343
        
 
344
        if not self.debug:
 
345
            shutil.rmtree(self.path)
 
346
        self.assertFalse(self.debug)
 
347
 
 
348
    def test_write_model(self):
 
349
        """ Check that we can write all the require UFO files """
 
350
        
 
351
        output = pjoin(self.path, 'usrmod')
 
352
        self.base_model.write(output)
 
353
        sm_path = import_ufo.find_ufo_path('sm')
 
354
        self.assertEqual(12, 
 
355
                len([1 for name in os.listdir(sm_path) if name.endswith('.py')]), 
 
356
               'New file in  UFO format, usrmod need to be modified')
 
357
 
 
358
        self.assertEqual(11, 
 
359
                len([1 for name in os.listdir(output) if name.endswith('.py')]))
 
360
 
 
361
        sys.path.insert(0, os.path.dirname(output))
 
362
        import usrmod
 
363
 
 
364
 
 
365
    def compare(self, text1, text2, optional=[], default={}):
 
366
        """ """
 
367
        
 
368
        texts= [text1, text2]
 
369
        data = []
 
370
        
 
371
        for text in texts:
 
372
            curr_data = []
 
373
            data.append(curr_data)
 
374
            curr_object = {}
 
375
            for line in text.split('\n'):
 
376
                line = line.strip()
 
377
                if line.endswith(',') or line.endswith(')'):
 
378
                    line = line[:-1]
 
379
                    
 
380
                if (line.count('=') == 2 and line.count('(') == 1):
 
381
                    if curr_object:
 
382
                        curr_data.append(curr_object)
 
383
                    curr_object = dict(default)
 
384
                    k,value = line.split('(')[1].split('=')
 
385
                    curr_object[k.strip()] = value.strip()
 
386
                elif line.count('=') == 1:
 
387
                    k,value = line.split('=')
 
388
                    curr_object[k.strip()] =  value.strip()
 
389
            else:
 
390
                if curr_object:
 
391
                    curr_data.append(curr_object)
 
392
        
 
393
        for element in data[0]:
 
394
            #print element, type(element)
 
395
            for i in range(1, len(data)):
 
396
                #for element2 in data[i]:
 
397
                #    print element2,
 
398
                #    if element == element2:
 
399
                #        print 'identical'
 
400
                #        break
 
401
                #    else:
 
402
                #        print 'different'
 
403
                #else:
 
404
                #    self.assertFalse(True)
 
405
                self.assertTrue(element in data[i])
 
406
 
 
407
 
 
408
    def test_write_orders(self):
 
409
        """Check that the content of the file is valid"""
 
410
 
 
411
        output = self.path
 
412
        self.base_model.write_orders(output)
 
413
        filename = os.path.join(output, 'coupling_orders.py')
 
414
        text = open(os.path.join(filename)).read()
 
415
        
 
416
        target = """
 
417
# This file was automatically created by The UFO_usermod        
 
418
 
 
419
from object_library import all_orders, CouplingOrder
 
420
QCD = CouplingOrder(name = 'QCD',
 
421
                    expansion_order = 99,
 
422
                    hierarchy = 1,
 
423
                    perturbative_expansion = 0)
 
424
 
 
425
 
 
426
QED = CouplingOrder(name = 'QED',
 
427
                    expansion_order = 99,
 
428
                    hierarchy = 2,
 
429
                    perturbative_expansion = 0)
 
430
 
 
431
"""
 
432
 
 
433
        self.compare(target, text, default={'perturbative_expansion':'0'})
 
434
        
 
435
 
 
436
 
 
437
 
 
438
 
 
439
    def test_write_particles(self):
 
440
        """Check that the content of the file is valid"""
 
441
 
 
442
        output = self.path
 
443
        self.base_model.write_particles(output)
 
444
        filename = os.path.join(output, 'particles.py')
 
445
        text = open(os.path.join(filename)).read()
 
446
        target = open(pjoin(self.sm_path, 'particles.py')).read()
 
447
 
 
448
 
 
449
        
 
450
        #format the ouptut
 
451
        target = target.replace('0.0,','0,')
 
452
        target = target.replace('1/3,','0.333333333333,')
 
453
        target = target.replace('2/3,','0.666666666667,')
 
454
        target = target.split('\n')
 
455
        target = [l.strip() for l in target 
 
456
                  if l.strip() and not l.strip().startswith('#') and 
 
457
                  not l.split('=')[0].strip() in ['line', 'propagating', 'goldstoneboson', 'GoldstoneBoson','selfconjugate']]
 
458
        duplicate = []
 
459
        target = [l for l in target if not '.anti()' in l or duplicate.append(l.split('=')[0].strip())] 
 
460
        
 
461
        text = text.replace('.0,',',')
 
462
        text = text.replace('1/3,','0.333333333333,')
 
463
        text = text.replace('2/3,','0.666666666667,')
 
464
        text = text.replace('0.6666666666666666', '0.666666666667')
 
465
        text = text.replace('0.3333333333333333', '0.333333333333')
 
466
        text = text.split('\n')        
 
467
        text = [l.strip() for l in text
 
468
                  if l.strip() and not l.strip().startswith('#') and 
 
469
                  not l.split('=')[0].strip() in ['line', 'propagating', 'goldstoneboson', 'GoldstoneBoson','selfconjugate']]
 
470
 
 
471
        
 
472
        keep = True      
 
473
        new_text = []  
 
474
        for line in text:
 
475
            if 'Particle' in line:
 
476
                if line.split('=')[0].strip() in duplicate:
 
477
                    keep = False
 
478
                else:
 
479
                    keep = True
 
480
            if not keep:
 
481
                continue
 
482
            else:
 
483
                new_text.append(line)
 
484
        text=new_text
 
485
        
 
486
        for line1, line2 in zip(target, text):
 
487
            self.assertEqual(line1.replace(',',')'), line2.replace(',',')'))
 
488
 
 
489
                
 
490
    def test_write_vertices(self):
 
491
        """Check that the content of the file is valid"""
 
492
 
 
493
        output = self.path
 
494
        self.base_model.vertices = self.base_model.vertices[:2]
 
495
        self.base_model.write_vertices(output)
 
496
        filename = os.path.join(output, 'vertices.py')
 
497
        text = open(os.path.join(filename)).read()
 
498
        target = """V_1 = Vertex(name = 'V_1',
 
499
             particles = [P.G0, P.G0, P.G0, P.G0],
 
500
             color = ['1'],
 
501
             lorentz = [L.SSSS1],
 
502
             couplings = {(0,0): C.GC_33})
 
503
 
 
504
 
 
505
V_2 = Vertex(name = 'V_2',
 
506
             particles = [P.G0, P.G0, P.G__minus__, P.G__plus__],
 
507
             color = ['1'],
 
508
             lorentz = [L.SSSS1],
 
509
             couplings = {(0,0): C.GC_31})
 
510
        """
 
511
 
 
512
 
 
513
 
 
514
#===============================================================================
 
515
# Test The UFO usermod package 
 
516
#===============================================================================
 
517
class Test_ADDON_UFO(unittest.TestCase):
 
518
    """Test class for the USERMOD object"""
 
519
 
 
520
 
 
521
    def setUp(self):
 
522
        
 
523
        self.path = tempfile.mkdtemp(prefix='unitest_usermod') 
 
524
 
 
525
        #Read the full SM
 
526
        self.sm_path = import_ufo.find_ufo_path('sm')
 
527
        self.base_model = usermod.UFOModel(self.sm_path)
 
528
        self.mymodel = Model()
 
529
        self.sm = models.load_model('sm')
 
530
        for key in self.mymodel.__dict__:
 
531
            obj = getattr(self.mymodel, key)
 
532
            for o in obj[:]:
 
533
                obj.pop()
 
534
        
 
535
    def tearDown(self):
 
536
        
 
537
        shutil.rmtree(self.path)
 
538
        
 
539
    def test_add_particle(self):
 
540
        """Check that we can an external parameter consistently"""
 
541
        
 
542
        #ZERO is define in all model => we should just do nothing
 
543
        ZERO = Parameter(name = 'ZERO',
 
544
                 nature = 'internal',
 
545
                 type = 'real',
 
546
                 value = '0.0',
 
547
                 texname = '0')
 
548
 
 
549
        MH = Parameter(name = 'MH',
 
550
               nature = 'external',
 
551
               type = 'real',
 
552
               value = 125,
 
553
               texname = '\\text{MH}',
 
554
               lhablock = 'MASS',
 
555
               lhacode = [ 25 ])        
 
556
 
 
557
        WH = Parameter(name = 'WH',
 
558
               nature = 'external',
 
559
               type = 'real',
 
560
               value = 125,
 
561
               texname = '\\text{MH}',
 
562
               lhablock = 'WIDTH',
 
563
               lhacode = [ 25 ])
 
564
        
 
565
        H = Particle(pdg_code = 25,
 
566
             name = 'H',
 
567
             antiname = 'H',
 
568
             spin = 1,
 
569
             color = 1,
 
570
             mass = MH,
 
571
             width = WH,
 
572
             texname = 'H',
 
573
             antitexname = 'H',
 
574
             charge = 0,
 
575
             GhostNumber = 0,
 
576
             LeptonNumber = 0,
 
577
             Y = 0)
 
578
        
 
579
        number_particles = len(self.base_model.particles)
 
580
        
 
581
        #Add a particle which is exactly the Higgs like in the Standard Model
 
582
        self.base_model.add_particle(H)
 
583
        self.assertEqual( number_particles, len(self.base_model.particles))
 
584
        self.assertEqual( number_particles, len(self.sm.all_particles))
 
585
        
 
586
        #Same name but different pid ->add but with rename
 
587
        H = Particle(pdg_code = 26,
 
588
             name = 'H',
 
589
             antiname = 'H',
 
590
             spin = 1,
 
591
             color = 1,
 
592
             mass = MH,
 
593
             width = WH,
 
594
             texname = 'H',
 
595
             antitexname = 'H',
 
596
             charge = 0,
 
597
             GhostNumber = 0,
 
598
             LeptonNumber = 0,
 
599
             Y = 0) 
 
600
        self.base_model.add_particle(H)
 
601
        self.assertEqual( number_particles+1, len(self.base_model.particles))       
 
602
        self.assertEqual( number_particles, len(self.sm.all_particles))
 
603
        orig_number_particles = number_particles
 
604
        number_particles+=1
 
605
        self.assertEqual(H.name, 'H__1')
 
606
        
 
607
        #Different name and different pid keep it
 
608
        H = Particle(pdg_code = 26,
 
609
             name = 'H2',
 
610
             antiname = 'H2',
 
611
             spin = 1,
 
612
             color = 1,
 
613
             mass = MH,
 
614
             width = WH,
 
615
             texname = 'H',
 
616
             antitexname = 'H',
 
617
             charge = 0,
 
618
             GhostNumber = 0,
 
619
             LeptonNumber = 0,
 
620
             Y = 0) 
 
621
        self.base_model.add_particle(H)
 
622
        self.assertEqual( number_particles+1, len(self.base_model.particles)) 
 
623
        self.assertEqual( orig_number_particles, len(self.sm.all_particles))      
 
624
        number_particles+=1
 
625
        self.assertEqual(H.name, 'H2')
 
626
        #Different name But different pid.
 
627
        H = Particle(pdg_code = 25,
 
628
             name = 'H3',
 
629
             antiname = 'H3',
 
630
             spin = 1,
 
631
             color = 1,
 
632
             mass = MH,
 
633
             width = WH,
 
634
             texname = 'H',
 
635
             antitexname = 'H',
 
636
             charge = 0,
 
637
             GhostNumber = 0,
 
638
             LeptonNumber = 0,
 
639
             Y = 0) 
 
640
        self.base_model.add_particle(H)
 
641
        self.assertEqual( number_particles, len(self.base_model.particles)) 
 
642
        self.assertEqual( orig_number_particles, len(self.sm.all_particles))      
 
643
        #number_particles+=1
 
644
        self.assertEqual(H.name, 'H3')
 
645
        
 
646
        ###################################################
 
647
        ##  ALL THOSE TEST WERE NOT CHEKING MASS / WIDTH ##
 
648
        ###################################################                       
 
649
        # plugin to zero -> keep the one of the model
 
650
        H = Particle(pdg_code = 25,
 
651
             name = 'H',
 
652
             antiname = 'H',
 
653
             spin = 1,
 
654
             color = 1,
 
655
             mass = ZERO,
 
656
             width = ZERO,
 
657
             texname = 'H',
 
658
             antitexname = 'H',
 
659
             charge = 0,
 
660
             GhostNumber = 0,
 
661
             LeptonNumber = 0,
 
662
             Y = 0)         
 
663
        self.base_model.add_particle(H)
 
664
        self.assertEqual( number_particles, len(self.base_model.particles))
 
665
        self.assertEqual( orig_number_particles, len(self.sm.all_particles))       
 
666
        self.assertEqual(H.name, 'H')        
 
667
        self.assertEqual(H.mass.name, 'ZERO')
 
668
        true_higgs = self.base_model.particle_dict[25]
 
669
        self.assertEqual(true_higgs.name, 'H')        
 
670
        self.assertEqual(true_higgs.mass.name, 'MH')        
 
671
        
 
672
        # base_model to zero -> keep the one of the plugin
 
673
        M5 = Parameter(name = 'M5',
 
674
               nature = 'external',
 
675
               type = 'real',
 
676
               value = 125,
 
677
               texname = '\\text{MH}',
 
678
               lhablock = 'MASS',
 
679
               lhacode = [ 5 ]) 
 
680
        W5 = Parameter(name = 'W5',
 
681
               nature = 'external',
 
682
               type = 'real',
 
683
               value = 125,
 
684
               texname = '\\text{MH}',
 
685
               lhablock = 'DECAY',
 
686
               lhacode = [ 5 ]) 
 
687
        B = Particle(pdg_code = 5,
 
688
             name = 'B',
 
689
             antiname = 'B~',
 
690
             spin = 1,
 
691
             color = 1,
 
692
             mass = M5,
 
693
             width = W5,
 
694
             texname = 'H',
 
695
             antitexname = 'H',
 
696
             charge = 0,
 
697
             GhostNumber = 0,
 
698
             LeptonNumber = 0,
 
699
             Y = 0)   
 
700
 
 
701
        self.base_model.add_parameter(M5)
 
702
        self.base_model.add_parameter(W5)
 
703
        self.base_model.add_particle(B)
 
704
        self.assertEqual( number_particles, len(self.base_model.particles)) 
 
705
        self.assertEqual( orig_number_particles, len(self.sm.all_particles))      
 
706
        # For the mass both are define, so this is should be a merge
 
707
        self.assertEqual(B.name, 'B')        
 
708
        self.assertEqual(B.mass.name, 'M5')
 
709
        true_b = self.base_model.particle_dict[5]
 
710
        self.assertEqual(true_b.name, 'b')        
 
711
        self.assertEqual(true_b.mass.name, 'MB') # keep MB since M5 is merge on MB            
 
712
        self.assertEqual(self.base_model.old_new['M5'], 'MB')
 
713
        # For the width the model one is zero => overwrite
 
714
        self.assertEqual(B.name, 'B')        
 
715
        self.assertEqual(B.width.name, 'W5')
 
716
        self.assertEqual(true_b.width.name, 'W5')
 
717
 
 
718
 
 
719
 
 
720
        
 
721
        
 
722
    def test_add_external_parameters(self):
 
723
        """Check that we can an external parameter consistently"""        
 
724
                
 
725
        nb_param = len(self.base_model.parameters)
 
726
        #ZERO is define in all model => we should just do nothing
 
727
        ZERO = Parameter(name = 'ZERO',
 
728
                 nature = 'internal',
 
729
                 type = 'real',
 
730
                 value = '0.0',
 
731
                 texname = '0')
 
732
        # add it and check that nothing happen!
 
733
        self.base_model.add_parameter(ZERO)
 
734
        self.assertEqual(nb_param,  len(self.base_model.parameters))
 
735
        
 
736
        
 
737
        # MH is already define 
 
738
        MH = Parameter(name = 'MH',
 
739
               nature = 'external',
 
740
               type = 'real',
 
741
               value = 125,
 
742
               texname = '\\text{MH}',
 
743
               lhablock = 'MASS',
 
744
               lhacode = [ 25 ])
 
745
        
 
746
        # add it and check that nothing happen!
 
747
        self.base_model.add_parameter(MH)
 
748
        self.assertEqual(nb_param,  len(self.base_model.parameters))           
 
749
        
 
750
        # MH is already definebut has a different name ib both model
 
751
        MH = Parameter(name = 'MH2',
 
752
               nature = 'external',
 
753
               type = 'real',
 
754
               value = 125,
 
755
               texname = '\\text{MH}',
 
756
               lhablock = 'MASS',
 
757
               lhacode = [ 25 ])
 
758
        
 
759
        # add it and check that nothing happen!
 
760
        self.base_model.add_parameter(MH)
 
761
        self.assertEqual(nb_param,  len(self.base_model.parameters)) 
 
762
        # But the information should be present in the old->new dict
 
763
        self.assertEqual(self.base_model.old_new['MH2'], 'MH')
 
764
 
 
765
        # Add an internal parameter depending of MH2
 
766
        GH = Parameter(name = 'GH',
 
767
               nature = 'internal',
 
768
               type = 'real',
 
769
               texname = '\\text{MH}',
 
770
               value = '25*MH2**2*AMH2*MH25')
 
771
        
 
772
        self.base_model.add_parameter(GH)
 
773
        self.assertEqual(nb_param+1,  len(self.base_model.parameters)) 
 
774
        #check that the expression of GH is correctly modified
 
775
        self.assertEqual(GH.value, '25*MH**2*AMH2*MH25')
 
776
        self.assertEqual(GH.name, 'GH')
 
777
        nb_param = nb_param+1
 
778
        
 
779
        # Add an internal parameter depending of MH2
 
780
        # But with a name conflict
 
781
        Gf = Parameter(name = 'Gf',
 
782
               nature = 'internal',
 
783
               type = 'real',
 
784
               texname = '\\text{MH}',
 
785
               value = '25*MH2**2*AMH2*MH25')
 
786
        
 
787
        self.base_model.add_parameter(Gf)
 
788
        self.assertEqual(nb_param+1,  len(self.base_model.parameters)) 
 
789
        #check that the expression of GH is correctly modified
 
790
        self.assertEqual(Gf.value, '25*MH**2*AMH2*MH25')
 
791
        self.assertEqual(Gf.name, 'Gf__1')
 
792
        self.assertEqual(self.base_model.old_new['Gf'], 'Gf__1')       
 
793
        nb_param = nb_param+1
 
794
         
 
795
        # Add an internal parameter depending of MH2 and of Gf
 
796
        # But with a name conflict
 
797
        Gf2 = Parameter(name = 'Gf2',
 
798
               nature = 'internal',
 
799
               type = 'real',
 
800
               texname = '\\text{MH}',
 
801
               value = '25*MH2**2*AMH2*MH25*math.cmath(Gf)')
 
802
        
 
803
        self.base_model.add_parameter(Gf2)
 
804
        self.assertEqual(nb_param+1,  len(self.base_model.parameters)) 
 
805
        #check that the expression of GH is correctly modified
 
806
        self.assertEqual(Gf2.value, '25*MH**2*AMH2*MH25*math.cmath(Gf__1)')
 
807
        self.assertEqual(Gf2.name, 'Gf2') 
 
808
        nb_param = nb_param+1        
 
809
        
 
810
        # MH250 is a completely new external parameter
 
811
        MH250 = Parameter(name = 'MH250',
 
812
               nature = 'external',
 
813
               type = 'real',
 
814
               value = 125,
 
815
               texname = '\\text{MH}',
 
816
               lhablock = 'MASS',
 
817
               lhacode = [ 250 ])
 
818
        self.base_model.add_parameter(MH250)
 
819
        self.assertEqual(nb_param+1,  len(self.base_model.parameters))         
 
820
        nb_param += 1
 
821
 
 
822
        # MH251 is a completely new external parameter with same name as MH250
 
823
        MH251 = Parameter(name = 'MH250',
 
824
               nature = 'external',
 
825
               type = 'real',
 
826
               value = 125,
 
827
               texname = '\\text{MH}',
 
828
               lhablock = 'MASS',
 
829
               lhacode = [ 251 ])
 
830
 
 
831
        self.base_model.add_parameter(MH251)
 
832
        self.assertEqual(nb_param+1,  len(self.base_model.parameters)) 
 
833
        self.assertEqual(self.base_model.old_new['MH250'], 'MH250__1')
 
834
        self.assertEqual(MH251.name, 'MH250__1')         
 
835
        nb_param += 1
 
836
 
 
837
                          
 
838
                          
 
839
    def test_couplings(self):
 
840
        
 
841
        nb_coup = len(self.base_model.couplings)
 
842
        
 
843
        
 
844
        GC_107 = Coupling(name = 'GC_107',
 
845
                  value = '(ee*complex(0,1)*complexconjugate(CKM3x2))/(sw*cmath.sqrt(2))',
 
846
                  order = {'QED':1})
 
847
        
 
848
        self.base_model.add_coupling(GC_107)
 
849
        self.assertEqual(nb_coup,  len(self.base_model.couplings))
 
850
        self.assertEqual(nb_coup,  len(self.sm.all_couplings))
 
851
        self.assertTrue(hasattr(GC_107, 'replace'))
 
852
        self.assertEqual(nb_coup,  len(self.sm.all_couplings))
 
853
 
 
854
        GC_107 = Coupling(name = 'GC_110',
 
855
                  value = '(ee*complex(0,1)*complexconjugate(CKM3x2))/(sw*cmath.sqrt(2))',
 
856
                  order = {'QED':1})
 
857
        
 
858
        self.base_model.add_coupling(GC_107)
 
859
        self.assertEqual(nb_coup,  len(self.base_model.couplings))
 
860
        self.assertEqual(nb_coup,  len(self.sm.all_couplings))
 
861
        self.assertTrue(hasattr(GC_107, 'replace')) 
 
862
        self.assertEqual(nb_coup,  len(self.sm.all_couplings)) 
 
863
        
 
864
        GC_107 = Coupling(name = 'GC_107',
 
865
                  value = '(ee*complex(0,1)*complexconjugate(CKM3x99))/(sw*cmath.sqrt(2))',
 
866
                  order = {'QED':1})
 
867
        
 
868
        self.base_model.add_coupling(GC_107)
 
869
        self.assertEqual(nb_coup+1,  len(self.base_model.couplings))
 
870
        self.assertEqual(nb_coup,  len(self.sm.all_couplings))
 
871
        self.assertFalse(hasattr(GC_107, 'replace'))        
 
872
        
 
873
    
 
874
    def test_interaction(self):
 
875
        
 
876
        GC_1 = Coupling(name = 'GC_1',
 
877
                  value = '(ee*complex(0,1)*complexconjugate(CKM3x100))/(sw*cmath.sqrt(2))',
 
878
                  order = {'QED':1})        
 
879
        self.base_model.add_coupling(GC_1)
 
880
        M5 = Parameter(name = 'M5',
 
881
               nature = 'external',
 
882
               type = 'real',
 
883
               value = 125,
 
884
               texname = '\\text{MH}',
 
885
               lhablock = 'MASS',
 
886
               lhacode = [ 5 ]) 
 
887
        W5 = Parameter(name = 'W5',
 
888
               nature = 'external',
 
889
               type = 'real',
 
890
               value = 125,
 
891
               texname = '\\text{MH}',
 
892
               lhablock = 'DECAY',
 
893
               lhacode = [ 5 ]) 
 
894
        self.base_model.add_parameter(M5)
 
895
        self.base_model.add_parameter(W5)
 
896
        
 
897
        L = Lorentz(name = 'FFS2',
 
898
               spins = [ 2, 2, 1 ],
 
899
               structure = 'Identity(2,1)')
 
900
        self.base_model.add_lorentz(L)
 
901
 
 
902
        B = Particle(pdg_code = 5,
 
903
             name = 'B',
 
904
             antiname = 'B~',
 
905
             spin = 1,
 
906
             color = 1,
 
907
             mass = M5,
 
908
             width = W5,
 
909
             texname = 'H',
 
910
             antitexname = 'H',
 
911
             charge = 0,
 
912
             GhostNumber = 0,
 
913
             LeptonNumber = 0,
 
914
             Y = 0) 
 
915
        self.base_model.add_particle(B)
 
916
        
 
917
        V_2 = Vertex(name = 'V_2',
 
918
             particles = [ B, B, B, B ],
 
919
             color = [ '1' ],
 
920
             lorentz = [ L ],
 
921
             couplings = {(0,0): GC_1})
 
922
 
 
923
        # check the size for avoiding border effect
 
924
        self.assertEqual(len(all_particles),1)
 
925
        self.assertEqual(len(self.mymodel.all_particles),1)
 
926
        self.assertEqual(len(self.mymodel.all_vertices),1)
 
927
        
 
928
        orig = len(self.base_model.vertices)
 
929
        self.base_model.add_interaction(V_2, self.mymodel)
 
930
        self.assertEqual(orig+1, len(self.base_model.vertices))
 
931
        added = self.base_model.vertices[-1]
 
932
        self.assertEqual(added.name, 'V_2__1')
 
933
        self.assertNotEqual(id(added.particles[0]), id(B))
 
934
        
 
935
        # check the size for avoiding border effect
 
936
        self.assertEqual(len(all_particles),1)
 
937
        self.assertEqual(len(self.mymodel.all_particles),1)
 
938
        self.assertEqual(len(self.mymodel.all_vertices),1)        
 
939
        
 
940
         
 
941
        
 
942
        ## add a second time the interaction to check that she is not added
 
943
        orig = len(self.base_model.vertices)
 
944
        self.base_model.add_interaction(V_2, self.mymodel)
 
945
        self.assertEqual(orig, len(self.base_model.vertices))
 
946
        
 
947
        ## check that the sm model is not impacted
 
948
        self.assertNotEqual(orig, len(self.sm.all_vertices))
 
949
 
 
950
 
 
951
    def test_identify_particle(self):
 
952
        
 
953
        GC_1 = Coupling(name = 'GC_1',
 
954
                  value = '(ee*complex(0,1)*complexconjugate(CKM3x100))/(sw*cmath.sqrt(2))',
 
955
                  order = {'QED':1})        
 
956
        #self.base_model.add_coupling(GC_1)
 
957
        M5 = Parameter(name = 'M5',
 
958
               nature = 'external',
 
959
               type = 'real',
 
960
               value = 125,
 
961
               texname = '\\text{MH}',
 
962
               lhablock = 'MASS',
 
963
               lhacode = [ 105 ]) 
 
964
        W5 = Parameter(name = 'W5',
 
965
               nature = 'external',
 
966
               type = 'real',
 
967
               value = 125,
 
968
               texname = '\\text{MH}',
 
969
               lhablock = 'DECAY',
 
970
               lhacode = [ 105 ]) 
 
971
        #self.base_model.add_parameter(M5)
 
972
        #self.base_model.add_parameter(W5)
 
973
        
 
974
        L = Lorentz(name = 'FFS2',
 
975
               spins = [ 2, 2, 1 ],
 
976
               structure = 'Identity(2,1)')
 
977
        #self.base_model.add_lorentz(L)
 
978
 
 
979
        B = Particle(pdg_code = 105,
 
980
             name = 'B',
 
981
             antiname = 'B',
 
982
             spin = 1,
 
983
             color = 1,
 
984
             mass = M5,
 
985
             width = W5,
 
986
             texname = 'H',
 
987
             antitexname = 'H',
 
988
             charge = 0,
 
989
             GhostNumber = 0,
 
990
             LeptonNumber = 0,
 
991
             Y = 0) 
 
992
        #self.base_model.add_particle(B)
 
993
        
 
994
        V_2 = Vertex(name = 'V_2',
 
995
             particles = [ B, B, B, B ],
 
996
             color = [ '1' ],
 
997
             lorentz = [ L ],
 
998
             couplings = {(0,0): GC_1})
 
999
        self.mymodel.__path__ = '.'
 
1000
        self.base_model.add_model(self.mymodel, identify_particles={'B':'H'})
 
1001
        
 
1002
        # check that the B object still has is name/pdg_code
 
1003
        self.assertEqual(B.pdg_code, 105)
 
1004
        self.assertEqual(B.name, 'B')
 
1005
        # check that the original model still has the H particles
 
1006
        model = ufomodels.load_model(self.sm_path)
 
1007
        particles_name = [p.name for p in model.all_particles]
 
1008
        self.assertTrue('H' in particles_name)
 
1009
        self.assertFalse('B' in particles_name)
 
1010
        # check the mass
 
1011
        parameters_name = [p.name for p in model.all_parameters]
 
1012
        self.assertTrue('MH' in parameters_name)
 
1013
        self.assertFalse('M5' in parameters_name)        
 
1014
        
 
1015
        
 
1016
        
 
1017
        
 
1018
        
 
1019