Merge lp:~maddevelopers/mg5amcnlo/2.6.3_optimizenlomodel into lp:~mg5core2/mg5amcnlo/2.6.3

Proposed by Olivier Mattelaer
Status: Merged
Merged at revision: 314
Proposed branch: lp:~maddevelopers/mg5amcnlo/2.6.3_optimizenlomodel
Merge into: lp:~mg5core2/mg5amcnlo/2.6.3
Diff against target: 1284 lines (+672/-101)
16 files modified
UpdateNotes.txt (+11/-1)
aloha/aloha_writers.py (+21/-6)
aloha/create_aloha.py (+2/-3)
madgraph/loop/loop_helas_objects.py (+1/-2)
madgraph/various/misc.py (+2/-1)
mg5decay/decay_objects.py (+1/-1)
models/import_ufo.py (+281/-32)
tests/acceptance_tests/test_model_equivalence.py (+5/-2)
tests/input_files/IOTestsComparison/TestCmdMatchBox/MatchBoxOutput/%TEST%SubProcesses%P0_wpwm_wpwm%matrix.f (+8/-8)
tests/parallel_tests/test_ML5.py (+1/-1)
tests/parallel_tests/test_ML5MSSMQCD.py (+1/-1)
tests/parallel_tests/test_aloha.py (+168/-2)
tests/unit_tests/iolibs/test_export_v4.py (+1/-1)
tests/unit_tests/iolibs/test_helas_call_writers.py (+30/-30)
tests/unit_tests/various/test_decay.py (+2/-2)
tests/unit_tests/various/test_import_ufo.py (+137/-8)
To merge this branch: bzr merge lp:~maddevelopers/mg5amcnlo/2.6.3_optimizenlomodel
Reviewer Review Type Date Requested Status
Valentin Hirschi (community) Approve
Review via email: mp+346864@code.launchpad.net

Commit message

1) include a analyze of the model at (first) loading time to merge multiple lorentz structure in a single one if they have the same coupling (which allows better optimization at ALOHA level and cleaner code)

2) if ALOHA name, use a hash method to keep it short (will be problematic for debugging since the name is machine dependent)

3) improve test suite (and fixed a bug associated to get_custom_propa)

To post a comment you must log in.
283. By olivier-mattelaer

merge with 2.6.3

284. By olivier-mattelaer

also optimise for ident coupling (here up to a sign) after restriction

Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :

I've continued the work in model optimization in the context of restricted model

1) redo the above work of creating new lorentz structure for identified coupling.
2) Identify opposite sign coupling and keep only one of the two.
3) Doing the same as 1 but also for opposite sign coupling. This is very helpfull to avoid numerical inaccuracy in some complex model (complex spin 3/2 for example)

I'm running all the tests (I obviously add some at the same time) and then I will push this.
So please do not start this review right now.

Cheers,

Olivier

Revision history for this message
Valentin Hirschi (valentin-hirschi) wrote :

Ok, I'll wait for your go-ahead then.

285. By olivier-mattelaer

make the code pass all unittest/acceptest (including fixing side effects)

286. By olivier-mattelaer

fixing tests associated to the model optimization

Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :

Hi,

OK this seems quite stable now.
I'm just a bit worried that the parallel test might not be complete enough to detect issue here.

I think that such changes can be really important for complex model (in term of speed/precision).
But such improvement required complex model but this makes the possibility to not detect the introduction of subtle bugs (which will not be detected via unittest/...).

If you have an idea of parallel test (i.e. model/process) this would be great.

Cheers,

Olivier

Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :

Hi,

I have tested that setting the merged R2 for gggg to zero was leading to the following difference to the g g > g g [virt=QCD]:
 Finite = -6.6634187771890723e+01 [result in 2.6.3 and in this branch]
to
Finite = -6.6714876289454040e+01 [hack code to set this contribution to 0]

So we have at least that parralel test which is sensitive to such modification so we should be safe here.

Cheers,

Olivier

287. By olivier-mattelaer

merge with latest 2.6.3

Revision history for this message
Valentin Hirschi (valentin-hirschi) wrote :

Hi Olivier,

As I wrote on Skype, I think the coverage of parallel tests of MadLoop5 for
the SM is really exhaustive (complex-mass scheme excluded however).

Cheers,

On Fri, Jun 1, 2018 at 2:52 PM, Olivier Mattelaer <
<email address hidden>> wrote:

> Hi,
>
> I have tested that setting the merged R2 for gggg to zero was leading to
> the following difference to the g g > g g [virt=QCD]:
> Finite = -6.6634187771890723e+01 [result in 2.6.3 and in this branch]
> to
> Finite = -6.6714876289454040e+01 [hack code to set this contribution
> to 0]
>
> So we have at least that parralel test which is sensitive to such
> modification so we should be safe here.
>
>
> Cheers,
>
> Olivier
> --
> https://code.launchpad.net/~maddevelopers/mg5amcnlo/2.6.3_
> optimizenlomodel/+merge/346864
> You are requested to review the proposed merge of
> lp:~maddevelopers/mg5amcnlo/2.6.3_optimizenlomodel into
> lp:~mg5core2/mg5amcnlo/2.6.3.
>

--
Valentin

288. By olivier-mattelaer

fixing issue with the mssm model

Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :

Hi,

I plan to release 2.6.3, should I understand that this is not going to be in 2.6.3.
(I do not care you were the one pushing for it)

Cheers,

Olivier

Revision history for this message
Valentin Hirschi (valentin-hirschi) wrote :

Hi Olivier,

Thanks a lot for this improvement! I checked that the problematic model with long aloha name now goes through fine with identical results as before.
I also tried a complicated 2->4 electroweak loop process which again yielded identical results.
This, together with the existing other parallel tests and the additional ones you've put in place should give us confidence that this can be merged in 2.6.3.

I don't have any smart comment on the code (I also don't know ALOHA well enough), but I was wondering if there would be a benefit in having a special aloha mode which defines a unique different aloha routine for each vertex with definite with a definite colour structure.
This way you could maximise the computational efficiency of the Lorentz part of each vertex in the model. That would of course be inefficient in terms of the size of ALOHA output, but this may sometimes be a trade-of you would be willing to make.
I'm thinking of this now, because I feel that the implementation of the mode described above would have some similarities with what you just implemented.

Anyway, I approve this merge.

review: Approve
Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :

Hi,

> I don't have any smart comment on the code (I also don't know ALOHA well enough), but I was wondering if there would be a benefit in having a special aloha mode which defines a unique different aloha routine for each vertex with definite with a definite colour structure.
> This way you could maximise the computational efficiency of the Lorentz part of each vertex in the model. That would of course be inefficient in terms of the size of ALOHA output, but this may sometimes be a trade-of you would be willing to make.
> I'm thinking of this now, because I feel that the implementation of the mode described above would have some similarities with what you just implemented.

Can you explain more? I do not see the difference that you propose compare to what is in place now?

Cheers,

Olivier

> On 12 Jun 2018, at 11:11, Valentin Hirschi <email address hidden> wrote:
>
> Review: Approve
>
> Hi Olivier,
>
> Thanks a lot for this improvement! I checked that the problematic model with long aloha name now goes through fine with identical results as before.
> I also tried a complicated 2->4 electroweak loop process which again yielded identical results.
> This, together with the existing other parallel tests and the additional ones you've put in place should give us confidence that this can be merged in 2.6.3.
>
> I don't have any smart comment on the code (I also don't know ALOHA well enough), but I was wondering if there would be a benefit in having a special aloha mode which defines a unique different aloha routine for each vertex with definite with a definite colour structure.
> This way you could maximise the computational efficiency of the Lorentz part of each vertex in the model. That would of course be inefficient in terms of the size of ALOHA output, but this may sometimes be a trade-of you would be willing to make.
> I'm thinking of this now, because I feel that the implementation of the mode described above would have some similarities with what you just implemented.
>
> Anyway, I approve this merge.
> --
> https://code.launchpad.net/~maddevelopers/mg5amcnlo/2.6.3_optimizenlomodel/+merge/346864
> Your team MadDevelopers is subscribed to branch lp:~maddevelopers/mg5amcnlo/2.6.3_optimizenlomodel.

Revision history for this message
Valentin Hirschi (valentin-hirschi) wrote :

Nevermind, I worked it out again and realised what you did is basically the best you can get already. In general, if you have this interaction:

particles = [p.A, p.B, p.C]
color = ['C1','C2']
lorentz = [L.LA, L.LB, L.LC]
couplings = {
(0,0): C.G1, (0,1): C.G2, (0,2): C.G3,
(1,0): C.G4, (1,1): C.G5
}

you can generalise your procedure by defining the following two Lorentz structure being basically:

L.LA + (C.G2/C.G1)*L.B + (C.G3/C.G1)*L.C

and

L.LA + (C.G5/C.G4)*L.B

But I now realise that it's pointless/hard to do this if (C.G<i>/C.G<j>)=K , with K having model parametric dependence. You implemented this for K= +/-1, and in principle it could be extended to any integer, but that has very little value in practice indeed.
So I agree, what you did is already basically the best you can get already.

Cheers

Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :

Hi,

To be complete I detect K=1
only if it is analytically 1 (and trivially so, i.e. if both use the same name

The case K=+/-1 is tackle ONLY for restricted model and the comparison is done numerically.
I would not like to pass to numerical comparison for ALL integer since it is too dangerous to have false positif.
Also doing K=+/-2 differs from the actual description of the restrict_model (but thate

Now it would make sense to look at the K as any integer at the analytical level.
But I'm slightly worried about the time impact (at the same time this is only the first time since it is save in the pkl). I think i will test something with string comparison:

something like:

couplings.order(key=len)
for i in range(len(couplings)):
 for j in range(i+1, len(couplings))
  c1, c2 = couplings[i], couplings[j]
  c2.expr = c2.expr.replace(str(c1), c1.name)

Then a simple regular expression should be able to detect case where

c2.expr=" 2 * GC_1"

What do you think?

Cheers,

Olivier

> On 12 Jun 2018, at 16:31, Valentin Hirschi <email address hidden> wrote:
>
> Nevermind, I worked it out again and realised what you did is basically the best you can get already. In general, if you have this interaction:
>
> particles = [p.A, p.B, p.C]
> color = ['C1','C2']
> lorentz = [L.LA, L.LB, L.LC]
> couplings = {
> (0,0): C.G1, (0,1): C.G2, (0,2): C.G3,
> (1,0): C.G4, (1,1): C.G5
> }
>
> you can generalise your procedure by defining the following two Lorentz structure being basically:
>
> L.LA + (C.G2/C.G1)*L.B + (C.G3/C.G1)*L.C
>
> and
>
> L.LA + (C.G5/C.G4)*L.B
>
> But I now realise that it's pointless/hard to do this if (C.G<i>/C.G<j>)=K , with K having model parametric dependence. You implemented this for K= +/-1, and in principle it could be extended to any integer, but that has very little value in practice indeed.
> So I agree, what you did is already basically the best you can get already.
>
> Cheers
>
> --
> https://code.launchpad.net/~maddevelopers/mg5amcnlo/2.6.3_optimizenlomodel/+merge/346864
> Your team MadDevelopers is subscribed to branch lp:~maddevelopers/mg5amcnlo/2.6.3_optimizenlomodel.

Revision history for this message
Valentin Hirschi (valentin-hirschi) wrote :
Download full text (3.2 KiB)

Hi,

On Tue, Jun 12, 2018 at 10:00 PM, Olivier Mattelaer <
<email address hidden>> wrote:

> Hi,
>
> To be complete I detect K=1
> only if it is analytically 1 (and trivially so, i.e. if both use the same
> name
>

Mhh, It may be nice to cover K=-1 too no?

> The case K=+/-1 is tackle ONLY for restricted model and the comparison is
> done numerically.
> I would not like to pass to numerical comparison for ALL integer since it
> is too dangerous to have false positif.
> Also doing K=+/-2 differs from the actual description of the
> restrict_model (but thate
>

I agree completely here, such false positive would be really hard to track
down.

>
> Now it would make sense to look at the K as any integer at the analytical
> level.
> But I'm slightly worried about the time impact (at the same time this is
> only the first time since it is save in the pkl). I think i will test
> something with string comparison:
>
> something like:
>
> couplings.order(key=len)
> for i in range(len(couplings)):
> for j in range(i+1, len(couplings))
> c1, c2 = couplings[i], couplings[j]
> c2.expr = c2.expr.replace(str(c1), c1.name)
>
> Then a simple regular expression should be able to detect case where
>
> c2.expr=" 2 * GC_1"
>
> What do you think?
>

That could work I suppose, but I think that in practice it makes very
little difference because most of the model will benefit from
simplifications where K is -1 or 1.
So in my opinion, it's not worth the effort:

PS: checkout sympy, it's nice to keep that option in mind for possible
future applications one day (though for anything heavy, it would be better
to wait for the upcoming python bindings of the new version of FORM).

Cheers,

>
> Cheers,
>
> Olivier
>
> > On 12 Jun 2018, at 16:31, Valentin Hirschi <email address hidden>
> wrote:
> >
> > Nevermind, I worked it out again and realised what you did is basically
> the best you can get already. In general, if you have this interaction:
> >
> > particles = [p.A, p.B, p.C]
> > color = ['C1','C2']
> > lorentz = [L.LA, L.LB, L.LC]
> > couplings = {
> > (0,0): C.G1, (0,1): C.G2, (0,2): C.G3,
> > (1,0): C.G4, (1,1): C.G5
> > }
> >
> > you can generalise your procedure by defining the following two Lorentz
> structure being basically:
> >
> > L.LA + (C.G2/C.G1)*L.B + (C.G3/C.G1)*L.C
> >
> > and
> >
> > L.LA + (C.G5/C.G4)*L.B
> >
> > But I now realise that it's pointless/hard to do this if
> (C.G<i>/C.G<j>)=K , with K having model parametric dependence. You
> implemented this for K= +/-1, and in principle it could be extended to any
> integer, but that has very little value in practice indeed.
> > So I agree, what you did is already basically the best you can get
> already.
> >
> > Cheers
> >
> > --
> > https://code.launchpad.net/~maddevelopers/mg5amcnlo/2.6.3_
> optimizenlomodel/+merge/346864
> > Your team MadDevelopers is subscribed to branch
> lp:~maddevelopers/mg5amcnlo/2.6.3_optimizenlomodel.
>
>
> --
> https://code.launchpad.net/~maddevelopers/mg5amcnlo/2.6.3_
> optimizenlomodel/+merge/346864
> You are reviewing the proposed merge of lp:~maddevelopers/mg5amcnlo/2.6.3_optimizenlomodel
> into lp:~mg5core2/mg5...

Read more...

Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :
Download full text (3.9 KiB)

Mhh, It may be nice to cover K=-1 too no?

Nice yes, but quite heavy.
(ALOHA itself will be quite slow for such task,
 yacc and lex are a fast enough solution but quite heavy to implement.
regular expression might be easy enough but quite slow.

The best would be that such identification be part of the UFO model and not something that we have to discover...

This is quite hard since you have case like
a/(b+c) + c + (d+ e)/f
and the opposite
-a/(b+c) - c + (d+ e)/(-f)
(ok I'm slightly complexify what we will face but the problem is there)

Cheers,

Olivier

On 12 Jun 2018, at 22:27, Valentin Hirschi <<email address hidden><mailto:<email address hidden>>> wrote:

Hi,

On Tue, Jun 12, 2018 at 10:00 PM, Olivier Mattelaer <
<email address hidden><mailto:<email address hidden>>> wrote:

Hi,

To be complete I detect K=1
only if it is analytically 1 (and trivially so, i.e. if both use the same
name

Mhh, It may be nice to cover K=-1 too no?

The case K=+/-1 is tackle ONLY for restricted model and the comparison is
done numerically.
I would not like to pass to numerical comparison for ALL integer since it
is too dangerous to have false positif.
Also doing K=+/-2 differs from the actual description of the
restrict_model (but thate

I agree completely here, such false positive would be really hard to track
down.

Now it would make sense to look at the K as any integer at the analytical
level.
But I'm slightly worried about the time impact (at the same time this is
only the first time since it is save in the pkl). I think i will test
something with string comparison:

something like:

couplings.order(key=len)
for i in range(len(couplings)):
       for j in range(i+1, len(couplings))
               c1, c2 = couplings[i], couplings[j]
               c2.expr = c2.expr.replace(str(c1), c1.name)

Then a simple regular expression should be able to detect case where

c2.expr=" 2 * GC_1"

What do you think?

That could work I suppose, but I think that in practice it makes very
little difference because most of the model will benefit from
simplifications where K is -1 or 1.
So in my opinion, it's not worth the effort:

PS: checkout sympy, it's nice to keep that option in mind for possible
future applications one day (though for anything heavy, it would be better
to wait for the upcoming python bindings of the new version of FORM).

Cheers,

Cheers,

Olivier

On 12 Jun 2018, at 16:31, Valentin Hirschi <<email address hidden><mailto:<email address hidden>>>
wrote:

Nevermind, I worked it out again and realised what you did is basically
the best you can get already. In general, if you have this interaction:

particles = [p.A, p.B, p.C]
color = ['C1','C2']
lorentz = [L.LA, L.LB, L.LC]
couplings = {
(0,0): C.G1, (0,1): C.G2, (0,2): C.G3,
(1,0): C.G4, (1,1): C.G5
}

you can generalise your procedure by defining the following two Lorentz
structure being basically:

L.LA + (C.G2/C.G1)*L.B + (C.G3/C.G1)*L.C

and

L.LA + (C.G5/C.G4)*L.B

But I now realise that it's pointless/hard to do this if
(C.G<i>/C.G<j>)=K , with K having model parametric dependence. You
implemented this for K= +/-1, and in principle it could be extended t...

Read more...

Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :
Download full text (7.3 KiB)

I have run the following code on the loop_sm model.
It basically strips all the + and - of any expression and identifies equal string.
This is obviously not save but instructive of the issue to handle:

       #check opposite couplings
        for key in self.couplings:
            iden_list = collections.defaultdict(list)
            for C in self.couplings[key]:
                #misc.sprint(C.name, C.expr)
                expr = re.sub(r'\s*[+-]\s*', '', C.expr)
                iden_list[expr].append(C)
            to_lookat = [ str([(c.name,c.expr) for c in iden_list[k]]) for k in iden_list if len(iden_list[k])>1]
            misc.sprint('\n'.join(to_lookat))

I put below the result of the print statement. (and put in bold the false positif expression)

DEBUG: '\n'.join(to_lookat) =
 [('GC_1009', 'ee__exp__2/(2.*cw)'), ('GC_1007', '-ee__exp__2/(2.*cw)')]
[('GC_1091', 'ym'), ('GC_1090', '-ym')]
[('GC_1087', 'ye'), ('GC_1086', '-ye')]
[('GC_21', '-(cw*ee*complexi)/(2.*sw)'), ('GC_22', '(cw*ee*complexi)/(2.*sw)')]
[('GC_1039', '(ee*complexi)/(2.*sw)'), ('GC_1038', '-(ee*complexi)/(2.*sw)')]
[('GC_28', '(cw*ee*complexi)/(2.*sw) + (ee*complexi*sw)/(2.*cw)'), ('GC_1061', '-(cw*ee*complexi)/(2.*sw) + (ee*complexi*sw)/(2.*cw)')]
[('GC_10', '(ee__exp__2*complexi)/(2.*sw__exp__2)'), ('GC_1034', '(ee__exp__2*complexi)/(2.*sw__exp__2)')]
[('GC_3', '-(ee*complexi)'), ('GC_1003', '-(ee*complexi)')]
[('GC_1097', 'ytau'), ('GC_1096', '-ytau')]
[('GC_1067', '(ee__exp__2*v)/(2.*cw)'), ('GC_1066', '-(ee__exp__2*v)/(2.*cw)')]
[('GC_29', 'ee__exp__2*complexi + (cw__exp__2*ee__exp__2*complexi)/(2.*sw__exp__2) + (ee__exp__2*complexi*sw__exp__2)/(2.*cw__exp__2)'), ('GC_1065', 'ee__exp__2*complexi + (cw__exp__2*ee__exp__2*complexi)/(2.*sw__exp__2) + (ee__exp__2*complexi*sw__exp__2)/(2.*cw__exp__2)')]
[('GC_HHHH', '-6*complexi*lam'), ('GC_1033', '-6*complexi*lam')]
[('GC_1054', '-ee__exp__2/(2.*sw)'), ('GC_1056', 'ee__exp__2/(2.*sw)')]
[('GC_1074', '-(ee__exp__2*v)/(2.*sw)'), ('GC_1075', '(ee__exp__2*v)/(2.*sw)')] [import_ufo.py at line 1643]

 [('R2GC_141_50', '-(complexi*G__exp__4)/(16.*cmath.pi**2)'), ('R2GC_142_52', '(complexi*G__exp__4)/(16.*cmath.pi**2)')]
[('R2GC_137_43', '(complexi*G__exp__4)/(192.*cmath.pi**2)'), ('R2GC_138_45', '-(complexi*G__exp__4)/(192.*cmath.pi**2)')]
[('R2GC_137_44', '-(complexi*G__exp__4)/(64.*cmath.pi**2)'), ('R2GC_138_46', '(complexi*G__exp__4)/(64.*cmath.pi**2)')]
[('R2GC_141_51', '(-7*complexi*G__exp__4)/(32.*cmath.pi**2)'), ('R2GC_142_53', '(7*complexi*G__exp__4)/(32.*cmath.pi**2)')] [import_ufo.py at line 1643]

So we can
1) see how many different way a coupling can be different due to the sign
2) that model can have fully identical expression of coupling but different name (WHY?)
3) that the above method is actually not complete (it miss GC_UV couplings and GC_R2 identification)
4) sone coupling name are weird

Are we still using the hand written model?
Would not make sense to pass to FeynRules model (and to run the above script to manually optimise it?

Olivier

On 12 Jun 2018, at 22:45, Olivier Mattelaer <<email address hidden><mailto:<email address hidden>>> wrote:

Mhh, It may be nice to cover K=-1 to...

Read more...

Revision history for this message
Valentin Hirschi (valentin-hirschi) wrote :
Download full text (9.6 KiB)

Hi Olivier,

On Wed, Jun 13, 2018 at 10:21 AM, Olivier Mattelaer <
<email address hidden>> wrote:

> I have run the following code on the loop_sm model.
> It basically strips all the + and - of any expression and identifies equal
> string.
> This is obviously not save but instructive of the issue to handle:
>
> #check opposite couplings
> for key in self.couplings:
> iden_list = collections.defaultdict(list)
> for C in self.couplings[key]:
> #misc.sprint(C.name, C.expr)
> expr = re.sub(r'\s*[+-]\s*', '', C.expr)
> iden_list[expr].append(C)
> to_lookat = [ str([(c.name,c.expr) for c in iden_list[k]])
> for k in iden_list if len(iden_list[k])>1]
> misc.sprint('\n'.join(to_lookat))
>
> I put below the result of the print statement. (and put in bold the false
> positif expression)
>
> DEBUG: '\n'.join(to_lookat) =
> [('GC_1009', 'ee__exp__2/(2.*cw)'), ('GC_1007', '-ee__exp__2/(2.*cw)')]
> [('GC_1091', 'ym'), ('GC_1090', '-ym')]
> [('GC_1087', 'ye'), ('GC_1086', '-ye')]
> [('GC_21', '-(cw*ee*complexi)/(2.*sw)'), ('GC_22',
> '(cw*ee*complexi)/(2.*sw)')]
> [('GC_1039', '(ee*complexi)/(2.*sw)'), ('GC_1038',
> '-(ee*complexi)/(2.*sw)')]
> [('GC_28', '(cw*ee*complexi)/(2.*sw) + (ee*complexi*sw)/(2.*cw)'),
> ('GC_1061', '-(cw*ee*complexi)/(2.*sw) + (ee*complexi*sw)/(2.*cw)')]
> [('GC_10', '(ee__exp__2*complexi)/(2.*sw__exp__2)'), ('GC_1034',
> '(ee__exp__2*complexi)/(2.*sw__exp__2)')]
> [('GC_3', '-(ee*complexi)'), ('GC_1003', '-(ee*complexi)')]
> [('GC_1097', 'ytau'), ('GC_1096', '-ytau')]
> [('GC_1067', '(ee__exp__2*v)/(2.*cw)'), ('GC_1066',
> '-(ee__exp__2*v)/(2.*cw)')]
> [('GC_29', 'ee__exp__2*complexi + (cw__exp__2*ee__exp__2*complexi)/(2.*sw__exp__2)
> + (ee__exp__2*complexi*sw__exp__2)/(2.*cw__exp__2)'), ('GC_1065',
> 'ee__exp__2*complexi + (cw__exp__2*ee__exp__2*complexi)/(2.*sw__exp__2) +
> (ee__exp__2*complexi*sw__exp__2)/(2.*cw__exp__2)')]
> [('GC_HHHH', '-6*complexi*lam'), ('GC_1033', '-6*complexi*lam')]
> [('GC_1054', '-ee__exp__2/(2.*sw)'), ('GC_1056', 'ee__exp__2/(2.*sw)')]
> [('GC_1074', '-(ee__exp__2*v)/(2.*sw)'), ('GC_1075',
> '(ee__exp__2*v)/(2.*sw)')] [import_ufo.py at line 1643]
>
> [('R2GC_141_50', '-(complexi*G__exp__4)/(16.*cmath.pi**2)'),
> ('R2GC_142_52', '(complexi*G__exp__4)/(16.*cmath.pi**2)')]
> [('R2GC_137_43', '(complexi*G__exp__4)/(192.*cmath.pi**2)'),
> ('R2GC_138_45', '-(complexi*G__exp__4)/(192.*cmath.pi**2)')]
> [('R2GC_137_44', '-(complexi*G__exp__4)/(64.*cmath.pi**2)'),
> ('R2GC_138_46', '(complexi*G__exp__4)/(64.*cmath.pi**2)')]
> [('R2GC_141_51', '(-7*complexi*G__exp__4)/(32.*cmath.pi**2)'),
> ('R2GC_142_53', '(7*complexi*G__exp__4)/(32.*cmath.pi**2)')]
> [import_ufo.py at line 1643]
>
>
> So we can
> 1) see how many different way a coupling can be different due to the sign
>

As we discussed on Skype, it is probably a bit hard to do this with string
parsing. For example the ratio of this pair:

[('GC_28', '(cw*ee*complexi)/(2.*sw) + (ee*complexi*sw)/(2.*cw)'),
('GC_1061', '-(cw*ee*complexi)/(2.*sw) + (ee*complexi*sw)/(2.*cw)')]

is actually *not* -1.
I think here the simplest thing to do is t...

Read more...

Revision history for this message
Rikkert Frederix (frederix) wrote :

Guys,

Wouldn't it make more sense to check this numerically? I.e., assign some random numbers to all the terms, compute the ratio between all the couplings and repeat this a couple of times. If the ratio between couplings doesn't change up to machine precision for several choices of the random numbers consider them equal with the (numerical) proportionality factor given by the ratio?

Cheers,
Rik

Revision history for this message
Valentin Hirschi (valentin-hirschi) wrote :

Hi Olivier,

Sure, the numerical approach is one possibility and we discussed it a bit
already in the previous emails of this thread.
We were then worried that we could hit false positive, and you are saying
that we could reduce this risk to an insignificant number by doing it
repeatedly with arbitrary assignment of the external parameters.
I suppose this could work indeed (I think it shouldn't be *too* hard to
implement, but Olivier should confirm).

Of course, when using a restriction file when loading the model, we should
only do this using the specified input parameters, as they may exhibit
extra simplifications that are ok to use, at least for K=1.
But then we could also combine this some other ratios detected with your
method Rik, as those would be safe to use anyway.

I don't think this is too crucial, so we should only go for simple
solutions if there are some, or none if too complicated.

Cheers

On Wed, Jun 13, 2018 at 2:26 PM, Rikkert Frederix <email address hidden>
wrote:

> Guys,
>
> Wouldn't it make more sense to check this numerically? I.e., assign some
> random numbers to all the terms, compute the ratio between all the
> couplings and repeat this a couple of times. If the ratio between couplings
> doesn't change up to machine precision for several choices of the random
> numbers consider them equal with the (numerical) proportionality factor
> given by the ratio?
>
> Cheers,
> Rik
>
> --
> https://code.launchpad.net/~maddevelopers/mg5amcnlo/2.6.3_
> optimizenlomodel/+merge/346864
> You are reviewing the proposed merge of lp:~maddevelopers/mg5amcnlo/2.6.3_optimizenlomodel
> into lp:~mg5core2/mg5amcnlo/2.6.3.
>

--
Valentin

Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :
Download full text (4.9 KiB)

Hi,

To merge this to 2.6.3, we have to keep such change minimal for the moment.

So I have had the bare minimum to the current status.
This is
a) detect fully identical expression --same string-- and merge them
b) remove couplings exactly equals to zero (no point to keep them obviously)

This is pretty minimal and quite save.
for loop_sm this does not do anything in the unitary gauge. (but make few simplification in the feynman gauge)
for the loop_qcd_qed_sm, they are 148 coupling equals to zero, so this makes some cool cleaning.

Now we can also not push this in 2.6.3 to be save. They are nothing crucial in such change and can easily wait months to be include.

Cheers,

Olivier

=== modified file 'models/import_ufo.py'
--- models/import_ufo.py 2018-06-01 08:46:21 +0000
+++ models/import_ufo.py 2018-06-13 15:01:47 +0000
@@ -14,7 +14,7 @@
 ################################################################################
 """ How to import a UFO model to the MG5 format """

-
+import collections
 import fractions
 import logging
 import os
@@ -530,8 +530,10 @@
                 self.add_CTinteraction(interaction_info, color_info)

- for interaction in self.interactions:
+ for interaction in list(self.interactions):
             self.optimise_interaction(interaction)
+ if not interaction['couplings']:
+ self.interactions.remove(interaction)

         self.model.set('conserved_charge', self.conservecharge)
@@ -584,6 +586,32 @@

     def optimise_interaction(self, interaction):

+
+ # Check if two couplings have exactly the same definition.
+ # If so replace one by the other
+ if not hasattr(self, 'iden_couplings'):
+ coups = collections.defaultdict(list)
+ coups['0'].append('ZERO')
+ for coupling in self.ufomodel.all_couplings:
+ #if isinstance(coupling.value, str):
+ coups[str(coupling.value)].append( coupling.name)
+
+ self.iden_couplings = {}
+ for idens in [c for c in coups.values() if len(c)>1]:
+ for i in range(1, len(idens)):
+ self.iden_couplings[idens[i]] = idens[0]
+
+ # apply the replacement by identical expression
+ for key, coup in list(interaction['couplings'].items()):
+ if coup in self.iden_couplings:
+ interaction['couplings'][key] = self.iden_couplings[coup]
+ if interaction['couplings'][key] == 'ZERO':
+ del interaction['couplings'][key]
+
+
+
+
+
         # we want to check if the same coupling is used for two lorentz strucutre
         # for the same color structure.
         to_lor = {}
@@ -1807,9 +1835,9 @@
         self.remove_couplings(self.del_coup)

         # modify interaction to avoid to have identical coupling with different lorentz
- for interaction in self.get('interactions'):
+ for interaction in list(self.get('interactions')):
             self.optimise_interaction(interaction)
-
+
         # deal with parameters
         parameters = self.detect_special_parameters()
         self.fix_parameter_values(*parameters, simplify=rm_parameter,

On 13 Jun 2018...

Read more...

Revision history for this message
Valentin Hirschi (valentin-hirschi) wrote :
Download full text (5.7 KiB)

Hi Olivier

On Wed, Jun 13, 2018 at 5:09 PM, Olivier Mattelaer <
<email address hidden>> wrote:

> Hi,
>
> To merge this to 2.6.3, we have to keep such change minimal for the moment.
>
> So I have had the bare minimum to the current status.
> This is
> a) detect fully identical expression --same string-- and merge them
> b) remove couplings exactly equals to zero (no point to keep them
> obviously)
>
> This is pretty minimal and quite save.
> for loop_sm this does not do anything in the unitary gauge. (but make few
> simplification in the feynman gauge)
> for the loop_qcd_qed_sm, they are 148 coupling equals to zero, so this
> makes some cool cleaning.
>
> Now we can also not push this in 2.6.3 to be save. They are nothing
> crucial in such change and can easily wait months to be include.
>

I would need this to be pushed in 2.6.3 for this model to work:

http://feynrules.irmp.ucl.ac.be/wiki/GGG

So could you please put this in the 2.6.3 release ? (the model above in
principle only need the long name fix of course)

Cheers

>
> Cheers,
>
> Olivier
>
>
> === modified file 'models/import_ufo.py'
> --- models/import_ufo.py 2018-06-01 08:46:21 +0000
> +++ models/import_ufo.py 2018-06-13 15:01:47 +0000
> @@ -14,7 +14,7 @@
> ############################################################
> ####################
> """ How to import a UFO model to the MG5 format """
>
> -
> +import collections
> import fractions
> import logging
> import os
> @@ -530,8 +530,10 @@
> self.add_CTinteraction(interaction_info, color_info)
>
>
> - for interaction in self.interactions:
> + for interaction in list(self.interactions):
> self.optimise_interaction(interaction)
> + if not interaction['couplings']:
> + self.interactions.remove(interaction)
>
>
> self.model.set('conserved_charge', self.conservecharge)
> @@ -584,6 +586,32 @@
>
> def optimise_interaction(self, interaction):
>
> +
> + # Check if two couplings have exactly the same definition.
> + # If so replace one by the other
> + if not hasattr(self, 'iden_couplings'):
> + coups = collections.defaultdict(list)
> + coups['0'].append('ZERO')
> + for coupling in self.ufomodel.all_couplings:
> + #if isinstance(coupling.value, str):
> + coups[str(coupling.value)].append( coupling.name)
> +
> + self.iden_couplings = {}
> + for idens in [c for c in coups.values() if len(c)>1]:
> + for i in range(1, len(idens)):
> + self.iden_couplings[idens[i]] = idens[0]
> +
> + # apply the replacement by identical expression
> + for key, coup in list(interaction['couplings'].items()):
> + if coup in self.iden_couplings:
> + interaction['couplings'][key] = self.iden_couplings[coup]
> + if interaction['couplings'][key] == 'ZERO':
> + del interaction['couplings'][key]
> +
> +
> +
> +
> +
> # we want to check if the same coupling is used for two lorentz
> strucutre
> # for the same color structure.
> to_lor = {}
> @@...

Read more...

Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :
Download full text (6.1 KiB)

Hi,

I do not understand your mail,
This has nothing to do with 2.6.3
http://feynrules.irmp.ucl.ac.be/wiki/GGG

If you want me to add the model to the database this is done automatically for all model in the FR wiki.
So nothing to do here.

Cheers,

Olivier

On 13 Jun 2018, at 17:21, Valentin Hirschi <<email address hidden><mailto:<email address hidden>>> wrote:

Hi Olivier

On Wed, Jun 13, 2018 at 5:09 PM, Olivier Mattelaer <
<email address hidden><mailto:<email address hidden>>> wrote:

Hi,

To merge this to 2.6.3, we have to keep such change minimal for the moment.

So I have had the bare minimum to the current status.
This is
a) detect fully identical expression --same string-- and merge them
b) remove couplings exactly equals to zero (no point to keep them
obviously)

This is pretty minimal and quite save.
for loop_sm this does not do anything in the unitary gauge. (but make few
simplification in the feynman gauge)
for the loop_qcd_qed_sm, they are 148 coupling equals to zero, so this
makes some cool cleaning.

Now we can also not push this in 2.6.3 to be save. They are nothing
crucial in such change and can easily wait months to be include.

I would need this to be pushed in 2.6.3 for this model to work:

http://feynrules.irmp.ucl.ac.be/wiki/GGG

So could you please put this in the 2.6.3 release ? (the model above in
principle only need the long name fix of course)

Cheers

Cheers,

Olivier

=== modified file 'models/import_ufo.py'
--- models/import_ufo.py 2018-06-01 08:46:21 +0000
+++ models/import_ufo.py 2018-06-13 15:01:47 +0000
@@ -14,7 +14,7 @@
############################################################
####################
""" How to import a UFO model to the MG5 format """

-
+import collections
import fractions
import logging
import os
@@ -530,8 +530,10 @@
                self.add_CTinteraction(interaction_info, color_info)

- for interaction in self.interactions:
+ for interaction in list(self.interactions):
            self.optimise_interaction(interaction)
+ if not interaction['couplings']:
+ self.interactions.remove(interaction)

        self.model.set('conserved_charge', self.conservecharge)
@@ -584,6 +586,32 @@

    def optimise_interaction(self, interaction):

+
+ # Check if two couplings have exactly the same definition.
+ # If so replace one by the other
+ if not hasattr(self, 'iden_couplings'):
+ coups = collections.defaultdict(list)
+ coups['0'].append('ZERO')
+ for coupling in self.ufomodel.all_couplings:
+ #if isinstance(coupling.value, str):
+ coups[str(coupling.value)].append( coupling.name)
+
+ self.iden_couplings = {}
+ for idens in [c for c in coups.values() if len(c)>1]:
+ for i in range(1, len(idens)):
+ self.iden_couplings[idens[i]] = idens[0]
+
+ # apply the replacement by identical expression
+ for key, coup in list(interaction['couplings'].items()):
+ if coup in self.iden_couplings:
+ interaction['couplings'][key] = self.iden_couplings[coup]
+ i...

Read more...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'UpdateNotes.txt'
2--- UpdateNotes.txt 2018-05-08 20:37:57 +0000
3+++ UpdateNotes.txt 2018-06-02 22:01:27 +0000
4@@ -1,9 +1,19 @@
5 Update notes for MadGraph5_aMC@NLO (in reverse time order)
6
7 2.6.3 ()
8+ OM: When importing model, we now run one additional layer of optimisation:
9+ - if a vertex as two identical coupling for the same color structure then the associated lorentz
10+ structure are merged in a single one and the vertex is modified accordingly
11+ OM: When restricting a model, we also run one additional layer of optimisation
12+ - Opposite sign coupling are now identified and merged into a single one
13+ - if a vertex as two identical coupling (up to the sign) for the same color structure
14+ then the associated lorentz structure are merged in a single one and the
15+ vertex is modified accordingly
16+ VH+OM: changing the ALOHA naming scheme for combine routine when the function name starts to be too long.
17 OM: adding a hidden parameter to the run_card (python_seed) to allow to control the randon number
18 generated within python and be able to have full reproducibility of the events
19-
20+ OM: Adding Qnumbers block for ghost (the latest version of py8 was crashing due to their absence)
21+
22 2.6.2 (29/04/18)
23
24 Heavy ion pdf / pdf in general:
25
26=== modified file 'aloha/aloha_writers.py'
27--- aloha/aloha_writers.py 2018-04-11 15:28:05 +0000
28+++ aloha/aloha_writers.py 2018-06-02 22:01:27 +0000
29@@ -1177,7 +1177,7 @@
30
31 def get_routine_name(name=None, outgoing=None, tag=None, abstract=None):
32 """ build the name of the aloha function """
33-
34+
35 assert (name and outgoing is not None) or abstract
36
37 if tag is None:
38@@ -1205,6 +1205,14 @@
39 def combine_name(name, other_names, outgoing, tag=None, unknown_propa=False):
40 """ build the name for combined aloha function """
41
42+ def myHash(target_string):
43+ if len(target_string)<50:
44+ return target_string
45+ if '%(propa)s' in target_string:
46+ return 'ALOHA_'+(str(hash(target_string.lower()))).replace('-','m')+'%(propa)s'
47+ else:
48+ return 'ALOHA_'+(str(hash(target_string.lower()))).replace('-','m')
49+
50 if tag and any(t.startswith('P') for t in tag[:-1]):
51 # propagator need to be the last entry for the tag
52 for i,t in enumerate(tag):
53@@ -1238,9 +1246,11 @@
54 if unknown_propa and outgoing:
55 routine += '%(propa)s'
56 if outgoing is not None:
57- return routine +'_%s' % outgoing
58+ return myHash(routine)+'_%s' % outgoing
59+# return routine +'_%s' % outgoing
60 else:
61- return routine
62+ return myHash(routine)
63+# return routine
64
65 if tag is not None:
66 addon = ''.join(tag)
67@@ -1257,10 +1267,15 @@
68 if unknown_propa:
69 addon += '%(propa)s'
70
71+# if outgoing is not None:
72+# return '_'.join((name,) + tuple(other_names)) + addon + '_%s' % outgoing
73+# else:
74+# return '_'.join((name,) + tuple(other_names)) + addon
75+
76 if outgoing is not None:
77- return '_'.join((name,) + tuple(other_names)) + addon + '_%s' % outgoing
78+ return myHash('_'.join((name,) + tuple(other_names))) + addon + '_%s' % outgoing
79 else:
80- return '_'.join((name,) + tuple(other_names)) + addon
81+ return myHash('_'.join((name,) + tuple(other_names))) + addon
82
83 class ALOHAWriterForCPP(WriteALOHA):
84 """Routines for writing out helicity amplitudes as C++ .h and .cc files."""
85@@ -1736,7 +1751,7 @@
86 # added to another file
87 self.mode = 'no_include'
88
89- #name = combine_name(self.name, lor_names, offshell, self.tag)
90+
91
92 #h_text = self.write_combined_h(lor_names, offshell, **opt)
93 cc_text, h_text = StringIO() , StringIO()
94
95=== modified file 'aloha/create_aloha.py'
96--- aloha/create_aloha.py 2018-06-01 15:33:33 +0000
97+++ aloha/create_aloha.py 2018-06-02 22:01:27 +0000
98@@ -470,8 +470,8 @@
99 propaR = deltaL('pr1',id) * deltaL('pr2', 'I2') * delta('pr2', spin_id) * delta('pr1', 'I3')
100 #numerator += "*deltaL('pr_1',id) * deltaL('pr_2', 'I2') * delta('pr_1', spin_id) * delta('pr_2', 'I3')"
101 elif spin == 5 :
102- tag = {'1': _spin2_mult + id, '2': 2 * _spin2_mult + id,
103- '51': 'I2', '52': 'I3', 'id':id}
104+ tag = {'1': _spin2_mult + id, '2': 'I2',
105+ '51': 2 * _spin2_mult + id, '52': 'I3', 'id':id}
106
107 numerator = self.mod_propagator_expression(tag, numerator)
108 if denominator:
109@@ -1240,7 +1240,6 @@
110
111 # avoid to add tag in global
112 old_tag = set(aloha_lib.KERNEL.use_tag)
113- print 'create lib',tag
114 name, i = tag
115 if name == "Spin2Prop":
116 lib[('Spin2Prop',i)] = create( Spin2Propagator(_spin2_mult + i, \
117
118=== modified file 'madgraph/loop/loop_helas_objects.py'
119--- madgraph/loop/loop_helas_objects.py 2017-07-13 10:33:37 +0000
120+++ madgraph/loop/loop_helas_objects.py 2018-06-02 22:01:27 +0000
121@@ -2316,8 +2316,7 @@
122 already created and can be specified here instead of being generated.
123 This can make a difference for very complicated models."""
124
125-
126- if alohaModel is None:
127+ if not alohaModel:# is None:
128 # Generate it here
129 model = self.get('processes')[0].get('model')
130 myAlohaModel = create_aloha.AbstractALOHAModel(model.get('name'))
131
132=== modified file 'madgraph/various/misc.py'
133--- madgraph/various/misc.py 2018-06-01 12:14:52 +0000
134+++ madgraph/various/misc.py 2018-06-02 22:01:27 +0000
135@@ -1082,7 +1082,8 @@
136 return self.path
137
138 class TMP_variable(object):
139- """create a temporary directory and ensure this one to be cleaned.
140+ """replace an attribute of a class with another value for the time of the
141+ context manager
142 """
143
144 def __init__(self, cls, attribute, value):
145
146=== modified file 'mg5decay/decay_objects.py'
147--- mg5decay/decay_objects.py 2017-07-04 09:24:42 +0000
148+++ mg5decay/decay_objects.py 2018-06-02 22:01:27 +0000
149@@ -4091,7 +4091,7 @@
150 model.lorentz_dict = dict([(l.name, l) for l in model['lorentz']])
151 self.init_regular_expression()
152
153- structure = model.lorentz_dict[vertex['lorentz'][key[1]]].structure
154+ structure = model.lorentz_dict[vertex['lorentz'][key[1]]].structure
155 new_structure = self.lor_pattern.sub(self.simplify_lorentz,
156 structure)
157 lor_value = eval(new_structure % q_dict_lor)
158
159=== modified file 'models/import_ufo.py'
160--- models/import_ufo.py 2018-03-10 22:48:36 +0000
161+++ models/import_ufo.py 2018-06-02 22:01:27 +0000
162@@ -497,7 +497,7 @@
163 color_info = self.find_color_anti_color_rep()
164
165 # load the lorentz structure.
166- self.model.set('lorentz', self.ufomodel.all_lorentz)
167+ self.model.set('lorentz', list(self.ufomodel.all_lorentz))
168
169 # Substitute the expression of CT couplings which include CTparameters
170 # in their definition with the corresponding dictionaries, e.g.
171@@ -529,6 +529,11 @@
172 for interaction_info in self.ufomodel.all_CTvertices:
173 self.add_CTinteraction(interaction_info, color_info)
174
175+
176+ for interaction in self.interactions:
177+ self.optimise_interaction(interaction)
178+
179+
180 self.model.set('conserved_charge', self.conservecharge)
181
182 # If we deal with a Loop model here, the order hierarchy MUST be
183@@ -576,7 +581,102 @@
184 del self.checked_lor
185
186 return self.model
187-
188+
189+ def optimise_interaction(self, interaction):
190+
191+ # we want to check if the same coupling is used for two lorentz strucutre
192+ # for the same color structure.
193+ to_lor = {}
194+ for (color, lor), coup in interaction['couplings'].items():
195+ key = (color, coup)
196+ if key in to_lor:
197+ to_lor[key].append(lor)
198+ else:
199+ to_lor[key] = [lor]
200+
201+ nb_reduce = []
202+ optimize = False
203+ for key in to_lor:
204+ if len(to_lor[key]) >1:
205+ nb_reduce.append(len(to_lor[key])-1)
206+ optimize = True
207+
208+ if not optimize:
209+ return
210+
211+ if not hasattr(self, 'defined_lorentz_expr'):
212+ self.defined_lorentz_expr = {}
213+ self.lorentz_info = {}
214+ self.lorentz_combine = {}
215+ for lor in self.model['lorentz']:
216+ self.defined_lorentz_expr[lor.get('structure')] = lor.get('name')
217+ self.lorentz_info[lor.get('name')] = lor #(lor.get('structure'), lor.get('spins'))
218+
219+ for key in to_lor:
220+ if len(to_lor[key]) == 1:
221+ continue
222+ names = [interaction['lorentz'][i] for i in to_lor[key]]
223+ names.sort()
224+
225+ # get name of the new lorentz
226+ if tuple(names) in self.lorentz_combine:
227+ # already created new loretnz
228+ new_name = self.lorentz_combine[tuple(names)]
229+ else:
230+ new_name = self.add_merge_lorentz(names)
231+
232+ # remove the old couplings
233+ color, coup = key
234+ to_remove = [(color, lor) for lor in to_lor[key]]
235+ for rm in to_remove:
236+ del interaction['couplings'][rm]
237+
238+ #add the lorentz structure to the interaction
239+ if new_name not in [l for l in interaction.get('lorentz')]:
240+ interaction.get('lorentz').append(new_name)
241+
242+ #find the associate index
243+ new_l = interaction.get('lorentz').index(new_name)
244+ # adding the new combination (color,lor) associate to this sum of structure
245+ interaction['couplings'][(color, new_l)] = coup
246+
247+
248+ def add_merge_lorentz(self, names):
249+ """add a lorentz structure which is the sume of the list given above"""
250+
251+
252+ #create new_name
253+ ii = len(names[0])
254+ while ii>0:
255+ if not all(n.startswith(names[0][:ii]) for n in names[1:]):
256+ ii -=1
257+ else:
258+ base_name = names[0][:ii]
259+ break
260+ else:
261+ base_name = 'LMER'
262+
263+ i = 1
264+ while '%s%s' %(base_name, i) in self.lorentz_info:
265+ i +=1
266+ new_name = '%s%s' %(base_name, i)
267+ self.lorentz_combine[tuple(names)] = new_name
268+ assert new_name not in self.lorentz_info
269+ assert new_name not in [l.name for l in self.model['lorentz']]
270+
271+ # load the associate lorentz expression
272+ new_struct = ' + '.join([self.lorentz_info[n].get('structure') for n in names])
273+ spins = self.lorentz_info[names[0]].get('spins')
274+ new_lor = self.add_lorentz(new_name, spins, new_struct)
275+ self.lorentz_info[new_name] = new_lor
276+
277+ return new_name
278+
279+ # We also have to create the new lorentz
280+
281+
282+
283+
284
285 def add_particle(self, particle_info):
286 """ convert and add a particle in the particle list """
287@@ -980,7 +1080,6 @@
288 (intType if poleOrder==0 else (intType+str(poleOrder)+\
289 'eps')),loop_particles)
290
291-
292 def find_color_anti_color_rep(self, output=None):
293 """find which color are in the 3/3bar states"""
294 # method look at the 3 3bar 8 configuration.
295@@ -1197,6 +1296,7 @@
296 self.conservecharge.discard(charge)
297
298
299+
300 def get_sign_flow(self, flow, nb_fermion):
301 """ensure that the flow of particles/lorentz are coherent with flow
302 and return a correct version if needed"""
303@@ -1241,14 +1341,18 @@
304
305 def add_lorentz(self, name, spins , expr):
306 """ Add a Lorentz expression which is not present in the UFO """
307-
308- new = self.model['lorentz'][0].__class__(name = name,
309- spins = spins,
310- structure = expr)
311-
312- self.model['lorentz'].append(new)
313+
314+ assert name not in [l.name for l in self.model['lorentz']]
315+ with misc.TMP_variable(self.ufomodel.object_library, 'all_lorentz',
316+ self.model['lorentz']):
317+ new = self.model['lorentz'][0].__class__(name = name,
318+ spins = spins,
319+ structure = expr)
320+ assert name in [l.name for l in self.model['lorentz']]
321+ assert name not in [l.name for l in self.ufomodel.all_lorentz]
322+ #self.model['lorentz'].append(new) # already done by above command
323 self.model.create_lorentz_dict()
324- return name
325+ return new
326
327 _pat_T = re.compile(r'T\((?P<first>\d*),(?P<second>\d*)\)')
328 _pat_id = re.compile(r'Identity\((?P<first>\d*),(?P<second>\d*)\)')
329@@ -1702,6 +1806,10 @@
330 self.del_coup += zero_couplings
331 self.remove_couplings(self.del_coup)
332
333+ # modify interaction to avoid to have identical coupling with different lorentz
334+ for interaction in self.get('interactions'):
335+ self.optimise_interaction(interaction)
336+
337 # deal with parameters
338 parameters = self.detect_special_parameters()
339 self.fix_parameter_values(*parameters, simplify=rm_parameter,
340@@ -1772,14 +1880,23 @@
341 return self.detect_identical_couplings(strict_zero=True)
342
343
344- if value in dict_value_coupling:
345- iden_key.add(value)
346- dict_value_coupling[value].append(name)
347+ if value in dict_value_coupling or -1*value in dict_value_coupling:
348+ if value in dict_value_coupling:
349+ iden_key.add(value)
350+ dict_value_coupling[value].append((name,1))
351+ else:
352+ iden_key.add(-1*value)
353+ dict_value_coupling[-1*value].append((name,-1))
354 else:
355- dict_value_coupling[value] = [name]
356-
357+ dict_value_coupling[value] = [(name,1)]
358 for key in iden_key:
359- iden_coupling.append(dict_value_coupling[key])
360+ tmp = []
361+ if key in dict_value_coupling:
362+ tmp += dict_value_coupling[key]
363+ elif -1*key in dict_value_coupling:
364+ tmp += dict_value_coupling[-1*key]
365+ assert tmp
366+ iden_coupling.append(tmp)
367
368 return zero_coupling, iden_coupling
369
370@@ -1898,17 +2015,52 @@
371 return output
372
373
374+ @staticmethod
375+ def get_new_coupling_name(main, coupling, value, coeff):
376+ """ We have main == coeff * coupling
377+ coeff is only +1 or -1
378+ main can be either GC_X or -GC_X
379+ coupling can be either GC_Y or -GC_Y
380+ value is either GC_Y or -GC_Y
381+ the return is either GC_X or -GC_X
382+ such that we have value == OUTPUT
383+ """
384+ assert coeff in [-1,1]
385+ assert value == coupling or value == '-%s' % coupling or coupling == '-%s' % value
386+ assert isinstance(main, str)
387+ assert isinstance(coupling, str)
388+ assert isinstance(value, str)
389+ if coeff ==1:
390+ if value == coupling:
391+ return main # 4/4
392+ else:
393+ if main.startswith('-'):
394+ return main[1:] # 2/2
395+ else:
396+ return '-%s' % main # 2/2
397+ else:
398+ if value == coupling:
399+ if main.startswith('-'):
400+ return main[1:] # 2/2
401+ else:
402+ return '-%s' % main # 2/2
403+ else:
404+ return main # 4/4
405+
406+
407 def merge_iden_couplings(self, couplings):
408 """merge the identical couplings in the interactions and particle
409 counterterms"""
410
411
412 logger_mod.debug(' Fuse the Following coupling (they have the same value): %s '% \
413- ', '.join([obj for obj in couplings]))
414+ ', '.join([str(obj) for obj in couplings]))
415+
416+ main = couplings[0][0]
417+ assert couplings[0][1] == 1
418+ self.del_coup += [c[0] for c in couplings[1:]] # add the other coupl to the suppress list
419
420- main = couplings[0]
421- self.del_coup += couplings[1:] # add the other coupl to the suppress list
422- for coupling in couplings[1:]:
423+ for coupling, coeff in couplings[1:]:
424 # check if param is linked to an interaction
425 if coupling not in self.coupling_pos:
426 continue
427@@ -1917,13 +2069,12 @@
428 isinstance(vert, base_objects.Interaction)]
429 for vertex in vertices:
430 for key, value in vertex['couplings'].items():
431- if value == coupling:
432- vertex['couplings'][key] = main
433- elif value == '-%s' % coupling:
434- if main.startswith('-'):
435- vertex['couplings'][key] = main[1:]
436- else:
437- vertex['couplings'][key] = '-%s' % main
438+ if value == coupling or value == '-%s' % coupling or coupling == '-%s' % value:
439+ vertex['couplings'][key] = self.get_new_coupling_name(\
440+ main, coupling, value, coeff)
441+
442+
443+
444
445 # replace the coupling appearing in the particle counterterm
446 particles_ct = [ pct for pct in self.coupling_pos[coupling] if
447@@ -2183,11 +2334,109 @@
448 data = self['parameters'][param_info[param]['dep']]
449 data.remove(param_info[param]['obj'])
450
451-
452-
453-
454-
455-
456+ def optimise_interaction(self, interaction):
457+
458+ # we want to check if the same coupling (up to the sign) is used for two lorentz structure
459+ # for the same color structure.
460+ to_lor = {}
461+ for (color, lor), coup in interaction['couplings'].items():
462+ abscoup, coeff = (coup[1:],-1) if coup.startswith('-') else (coup, 1)
463+ key = (color, abscoup)
464+ if key in to_lor:
465+ to_lor[key].append((lor,coeff))
466+ else:
467+ to_lor[key] = [(lor,coeff)]
468+
469+ nb_reduce = []
470+ optimize = False
471+ for key in to_lor:
472+ if len(to_lor[key]) >1:
473+ nb_reduce.append(len(to_lor[key])-1)
474+ optimize = True
475+
476+ if not optimize:
477+ return
478+
479+ if not hasattr(self, 'defined_lorentz_expr'):
480+ self.defined_lorentz_expr = {}
481+ self.lorentz_info = {}
482+ self.lorentz_combine = {}
483+ for lor in self.get('lorentz'):
484+ self.defined_lorentz_expr[lor.get('structure')] = lor.get('name')
485+ self.lorentz_info[lor.get('name')] = lor #(lor.get('structure'), lor.get('spins'))
486+
487+ for key in to_lor:
488+ if len(to_lor[key]) == 1:
489+ continue
490+ names = ['u%s' % interaction['lorentz'][i[0]] if i[1] ==1 else \
491+ 'd%s' % interaction['lorentz'][i[0]] for i in to_lor[key]]
492+
493+ names.sort()
494+
495+ # get name of the new lorentz
496+ if tuple(names) in self.lorentz_combine:
497+ # already created new loretnz
498+ new_name = self.lorentz_combine[tuple(names)]
499+ else:
500+ new_name = self.add_merge_lorentz(names)
501+
502+ # remove the old couplings
503+ color, coup = key
504+ to_remove = [(color, lor[0]) for lor in to_lor[key]]
505+ for rm in to_remove:
506+ del interaction['couplings'][rm]
507+
508+ #add the lorentz structure to the interaction
509+ if new_name not in [l for l in interaction.get('lorentz')]:
510+ interaction.get('lorentz').append(new_name)
511+
512+ #find the associate index
513+ new_l = interaction.get('lorentz').index(new_name)
514+ # adding the new combination (color,lor) associate to this sum of structure
515+ interaction['couplings'][(color, new_l)] = coup
516+
517+
518+
519+ def add_merge_lorentz(self, names):
520+ """add a lorentz structure which is the sume of the list given above"""
521+
522+ #create new_name
523+ ii = len(names[0])
524+ while ii>1:
525+ #do not count the initial "u/d letter whcih indicates the sign"
526+ if not all(n[1:].startswith(names[0][1:ii]) for n in names[1:]):
527+ ii -=1
528+ else:
529+ base_name = names[0][1:ii]
530+ break
531+ else:
532+ base_name = 'LMER'
533+ i = 1
534+ while '%s%s' %(base_name, i) in self.lorentz_info:
535+ i +=1
536+ new_name = '%s%s' %(base_name, i)
537+ self.lorentz_combine[tuple(names)] = new_name
538+
539+ # load the associate lorentz expression
540+ new_struct = ' + '.join([self.lorentz_info[n[1:]].get('structure') for n in names if n.startswith('u')])
541+ if any( n.startswith('d') for n in names ):
542+ new_struct += '-' + ' - '.join(['1.*(%s)' %self.lorentz_info[n[1:]].get('structure') for n in names if n.startswith('d')])
543+ spins = self.lorentz_info[names[0][1:]].get('spins')
544+ new_lor = self.add_lorentz(new_name, spins, new_struct)
545+ self.lorentz_info[new_name] = new_lor
546+
547+ return new_name
548+
549+ def add_lorentz(self, name, spin, struct):
550+ """adding lorentz structure to the current model"""
551+ new = self['lorentz'][0].__class__(name = name,
552+ spins = spin,
553+ structure = struct)
554+ self['lorentz'].append(new)
555+ self.create_lorentz_dict()
556+
557+ return None
558+
559
560
561
562
563=== modified file 'tests/acceptance_tests/test_model_equivalence.py'
564--- tests/acceptance_tests/test_model_equivalence.py 2016-09-06 15:01:18 +0000
565+++ tests/acceptance_tests/test_model_equivalence.py 2018-06-02 22:01:27 +0000
566@@ -347,6 +347,7 @@
567 solutions = {'ymtau ': [1.7769999504089355], 'I4x33 ': [0.024123685681481218, 0.0], 'MTA ': [1.7769999504089355], 'GC_81 ': [0.0, 67.544], 'GC_5 ': [0.0, 0.094836], 'MZ ': [91.18800354003906], 'GC_27 ': [0.94484, 0.0], 'I1x33 ': [0.024123685681481218, 0.0], 'I3x33 ': [0.9448443987662922, 0.0], 'GC_95 ': [0.66811, 0.0], 'GC_60 ': [-0.37035, 0.0], 'ee__exp__2 ': [0.09483552005165403], 'aEWM1 ': [132.5070037841797], 'ytau ': [0.01020661671581679], 'GC_69 ': [-0.0, -190.38], 'GC_35 ': [-0.0, -0.42671], 'cw__exp__2 ': [0.7777535472599892], 'Gf ': [1.16639e-05], 'GC_59 ': [0.0, 0.08231], 'GC_21 ': [-0.94484, -0.0], 'ee ': [0.307953762847045], 'WZ ': [2.441404104232788], 'sw2 ': [0.22224645274001076], 'WT ': [1.5083359479904175], 'GC_80 ': [-0.0, -33.772], 'GC_57 ': [-0.0, -0.35482], 'sqrt__sw2 ': [0.4714302204356555], 'GC_67 ': [13.239, 0.0], 'GC_76 ': [-29.784, 0.0], 'GC_36 ': [0.0, 0.33188], 'GC_68 ': [-0.0, -63.46], 'GC_56 ': [0.10058, 0.0], 'sw__exp__2 ': [0.22224645274001076], 'GC_3 ': [-0.0, -0.30795], 'GC_54 ': [-0.10058, 0.0], 'WW ': [2.047600030899048], 'GC_70 ': [-26.266, 0.0], 'GC_66 ': [-13.239, 0.0], 'GC_38 ': [-0.0, -0.32662], 'GC_83 ': [-0.0, -0.017058], 'GC_77 ': [-16.545, 0.0], 'gw ': [0.653232969584471], 'MH ': [125.0], 'ymb ': [4.199999809265137], 'complexi ': [0.0, 1.0], 'GC_37 ': [-0.32662, 0.0], 'conjg__CKM1x1 ': [1.0], 'GC_2 ': [0.0, 0.2053], 'GC_51 ': [0.0, 0.28804], 'GC_71 ': [-0.0, -26.266], 'GC_39 ': [0.0, 0.32662], 'GC_82 ': [-0.017058, 0.0], 'GC_55 ': [-0.0, -0.10058], 'GC_78 ': [16.545, 0.0], 'GC_98 ': [-0.0072172, 0.0], 'GC_30 ': [-0.024124, -0.0], 'GC_15 ': [0.024124, 0.0], 'cw ': [0.881903366168873], 'yt ': [0.9448443987662922], 'sqrt__aEW ': [0.08687215260631942], 'vev ': [246.2184581018163], 'GC_79 ': [29.784, 0.0], 'GC_72 ': [0.0, 52.532], 'GC_1 ': [-0.0, -0.10265], 'conjg__CKM3x3 ': [1.0], 'GC_52 ': [-0.0, -0.57609], 'GC_100 ': [0.0, 0.46191], 'GC_65 ': [0.0, 0.27432], 'GC_12 ': [0.0, 1.4828], 'I2x33 ': [0.9448443987662922, 0.0], 'GC_94 ': [-0.0, -0.66811], 'sqrt__aS ': [0.3435112817874484], 'GC_31 ': [-0.0, -0.25774], 'aS ': [0.11800000071525575], 'MW__exp__2 ': [6467.21673128622], 'MZ__exp__4 ': [69143415.65084904], 'yb ': [0.024123685681481218], 'GC_99 ': [-0.0, -0.0072172], 'WH ': [0.006382339168339968], 'GC_96 ': [-0.010207, 0.0], 'MH__exp__2 ': [15625.0], 'GC_63 ': [0.0, 0.12671], 'GC_53 ': [0.0, 0.57609], 'GC_73 ': [26.266, 0.0], 'GC_64 ': [0.0, 0.084653], 'sw ': [0.4714302204356555], 'GC_9 ': [0.053768, 0.0], 'GC_32 ': [-0.0, -0.51548], 'muH ': [88.38834764831844], 'GC_7 ': [-0.053768, 0.0], 'aEW ': [0.0075467708984556505], 'vev__exp__2 ': [60623.52911003587], 'MZ__exp__2 ': [8315.251989618177], 'GC_97 ': [0.010207, 0.0], 'GC_62 ': [0.0, 0.37035], 'GC_74 ': [-24.765, 0.0], 'g1 ': [0.34919218438279087], 'GC_10 ': [-1.2177, 0.0], 'GC_8 ': [0.0, 0.053768], 'CKM3x3 ': [1.0], 'MW ': [80.41900727617956], 'MT ': [172.0], 'GC_33 ': [-0.0, -0.77321], 'GC_6 ': [0.0, 0.18967], 'GC_4 ': [0.0, 0.30795], 'MB ': [4.699999809265137], 'GC_61 ': [0.0, -0.20573], 'ymt ': [164.5], 'GC_75 ': [24.765, 0.0], 'G__exp__2 ': [1.4828317414825511], 'lam ': [0.1288691060169027], 'GC_50 ': [-0.0, -0.28804], 'GC_34 ': [0.0, 0.21336], 'GC_11 ': [0.0, 1.2177], 'sqrt__2 ': [1.4142135623730951], 'GC_58 ': [-0.0, -0.027437]}
568 #solutions = {'GC_5 ': [0.0, 0.094836], 'mdl_MW ': [80.41900727617956], 'mdl_yb ': [0.024123685681481218], 'mdl_sw__exp__2 ': [0.22224645274001076], 'mdl_conjg__CKM3x3 ': [1.0], 'GC_56 ': [0.10058, 0.0], 'mdl_MH ': [125.0], 'GC_95 ': [0.66811, 0.0], 'mdl_I4x33 ': [0.024123685681481218, 0.0], 'mdl_complexi ': [0.0, 1.0], 'aEWM1 ': [132.5070037841797], 'GC_69 ': [-0.0, -190.38], 'GC_35 ': [-0.0, -0.42671], 'mdl_Gf ': [1.16639e-05], 'mdl_gw ': [0.653232969584471], 'mdl_conjg__CKM1x1 ': [1.0], 'mdl_sqrt__aEW ': [0.08687215260631942], 'GC_59 ': [0.0, 0.08231], 'GC_21 ': [-0.94484, -0.0], 'GC_4 ': [0.0, 0.30795], 'mdl_cw ': [0.881903366168873], 'GC_80 ': [-0.0, -33.772], 'GC_64 ': [0.0, 0.084653], 'GC_57 ': [-0.0, -0.35482], 'GC_76 ': [-29.784, 0.0], 'GC_67 ': [13.239, 0.0], 'mdl_vev__exp__2 ': [60623.52911003587], 'mdl_I3x33 ': [0.9448443987662922, 0.0], 'GC_36 ': [0.0, 0.33188], 'mdl_I1x33 ': [0.024123685681481218, 0.0], 'GC_81 ': [0.0, 67.544], 'mdl_sw2 ': [0.22224645274001076], 'GC_68 ': [-0.0, -63.46], 'mdl_ytau ': [0.01020661671581679], 'GC_100 ': [0.0, 0.46191], 'GC_3 ': [-0.0, -0.30795], 'GC_54 ': [-0.10058, 0.0], 'GC_70 ': [-26.266, 0.0], 'GC_66 ': [-13.239, 0.0], 'GC_38 ': [-0.0, -0.32662], 'GC_83 ': [-0.0, -0.017058], 'GC_77 ': [-16.545, 0.0], 'GC_27 ': [0.94484, 0.0], 'GC_10 ': [-1.2177, 0.0], 'GC_37 ': [-0.32662, 0.0], 'GC_60 ': [-0.37035, 0.0], 'GC_2 ': [0.0, 0.2053], 'mdl_muH ': [88.38834764831844], 'mdl_MT ': [172.0], 'mdl_WH ': [0.006382339168339968], 'GC_51 ': [0.0, 0.28804], 'GC_71 ': [-0.0, -26.266], 'GC_39 ': [0.0, 0.32662], 'GC_82 ': [-0.017058, 0.0], 'mdl_sw ': [0.4714302204356555], 'GC_55 ': [-0.0, -0.10058], 'GC_61 ': [0.0, -0.20573], 'mdl_cw__exp__2 ': [0.7777535472599892], 'mdl_ymt ': [164.5], 'GC_78 ': [16.545, 0.0], 'mdl_CKM3x3 ': [1.0], 'GC_30 ': [-0.024124, -0.0], 'GC_15 ': [0.024124, 0.0], 'mdl_aEW ': [0.0075467708984556505], 'mdl_sqrt__sw2 ': [0.4714302204356555], 'mdl_I2x33 ': [0.9448443987662922, 0.0], 'GC_72 ': [0.0, 52.532], 'GC_1 ': [-0.0, -0.10265], 'GC_52 ': [-0.0, -0.57609], 'GC_65 ': [0.0, 0.27432], 'GC_12 ': [0.0, 1.4828], 'mdl_ymb ': [4.199999809265137], 'mdl_ee ': [0.307953762847045], 'GC_79 ': [29.784, 0.0], 'mdl_sqrt__2 ': [1.4142135623730951], 'GC_31 ': [-0.0, -0.25774], 'aS ': [0.11800000071525575], 'GC_99 ': [-0.0, -0.0072172], 'mdl_vev ': [246.2184581018163], 'GC_96 ': [-0.010207, 0.0], 'GC_63 ': [0.0, 0.12671], 'GC_53 ': [0.0, 0.57609], 'GC_73 ': [26.266, 0.0], 'mdl_MZ__exp__2 ': [8315.251989618177], 'mdl_WZ ': [2.441404104232788], 'GC_9 ': [0.053768, 0.0], 'mdl_g1 ': [0.34919218438279087], 'GC_32 ': [-0.0, -0.51548], 'mdl_G ': [1.2177157884673053], 'mdl_WT ': [1.5083359479904175], 'GC_7 ': [-0.053768, 0.0], 'mdl_G__exp__2 ': [1.4828317414825511], 'GC_97 ': [0.010207, 0.0], 'GC_62 ': [0.0, 0.37035], 'GC_74 ': [-24.765, 0.0], 'mdl_MZ ': [91.18800354003906], 'mdl_MZ__exp__4 ': [69143415.65084904], 'GC_8 ': [0.0, 0.053768], 'mdl_yt ': [0.9448443987662922], 'GC_98 ': [-0.0072172, 0.0], 'mdl_ee__exp__2 ': [0.09483552005165403], 'mdl_MB ': [4.699999809265137], 'GC_33 ': [-0.0, -0.77321], 'mdl_ymtau ': [1.7769999504089355], 'mdl_WW ': [2.047600030899048], 'GC_6 ': [0.0, 0.18967], 'mdl_MTA ': [1.7769999504089355], 'GC_75 ': [24.765, 0.0], 'GC_94 ': [-0.0, -0.66811], 'mdl_MW__exp__2 ': [6467.21673128622], 'mdl_MH__exp__2 ': [15625.0], 'GC_50 ': [-0.0, -0.28804], 'GC_34 ': [0.0, 0.21336], 'GC_11 ': [0.0, 1.2177], 'mdl_sqrt__aS ': [0.3435112817874484], 'GC_58 ': [-0.0, -0.027437], 'mdl_lam ': [0.1288691060169027]}
569 nb_value = 0
570+ checked_solutions = solutions.keys()
571 for line in testprog.stdout:
572 self.assertTrue('Warning' not in line)
573 if '=' not in line:
574@@ -356,6 +357,7 @@
575 if variable.startswith('mdl_'):
576 variable = variable[4:]
577
578+ checked_solutions.remove(variable)
579 if ',' in line:
580 value = eval(split[1])
581 else:
582@@ -375,8 +377,9 @@
583 # solutions[variable] = [singlevalue]
584 # else:
585 # solutions[variable].append(singlevalue)
586-
587- self.assertEqual(nb_value, 116)
588+ self.assertEqual(nb_value, 116 - len(checked_solutions))
589+ self.assertEqual(set(checked_solutions), set(['GC_%s ' % i for i in [27,67,54,38,78,15,52,79,96,73,9,74,4,50]]))
590+
591
592
593
594
595=== modified file 'tests/input_files/IOTestsComparison/TestCmdMatchBox/MatchBoxOutput/%TEST%SubProcesses%P0_wpwm_wpwm%matrix.f'
596--- tests/input_files/IOTestsComparison/TestCmdMatchBox/MatchBoxOutput/%TEST%SubProcesses%P0_wpwm_wpwm%matrix.f 2016-02-19 12:28:04 +0000
597+++ tests/input_files/IOTestsComparison/TestCmdMatchBox/MatchBoxOutput/%TEST%SubProcesses%P0_wpwm_wpwm%matrix.f 2018-06-02 22:01:27 +0000
598@@ -198,18 +198,18 @@
599 CALL VXXXXX(P(0,4),MDL_MW,NHEL(4),+1*IC(4),W(1,4))
600 C Amplitude(s) for diagram number 1
601 CALL VVVV2_0(W(1,1),W(1,4),W(1,2),W(1,3),GC_35,AMP(1))
602- CALL VVV1P0_1(W(1,1),W(1,2),GC_4,ZERO,ZERO,W(1,5))
603+ CALL VVV1P0_1(W(1,1),W(1,2),-GC_3,ZERO,ZERO,W(1,5))
604 C Amplitude(s) for diagram number 2
605- CALL VVV1_0(W(1,5),W(1,4),W(1,3),GC_4,AMP(2))
606+ CALL VVV1_0(W(1,5),W(1,4),W(1,3),-GC_3,AMP(2))
607 CALL VVS1_3(W(1,1),W(1,2),GC_72,MDL_MH,MDL_WH,W(1,5))
608 C Amplitude(s) for diagram number 3
609 CALL VVS1_0(W(1,4),W(1,3),W(1,5),GC_72,AMP(3))
610 CALL VVV1_3(W(1,1),W(1,2),GC_53,MDL_MZ,MDL_WZ,W(1,5))
611 C Amplitude(s) for diagram number 4
612 CALL VVV1_0(W(1,4),W(1,3),W(1,5),GC_53,AMP(4))
613- CALL VVV1P0_1(W(1,1),W(1,3),GC_4,ZERO,ZERO,W(1,5))
614+ CALL VVV1P0_1(W(1,1),W(1,3),-GC_3,ZERO,ZERO,W(1,5))
615 C Amplitude(s) for diagram number 5
616- CALL VVV1_0(W(1,5),W(1,4),W(1,2),GC_4,AMP(5))
617+ CALL VVV1_0(W(1,5),W(1,4),W(1,2),-GC_3,AMP(5))
618 CALL VVS1_3(W(1,1),W(1,3),GC_72,MDL_MH,MDL_WH,W(1,5))
619 C Amplitude(s) for diagram number 6
620 CALL VVS1_0(W(1,4),W(1,2),W(1,5),GC_72,AMP(6))
621@@ -305,18 +305,18 @@
622 CALL VXXXXX(P(0,4),MDL_MW,NHEL(4),+1*IC(4),W(1,4))
623 C Amplitude(s) for diagram number 1
624 CALL VVVV2_0(W(1,1),W(1,4),W(1,2),W(1,3),GC_35,AMP(1))
625- CALL VVV1P0_1(W(1,1),W(1,2),GC_4,ZERO,ZERO,W(1,5))
626+ CALL VVV1P0_1(W(1,1),W(1,2),-GC_3,ZERO,ZERO,W(1,5))
627 C Amplitude(s) for diagram number 2
628- CALL VVV1_0(W(1,5),W(1,4),W(1,3),GC_4,AMP(2))
629+ CALL VVV1_0(W(1,5),W(1,4),W(1,3),-GC_3,AMP(2))
630 CALL VVS1_3(W(1,1),W(1,2),GC_72,MDL_MH,MDL_WH,W(1,5))
631 C Amplitude(s) for diagram number 3
632 CALL VVS1_0(W(1,4),W(1,3),W(1,5),GC_72,AMP(3))
633 CALL VVV1_3(W(1,1),W(1,2),GC_53,MDL_MZ,MDL_WZ,W(1,5))
634 C Amplitude(s) for diagram number 4
635 CALL VVV1_0(W(1,4),W(1,3),W(1,5),GC_53,AMP(4))
636- CALL VVV1P0_1(W(1,1),W(1,3),GC_4,ZERO,ZERO,W(1,5))
637+ CALL VVV1P0_1(W(1,1),W(1,3),-GC_3,ZERO,ZERO,W(1,5))
638 C Amplitude(s) for diagram number 5
639- CALL VVV1_0(W(1,5),W(1,4),W(1,2),GC_4,AMP(5))
640+ CALL VVV1_0(W(1,5),W(1,4),W(1,2),-GC_3,AMP(5))
641 CALL VVS1_3(W(1,1),W(1,3),GC_72,MDL_MH,MDL_WH,W(1,5))
642 C Amplitude(s) for diagram number 6
643 CALL VVS1_0(W(1,4),W(1,2),W(1,5),GC_72,AMP(6))
644
645=== modified file 'tests/parallel_tests/test_ML5.py'
646--- tests/parallel_tests/test_ML5.py 2016-05-25 22:03:40 +0000
647+++ tests/parallel_tests/test_ML5.py 2018-06-02 22:01:27 +0000
648@@ -463,7 +463,7 @@
649 # MadLoop goes to quadruple precision. The agreement is then fine (10e-14!)
650 # but it takes several hours for the non-optimized evaluation. So better skip
651 # it unless you explicitly want to try out quad prec behaviors.
652- def notest_long_sm_vs_stored_ML5_gg_ggg(self):
653+ def test_long_sm_vs_stored_ML5_gg_ggg(self):
654 proc = "gg_ggg"
655 self.compare_processes([ML5_processes_long_dic[proc]],
656 model = self.test_model_name, pickle_file = 'ml5_sm_%s.pkl'%proc,
657
658=== modified file 'tests/parallel_tests/test_ML5MSSMQCD.py'
659--- tests/parallel_tests/test_ML5MSSMQCD.py 2016-07-02 20:34:59 +0000
660+++ tests/parallel_tests/test_ML5MSSMQCD.py 2018-06-02 22:01:27 +0000
661@@ -108,7 +108,7 @@
662 filename = 'ptest_long_mssm_vs_HCR_%s'%proc, chosen_runner = 'HCR')
663
664 # ('g g > go go',{'QCD':2,'QED':0},['QCD'],{'QCD':6,'QED':0})
665- def test_long_mssm_vs_stored_HCR_gg_gogo_QCD(self):
666+ def test_short_mssm_vs_stored_HCR_gg_gogo_QCD(self):
667 proc = 'gg_gogo_mssm_QCD'
668 compare_processes(self,[HCR_processes_long_dic[proc]],
669 model = "loop_MSSM-parallel_test_gogo",
670
671=== modified file 'tests/parallel_tests/test_aloha.py'
672--- tests/parallel_tests/test_aloha.py 2017-12-09 21:34:23 +0000
673+++ tests/parallel_tests/test_aloha.py 2018-06-02 22:01:27 +0000
674@@ -21,6 +21,7 @@
675 import time
676 import tempfile as tempfile
677 from functools import wraps
678+from collections import namedtuple
679
680 import aloha
681 import aloha.aloha_object as aloha_obj
682@@ -3121,7 +3122,7 @@
683 helas_suite.look_for_multiple_lorentz_interactions()
684 solution = {'FFV2': [('FFV3',), ('FFV4',), ('FFV5',)], 'FFS1': [('FFS3',)]}
685 self.assertEqual(solution, helas_suite.multiple_lor)
686-
687+
688
689 def test_short_aloha_multiple_lorentz_and_symmetry(self):
690 """ check if the detection of multiple lorentz work """
691@@ -3466,6 +3467,7 @@
692 self.assertEqual(amp.name, conjg_amp.name)
693 self.assertEqual(amp.tag + ['C1'], conjg_amp.tag)
694
695+
696 def test_short_aloha_expr_FFFF3(self):
697 """Test analytical expression for four fermion (provide by Tim M).
698 it's particularity is about to have contraction A and 4*A """
699@@ -3498,6 +3500,7 @@
700 solution = [(-518016-1383424j), (317568-1604608j), (162600-4898488j), (-31800-8538056j)]
701 for out,sol in zip(ufo_value,solution):
702 self.assertAlmostEqual(out, sol)
703+
704
705 def test_short_aloha_expr_VVS1(self):
706 """Test analytical expression for VVS from SILH.
707@@ -3668,7 +3671,170 @@
708 class TestAlohaWriter(unittest.TestCase):
709 """ simple unittest of the writer more test are in test_export_v4
710 and test_export_pythia"""
711-
712+
713+ @set_global()
714+ def test_get_custom_propa(self):
715+
716+ FFVV = UFOLorentz(name = 'FFVV',
717+ spins = [ 2, 2, 3, 3])
718+
719+ abstract = AbstractRoutineBuilder(FFVV)
720+ Propagator = namedtuple('Propagator', ('name', 'numerator', 'denominator'))
721+ modelclass = namedtuple('modelclass', ('propagators'))
722+ propa = namedtuple('propa', ('mypropa'))
723+
724+ #start by the scalar case
725+ S = Propagator(name = "S",
726+ numerator = "complex(0,1)",
727+ denominator = "P('mu', id) * P('mu', id) - Mass(id) * Mass(id) + complex(0,1) * Mass(id) * Width(id)"
728+ )
729+
730+ abstract.model= modelclass(propagators=propa(mypropa=S))
731+ out = abstract.get_custom_propa('mypropa', 1, 1)
732+ # check numerator/denominator
733+ self.assertEqual(str(out), '1j')
734+ self.assertEqual(str(abstract.denominator), '( (TMP0) + (-1 * M1 * M1) + (1j * M1 * W1) )')
735+
736+ # check simple modification of the propagators
737+ S = Propagator(name = "S",
738+ numerator = "P('mu',id) **2",
739+ denominator = "Mass(id) * Mass(id)"
740+ )
741+
742+ abstract = AbstractRoutineBuilder(FFVV)
743+ abstract.model= modelclass(propagators=propa(mypropa=S))
744+ out = abstract.get_custom_propa('mypropa', 1, 2)
745+ # check numerator/denominator
746+ self.assertEqual(str(out), '(_P^2_mu * _P^2_mu)')
747+ self.assertEqual(str(abstract.denominator), '(M2 * M2)')
748+
749+ # check simple modification of the propagators
750+ F = Propagator(name = "F",
751+ numerator = "P('mu', id)* Gamma('mu',1,2)",
752+ denominator = "Mass(id) * Mass(id)"
753+ )
754+
755+ abstract = AbstractRoutineBuilder(FFVV)
756+ abstract.model= modelclass(propagators=propa(mypropa=F))
757+ out = abstract.get_custom_propa('mypropa', 2, 2)
758+ # check numerator/denominator
759+ self.assertEqual(str(out), '(_P^2_mu * Gamma^mu_I2_2)')
760+ self.assertEqual(type(out), aloha.aloha_lib.MultLorentz )
761+ out = out.expand()
762+ self.assertEqual(type(out), aloha.aloha_lib.LorentzObjectRepresentation )
763+ self.assertEqual(out.nb_lor, 0)
764+ self.assertEqual(out.nb_spin, 2)
765+ self.assertEqual(str(abstract.denominator), '(M2 * M2)')
766+
767+ # check propa with conjugate routine
768+ F = Propagator(name = "F",
769+ numerator = "P('mu', id)* Gamma('mu',1,2)",
770+ denominator = "Mass(id) * Mass(id)"
771+ )
772+
773+ abstract = AbstractRoutineBuilder(FFVV)
774+ abstract = abstract.define_conjugate_builder(1)
775+ abstract.model= modelclass(propagators=propa(mypropa=F))
776+ out = abstract.get_custom_propa('mypropa', 2, 2)
777+ # check numerator/denominator
778+ self.assertEqual(str(out), '(-1 * _P^2_mu * Gamma^mu_51_I2)')
779+ # the next line does not check the propagator in itself but show the consistency
780+ # of the 51 index.
781+ self.assertEqual(str(abstract.lorentz_expr), '(1) * C(51,2) * C(52,1)')
782+ self.assertEqual(type(out), aloha.aloha_lib.MultLorentz )
783+ out = out.expand()
784+ self.assertEqual(type(out), aloha.aloha_lib.LorentzObjectRepresentation )
785+ self.assertEqual(out.nb_lor, 0)
786+ self.assertEqual(out.nb_spin, 2)
787+ self.assertEqual(out.spin_ind, [51, 'I2'])
788+
789+
790+ # check simple modification of the propagators for Vector
791+ V = Propagator(name = "V",
792+ numerator = "P(1, id)* P(2, id) * FCT(P('mu', id)* P('mu', id))",
793+ denominator = "Mass(id) * Mass(id)"
794+ )
795+
796+ abstract = AbstractRoutineBuilder(FFVV)
797+ abstract.model= modelclass(propagators=propa(mypropa=V))
798+ out = abstract.get_custom_propa('mypropa', 3, 3)
799+ # check numerator/denominator
800+ self.assertEqual(str(out), '(_P^3_3 * _P^3_I2 * _FCT0)')
801+ self.assertEqual(type(out), aloha.aloha_lib.MultLorentz )
802+ out = out.expand()
803+ self.assertEqual(type(out), aloha.aloha_lib.LorentzObjectRepresentation )
804+ self.assertEqual(out.nb_lor, 2)
805+ self.assertEqual(out.nb_spin, 0)
806+ self.assertEqual(out.lorentz_ind, ['I2',3])
807+ self.assertEqual(str(abstract.denominator), '(M3 * M3)')
808+
809+ # check simple modification of the spin3/2 propagators
810+ R = Propagator(name = "R",
811+ numerator = "P(1, id)* Gamma(2,1,2)",
812+ denominator = "Mass(id) * Mass(id)"
813+ )
814+
815+ abstract = AbstractRoutineBuilder(FFVV)
816+ abstract.model= modelclass(propagators=propa(mypropa=R))
817+ out = abstract.get_custom_propa('mypropa', 4, 1)
818+ # check numerator/denominator
819+ self.assertEqual(str(out), '(-1 * _P^1_pr1 * Gamma^pr2_pr1_pr2 * IdL_pr1_1 * IdL_pr2_I2 * Id_pr1_1 * Id_pr2_I3)')
820+ self.assertEqual(type(out), aloha.aloha_lib.MultLorentz )
821+ out = out.expand()
822+ self.assertEqual(type(out), aloha.aloha_lib.LorentzObjectRepresentation )
823+ self.assertEqual(out.nb_lor, 2)
824+ self.assertEqual(out.nb_spin, 2)
825+ self.assertEqual(out.lorentz_ind, [1, 'I2'])
826+ self.assertEqual(out.spin_ind, ['I3', 1])
827+ self.assertEqual(str(abstract.denominator), '(M1 * M1)')
828+
829+
830+
831+ # check simple modification of the spin3/2 propagators
832+ R = Propagator(name = "R",
833+ numerator = "P(1, id)* Gamma(2,1,2)",
834+ denominator = "Mass(id) * Mass(id)"
835+ )
836+
837+ abstract = AbstractRoutineBuilder(FFVV)
838+ abstract.model= modelclass(propagators=propa(mypropa=R))
839+ abstract = abstract.define_conjugate_builder(1)
840+ out = abstract.get_custom_propa('mypropa', 4, 1)
841+ # check numerator/denominator
842+ self.assertEqual(str(out), '(_P^1_pr1 * Gamma^pr2_pr1_pr2 * IdL_pr1_1 * IdL_pr2_I2 * Id_pr2_52 * Id_pr1_I3)')
843+
844+ self.assertEqual(type(out), aloha.aloha_lib.MultLorentz )
845+ out = out.expand()
846+ self.assertEqual(type(out), aloha.aloha_lib.LorentzObjectRepresentation )
847+ self.assertEqual(out.nb_lor, 2)
848+ self.assertEqual(out.nb_spin, 2)
849+ self.assertEqual(out.lorentz_ind, [1, 'I2'])
850+ self.assertEqual(out.spin_ind, ['I3', 52])
851+ self.assertEqual(str(abstract.denominator), '(M1 * M1)')
852+
853+
854+ # check simple modification of the propagators for Vector
855+ S2 = Propagator(name = "S2",
856+ numerator = "P(1, id)* P(2, id) * FCT(P('mu', id)* P('mu', id)) * Metric(51,52)",
857+ denominator = "Mass(id) * Mass(id)"
858+ )
859+
860+ abstract = AbstractRoutineBuilder(FFVV)
861+ abstract.model= modelclass(propagators=propa(mypropa=S2))
862+ out = abstract.get_custom_propa('mypropa', 5, 3)
863+ # check numerator/denominator
864+ self.assertEqual(str(out), '(_P^3_1003 * _P^3_I2 * _FCT0 * _ETA_2003_I3)')
865+ self.assertEqual(type(out), aloha.aloha_lib.MultLorentz )
866+ out = out.expand()
867+ self.assertEqual(type(out), aloha.aloha_lib.LorentzObjectRepresentation )
868+ self.assertEqual(out.nb_lor, 4)
869+ self.assertEqual(out.nb_spin, 0)
870+ self.assertEqual(out.lorentz_ind, ['I2', 1003, 2003, 'I3'])
871+ self.assertEqual(str(abstract.denominator), '(M3 * M3)')
872+
873+
874+
875+
876 def old_test_reorder_call_listFFVV(self):
877
878 FFVV = UFOLorentz(name = 'FFVV',
879
880=== modified file 'tests/unit_tests/iolibs/test_export_v4.py'
881--- tests/unit_tests/iolibs/test_export_v4.py 2018-04-23 20:23:22 +0000
882+++ tests/unit_tests/iolibs/test_export_v4.py 2018-06-02 22:01:27 +0000
883@@ -9832,7 +9832,7 @@
884
885 # couplings
886 self.assertEqual(len(mg4_model.coups_dep), 3)
887- sol = ['GC_1', 'GC_2', 'GC_3', 'GC_4', 'GC_5', 'GC_6', 'GC_7', 'GC_8', 'GC_9', 'GC_15', 'GC_21', 'GC_27', 'GC_30', 'GC_31', 'GC_32', 'GC_33', 'GC_34', 'GC_35', 'GC_36', 'GC_37', 'GC_38', 'GC_39', 'GC_50', 'GC_51', 'GC_52', 'GC_53', 'GC_54', 'GC_55', 'GC_56', 'GC_57', 'GC_58', 'GC_59', 'GC_60', 'GC_61', 'GC_62', 'GC_63', 'GC_64', 'GC_65', 'GC_66', 'GC_67', 'GC_68', 'GC_69', 'GC_70', 'GC_71', 'GC_72', 'GC_73', 'GC_74', 'GC_75', 'GC_76', 'GC_77', 'GC_78', 'GC_79', 'GC_80', 'GC_81', 'GC_82', 'GC_83', 'GC_94', 'GC_95', 'GC_96', 'GC_97', 'GC_98', 'GC_99', 'GC_100']
888+ sol = ['GC_1', 'GC_2', 'GC_3', 'GC_5', 'GC_6', 'GC_7', 'GC_8', 'GC_21', 'GC_30', 'GC_31', 'GC_32', 'GC_33', 'GC_34', 'GC_35', 'GC_36', 'GC_37', 'GC_39', 'GC_51', 'GC_53', 'GC_55', 'GC_56', 'GC_57', 'GC_58', 'GC_59', 'GC_60', 'GC_61', 'GC_62', 'GC_63', 'GC_64', 'GC_65', 'GC_66', 'GC_68', 'GC_69', 'GC_70', 'GC_71', 'GC_72', 'GC_75', 'GC_76', 'GC_77', 'GC_80', 'GC_81', 'GC_82', 'GC_83', 'GC_94', 'GC_95', 'GC_97', 'GC_98', 'GC_99', 'GC_100']
889
890 self.assertEqual(sol, [ p.name for p in mg4_model.coups_indep])
891
892
893=== modified file 'tests/unit_tests/iolibs/test_helas_call_writers.py'
894--- tests/unit_tests/iolibs/test_helas_call_writers.py 2015-10-01 16:00:08 +0000
895+++ tests/unit_tests/iolibs/test_helas_call_writers.py 2018-06-02 22:01:27 +0000
896@@ -996,40 +996,40 @@
897 CALL VXXXXX(P(0,3),ZERO,NHEL(3),+1*IC(3),W(1,3))
898 CALL VXXXXX(P(0,4),mdl_MW,NHEL(4),+1*IC(4),W(1,4))
899 CALL VXXXXX(P(0,5),mdl_MZ,NHEL(5),+1*IC(5),W(1,5))
900-CALL VVV1_3(W(1,1),W(1,2),GC_4,DCMPLX(CMASS_mdl_MW),W(1,6))
901-CALL VVV1_2(W(1,3),W(1,4),GC_4,DCMPLX(CMASS_mdl_MW),W(1,7))
902+CALL VVV1_3(W(1,1),W(1,2),-GC_3,DCMPLX(CMASS_mdl_MW),W(1,6))
903+CALL VVV1_2(W(1,3),W(1,4),-GC_3,DCMPLX(CMASS_mdl_MW),W(1,7))
904 # Amplitude(s) for diagram number 1
905 CALL VVV1_0(W(1,6),W(1,7),W(1,5),GC_53,AMP(1))
906 CALL VVV1_1(W(1,4),W(1,5),GC_53,DCMPLX(CMASS_mdl_MW),W(1,8))
907 # Amplitude(s) for diagram number 2
908-CALL VVV1_0(W(1,3),W(1,6),W(1,8),GC_4,AMP(2))
909+CALL VVV1_0(W(1,3),W(1,6),W(1,8),-GC_3,AMP(2))
910 # Amplitude(s) for diagram number 3
911 CALL VVVV5_0(W(1,3),W(1,6),W(1,4),W(1,5),GC_57,AMP(3))
912-CALL VVV1_2(W(1,1),W(1,4),GC_4,DCMPLX(CMASS_mdl_MW),W(1,6))
913-CALL VVV1_3(W(1,3),W(1,2),GC_4,DCMPLX(CMASS_mdl_MW),W(1,9))
914+CALL VVV1_2(W(1,1),W(1,4),-GC_3,DCMPLX(CMASS_mdl_MW),W(1,6))
915+CALL VVV1_3(W(1,3),W(1,2),-GC_3,DCMPLX(CMASS_mdl_MW),W(1,9))
916 # Amplitude(s) for diagram number 4
917 CALL VVV1_0(W(1,9),W(1,6),W(1,5),GC_53,AMP(4))
918 CALL VVV1_2(W(1,2),W(1,5),GC_53,DCMPLX(CMASS_mdl_MW),W(1,10))
919 # Amplitude(s) for diagram number 5
920-CALL VVV1_0(W(1,3),W(1,10),W(1,6),GC_4,AMP(5))
921+CALL VVV1_0(W(1,3),W(1,10),W(1,6),-GC_3,AMP(5))
922 # Amplitude(s) for diagram number 6
923 CALL VVVV5_0(W(1,3),W(1,2),W(1,6),W(1,5),GC_57,AMP(6))
924 # Amplitude(s) for diagram number 7
925-CALL VVV1_0(W(1,1),W(1,9),W(1,8),GC_4,AMP(7))
926+CALL VVV1_0(W(1,1),W(1,9),W(1,8),-GC_3,AMP(7))
927 # Amplitude(s) for diagram number 8
928-CALL VVV1_0(W(1,1),W(1,10),W(1,7),GC_4,AMP(8))
929+CALL VVV1_0(W(1,1),W(1,10),W(1,7),-GC_3,AMP(8))
930 CALL VVVV2_4(W(1,1),W(1,3),W(1,2),GC_5,DCMPLX(CMASS_mdl_MW),W(1,10))
931 # Amplitude(s) for diagram number 9
932 CALL VVV1_0(W(1,10),W(1,4),W(1,5),GC_53,AMP(9))
933 CALL VVVV5_3(W(1,1),W(1,2),W(1,5),GC_57,DCMPLX(CMASS_mdl_MW),W(1,10))
934 # Amplitude(s) for diagram number 10
935-CALL VVV1_0(W(1,3),W(1,10),W(1,4),GC_4,AMP(10))
936+CALL VVV1_0(W(1,3),W(1,10),W(1,4),-GC_3,AMP(10))
937 CALL VVVV2_3(W(1,1),W(1,3),W(1,4),GC_5,DCMPLX(CMASS_mdl_MW),W(1,10))
938 # Amplitude(s) for diagram number 11
939 CALL VVV1_0(W(1,2),W(1,10),W(1,5),GC_53,AMP(11))
940 CALL VVVV5_2(W(1,1),W(1,4),W(1,5),GC_57,DCMPLX(CMASS_mdl_MW),W(1,10))
941 # Amplitude(s) for diagram number 12
942-CALL VVV1_0(W(1,3),W(1,2),W(1,10),GC_4,AMP(12))"""
943+CALL VVV1_0(W(1,3),W(1,2),W(1,10),-GC_3,AMP(12))"""
944
945 self.assertEqual(solution.split('\n'), result)
946
947@@ -1047,40 +1047,40 @@
948 vxxxxx(p[perm[2]],mME[2],hel[2],+1,w[2]);
949 vxxxxx(p[perm[3]],mME[3],hel[3],+1,w[3]);
950 vxxxxx(p[perm[4]],mME[4],hel[4],+1,w[4]);
951-VVV1_3(w[0],w[1],pars->GC_4,pars->CMASS_mdl_MW,w[5]);
952-VVV1_2(w[2],w[3],pars->GC_4,pars->CMASS_mdl_MW,w[6]);
953+VVV1_3(w[0],w[1],-pars->GC_3,pars->CMASS_mdl_MW,w[5]);
954+VVV1_2(w[2],w[3],-pars->GC_3,pars->CMASS_mdl_MW,w[6]);
955 # Amplitude(s) for diagram number 1
956 VVV1_0(w[5],w[6],w[4],pars->GC_53,amp[0]);
957 VVV1_1(w[3],w[4],pars->GC_53,pars->CMASS_mdl_MW,w[7]);
958 # Amplitude(s) for diagram number 2
959-VVV1_0(w[2],w[5],w[7],pars->GC_4,amp[1]);
960+VVV1_0(w[2],w[5],w[7],-pars->GC_3,amp[1]);
961 # Amplitude(s) for diagram number 3
962 VVVV5_0(w[2],w[5],w[3],w[4],pars->GC_57,amp[2]);
963-VVV1_2(w[0],w[3],pars->GC_4,pars->CMASS_mdl_MW,w[5]);
964-VVV1_3(w[2],w[1],pars->GC_4,pars->CMASS_mdl_MW,w[8]);
965+VVV1_2(w[0],w[3],-pars->GC_3,pars->CMASS_mdl_MW,w[5]);
966+VVV1_3(w[2],w[1],-pars->GC_3,pars->CMASS_mdl_MW,w[8]);
967 # Amplitude(s) for diagram number 4
968 VVV1_0(w[8],w[5],w[4],pars->GC_53,amp[3]);
969 VVV1_2(w[1],w[4],pars->GC_53,pars->CMASS_mdl_MW,w[9]);
970 # Amplitude(s) for diagram number 5
971-VVV1_0(w[2],w[9],w[5],pars->GC_4,amp[4]);
972+VVV1_0(w[2],w[9],w[5],-pars->GC_3,amp[4]);
973 # Amplitude(s) for diagram number 6
974 VVVV5_0(w[2],w[1],w[5],w[4],pars->GC_57,amp[5]);
975 # Amplitude(s) for diagram number 7
976-VVV1_0(w[0],w[8],w[7],pars->GC_4,amp[6]);
977+VVV1_0(w[0],w[8],w[7],-pars->GC_3,amp[6]);
978 # Amplitude(s) for diagram number 8
979-VVV1_0(w[0],w[9],w[6],pars->GC_4,amp[7]);
980+VVV1_0(w[0],w[9],w[6],-pars->GC_3,amp[7]);
981 VVVV2_4(w[0],w[2],w[1],pars->GC_5,pars->CMASS_mdl_MW,w[9]);
982 # Amplitude(s) for diagram number 9
983 VVV1_0(w[9],w[3],w[4],pars->GC_53,amp[8]);
984 VVVV5_3(w[0],w[1],w[4],pars->GC_57,pars->CMASS_mdl_MW,w[9]);
985 # Amplitude(s) for diagram number 10
986-VVV1_0(w[2],w[9],w[3],pars->GC_4,amp[9]);
987+VVV1_0(w[2],w[9],w[3],-pars->GC_3,amp[9]);
988 VVVV2_3(w[0],w[2],w[3],pars->GC_5,pars->CMASS_mdl_MW,w[9]);
989 # Amplitude(s) for diagram number 11
990 VVV1_0(w[1],w[9],w[4],pars->GC_53,amp[10]);
991 VVVV5_2(w[0],w[3],w[4],pars->GC_57,pars->CMASS_mdl_MW,w[9]);
992 # Amplitude(s) for diagram number 12
993-VVV1_0(w[2],w[1],w[9],pars->GC_4,amp[11]);"""
994+VVV1_0(w[2],w[1],w[9],-pars->GC_3,amp[11]);"""
995
996 self.assertEqual(solution.split('\n'), result)
997
998@@ -1097,40 +1097,40 @@
999 w[2] = vxxxxx(p[2],ZERO,hel[2],+1)
1000 w[3] = vxxxxx(p[3],mdl_MW,hel[3],+1)
1001 w[4] = vxxxxx(p[4],mdl_MZ,hel[4],+1)
1002-w[5]= VVV1_3(w[0],w[1],GC_4,CMASS_mdl_MW)
1003-w[6]= VVV1_2(w[2],w[3],GC_4,CMASS_mdl_MW)
1004+w[5]= VVV1_3(w[0],w[1],-GC_3,CMASS_mdl_MW)
1005+w[6]= VVV1_2(w[2],w[3],-GC_3,CMASS_mdl_MW)
1006 # Amplitude(s) for diagram number 1
1007 amp[0]= VVV1_0(w[5],w[6],w[4],GC_53)
1008 w[7]= VVV1_1(w[3],w[4],GC_53,CMASS_mdl_MW)
1009 # Amplitude(s) for diagram number 2
1010-amp[1]= VVV1_0(w[2],w[5],w[7],GC_4)
1011+amp[1]= VVV1_0(w[2],w[5],w[7],-GC_3)
1012 # Amplitude(s) for diagram number 3
1013 amp[2]= VVVV5_0(w[2],w[5],w[3],w[4],GC_57)
1014-w[5]= VVV1_2(w[0],w[3],GC_4,CMASS_mdl_MW)
1015-w[8]= VVV1_3(w[2],w[1],GC_4,CMASS_mdl_MW)
1016+w[5]= VVV1_2(w[0],w[3],-GC_3,CMASS_mdl_MW)
1017+w[8]= VVV1_3(w[2],w[1],-GC_3,CMASS_mdl_MW)
1018 # Amplitude(s) for diagram number 4
1019 amp[3]= VVV1_0(w[8],w[5],w[4],GC_53)
1020 w[9]= VVV1_2(w[1],w[4],GC_53,CMASS_mdl_MW)
1021 # Amplitude(s) for diagram number 5
1022-amp[4]= VVV1_0(w[2],w[9],w[5],GC_4)
1023+amp[4]= VVV1_0(w[2],w[9],w[5],-GC_3)
1024 # Amplitude(s) for diagram number 6
1025 amp[5]= VVVV5_0(w[2],w[1],w[5],w[4],GC_57)
1026 # Amplitude(s) for diagram number 7
1027-amp[6]= VVV1_0(w[0],w[8],w[7],GC_4)
1028+amp[6]= VVV1_0(w[0],w[8],w[7],-GC_3)
1029 # Amplitude(s) for diagram number 8
1030-amp[7]= VVV1_0(w[0],w[9],w[6],GC_4)
1031+amp[7]= VVV1_0(w[0],w[9],w[6],-GC_3)
1032 w[9]= VVVV2_4(w[0],w[2],w[1],GC_5,CMASS_mdl_MW)
1033 # Amplitude(s) for diagram number 9
1034 amp[8]= VVV1_0(w[9],w[3],w[4],GC_53)
1035 w[9]= VVVV5_3(w[0],w[1],w[4],GC_57,CMASS_mdl_MW)
1036 # Amplitude(s) for diagram number 10
1037-amp[9]= VVV1_0(w[2],w[9],w[3],GC_4)
1038+amp[9]= VVV1_0(w[2],w[9],w[3],-GC_3)
1039 w[9]= VVVV2_3(w[0],w[2],w[3],GC_5,CMASS_mdl_MW)
1040 # Amplitude(s) for diagram number 11
1041 amp[10]= VVV1_0(w[1],w[9],w[4],GC_53)
1042 w[9]= VVVV5_2(w[0],w[3],w[4],GC_57,CMASS_mdl_MW)
1043 # Amplitude(s) for diagram number 12
1044-amp[11]= VVV1_0(w[2],w[1],w[9],GC_4)"""
1045+amp[11]= VVV1_0(w[2],w[1],w[9],-GC_3)"""
1046
1047 self.assertEqual(solution.split('\n'), result)
1048
1049
1050=== modified file 'tests/unit_tests/various/test_decay.py'
1051--- tests/unit_tests/various/test_decay.py 2016-09-06 15:01:18 +0000
1052+++ tests/unit_tests/various/test_decay.py 2018-06-02 22:01:27 +0000
1053@@ -1397,7 +1397,7 @@
1054 except KeyError:
1055 coup0 = model['couplings'][()][0]
1056 # coupling depend on aS
1057- coup_aS = model['couplings'][('aS',)][0]
1058+ coup_aS = model['couplings'][('aS',)][1]
1059 # coupling depend on both aS and aEWM1
1060 try:
1061 coup_both = model['couplings'][('aS', 'aEWM1')][0]
1062@@ -1427,7 +1427,7 @@
1063
1064 # Both of GC_114 ('aS',) and GC_15 ('aEWSM1', 'aS') should change
1065 self.assertAlmostEqual(eval('decay_objects.'+coup_aS.name), \
1066- -decay_objects.G)
1067+ 1j*decay_objects.G**2)
1068
1069 # copying the expr of
1070 self.assertAlmostEqual(eval('decay_objects.'+coup_both.name), \
1071
1072=== modified file 'tests/unit_tests/various/test_import_ufo.py'
1073--- tests/unit_tests/various/test_import_ufo.py 2015-11-23 05:39:08 +0000
1074+++ tests/unit_tests/various/test_import_ufo.py 2018-06-02 22:01:27 +0000
1075@@ -26,6 +26,7 @@
1076 import models.model_reader as model_reader
1077 import madgraph.iolibs.export_v4 as export_v4
1078 import models as ufomodels
1079+import madgraph.various.misc as misc
1080
1081 _file_path = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]
1082
1083@@ -144,7 +145,7 @@
1084
1085 self.assertEqual(original_all_particles,ufo_model.all_particles)
1086 self.assertEqual(original_all_vertices,ufo_model.all_vertices)
1087-# self.assertEqual(original_all_couplings,ufo_model.all_couplings)
1088+ self.assertEqual(original_all_couplings,ufo_model.all_couplings)
1089 self.assertEqual(original_all_lorentz,ufo_model.all_lorentz)
1090 self.assertEqual(original_all_parameters,ufo_model.all_parameters)
1091 self.assertEqual(original_all_orders,ufo_model.all_orders)
1092@@ -152,6 +153,34 @@
1093 self.assertEqual(original_all_CTvertices,ufo_model.all_CTvertices)
1094 self.assertEqual(original_all_CTparameters,ufo_model.all_CTparameters)
1095
1096+ # Also test that one new lorentz struture has been added within the model
1097+ # and that the associate optimization is working as expected.
1098+ self.assertEqual(len(original_all_lorentz) + 1, len(model['lorentz']))
1099+ new_l = [l for l in model['lorentz'] if l not in original_all_lorentz][0]
1100+ new_name = new_l.name
1101+ self.assertEqual(new_l.name, 'R2RGA_VVVV1')
1102+ # find interactions with that lorentz structure
1103+ int_with_it = []
1104+ for id, vertices in model.get('interaction_dict').items():
1105+ if new_name in vertices['lorentz']:
1106+ int_with_it.append(vertices)
1107+ self.assertEqual(len(int_with_it), 2)
1108+ # check the first one
1109+ vert = int_with_it[0]
1110+ pdg = [p['pdg_code'] for p in vert['particles']]
1111+ self.assertEqual(pdg, [21,21,21,21])
1112+ # check the equivalent vertex in the original model
1113+ old_vert = [ v for v in ufo_model.all_CTvertices if pdg == [p.pdg_code for p in v.particles]]
1114+ #pick one
1115+ old_vert = old_vert[0]
1116+
1117+ # find the number of coupling associate to this lorentz structure
1118+ ind = vert['lorentz'].index(new_name)
1119+ coup_name = [ c for ((l,col),c) in vert['couplings'].items() if l ==ind]
1120+ nb_old = len([ c for ((l,col),c) in vert['couplings'].items() if c == coup_name[0]])
1121+ nb_new = len([ c for ((l,col,k),c) in old_vert.couplings.items() if c.name == coup_name[0]])
1122+ self.assertEqual(3*nb_old, nb_new)
1123+
1124 #===============================================================================
1125 # TestRestrictModel
1126 #===============================================================================
1127@@ -241,7 +270,20 @@
1128 self.assertEqual(expected, result)
1129
1130 # check what are the identical coupling
1131- expected = [['GC_100', 'GC_108', 'GC_49', 'GC_45', 'GC_40', 'GC_41', 'GC_104']]
1132+ expected = [[('GC_100',1), ('GC_108',1), ('GC_49',1), ('GC_45',1), ('GC_40',1), ('GC_41',1), ('GC_104',1)],
1133+ [('GC_21', 1), ('GC_27', -1)],
1134+ [('GC_3', 1), ('GC_4', -1)],
1135+ [('GC_39', 1), ('GC_38', -1)],
1136+ [('GC_51', 1), ('GC_50', -1)],
1137+ [('GC_53', 1), ('GC_52', -1)],
1138+ [('GC_56', 1), ('GC_54', -1)],
1139+ [('GC_66', 1), ('GC_67', -1)],
1140+ [('GC_7', 1), ('GC_9', -1)],
1141+ [('GC_70', 1), ('GC_73', -1)],
1142+ [('GC_75', 1), ('GC_74', -1)],
1143+ [('GC_76', 1), ('GC_79', -1)],
1144+ [('GC_77', 1), ('GC_78', -1)],
1145+ [('GC_97', 1), ('GC_96', -1)]]
1146 expected.sort()
1147 iden.sort()
1148 self.assertEqual(expected, iden)
1149@@ -286,28 +328,29 @@
1150
1151 # Check that All the code/model is the one intended for this test
1152 target = [i for i in iden if len(i)==7][0]
1153- GC = target[0]
1154+ target2 = [i[0] for i in target]
1155+ GC = target2[0]
1156
1157 check_content = [['d', 'u', 'w+'], ['s', 'c', 'w+'], ['b', 't', 'w+'], ['u', 'd', 'w+'], ['c', 's', 'w+'], ['t', 'b', 'w+'], ['e-', 've', 'w+'], ['m-', 'vm', 'w+'], ['tt-', 'vt', 'w+'], ['ve', 'e-', 'w+'], ['vm', 'm-', 'w+'], ['vt', 'tt-', 'w+']]
1158 content = [[p.get('name') for p in v.get('particles')] \
1159 for v in self.model.get('interactions') \
1160- if any([c in target for c in v['couplings'].values()])]
1161+ if any([c in target2 for c in v['couplings'].values()])]
1162
1163 self.assertEqual(len(check_content),len(content))#, 'test not up-to-date'
1164
1165 vertex_id = [v.get('id') \
1166 for v in self.model.get('interactions') \
1167- if any([c in target for c in v['couplings'].values()])]
1168+ if any([c in target2 for c in v['couplings'].values()])]
1169
1170
1171 for id in vertex_id:
1172 is_in_target = False
1173 for coup in self.model.get_interaction(id)['couplings'].values():
1174- if coup in target:
1175+ if coup in target2:
1176 is_in_target = True
1177 assert is_in_target == True, 'test not up-to-date'
1178
1179- # check now that everything is fine
1180+ # check now that everything is fine
1181 self.model.merge_iden_couplings(target)
1182 for id in vertex_id:
1183 has_GC = False
1184@@ -316,6 +359,41 @@
1185 if coup == GC:
1186 has_GC = True
1187 self.assertTrue(has_GC, True)
1188+
1189+ # check that the same occur with opposite sign coupling
1190+ target = [i for i in iden if len(i)==2][1]
1191+ target2 = [i[0] for i in target]
1192+ GC = target2[0]
1193+
1194+ check_content = [['a', 'w+', 'w+'], ['e-', 'e-', 'a'], ['mu-', 'mu-', 'a'], ['ta-', 'ta-', 'a']]
1195+ content = [[p.get('name') for p in v.get('particles')] \
1196+ for v in self.model.get('interactions') \
1197+ if any([c in target2 for c in v['couplings'].values()])]
1198+ #content = [[v.get('couplings').values() for p in v.get('particles')] \
1199+ # for v in self.model.get('interactions')]
1200+ self.assertEqual(len(check_content),len(content))#, 'test not up-to-date'
1201+
1202+ vertex_id = [v.get('id') \
1203+ for v in self.model.get('interactions') \
1204+ if any([c in target2[1:] for c in v['couplings'].values()])]
1205+
1206+ for id in vertex_id:
1207+ is_in_target = False
1208+ for coup in self.model.get_interaction(id)['couplings'].values():
1209+ if coup in target2:
1210+ is_in_target = True
1211+ assert is_in_target == True, 'test not up-to-date'
1212+
1213+ self.model.merge_iden_couplings(target)
1214+ for id in vertex_id:
1215+ has_GC = False
1216+ for coup in self.model.get_interaction(id)['couplings'].values():
1217+ self.assertFalse(coup in target[1:])
1218+ if coup == '-%s' % GC:
1219+ has_GC = True
1220+ self.assertTrue(has_GC, True)
1221+
1222+
1223
1224 def test_remove_couplings(self):
1225 """ check that the detection of irrelevant interactions works """
1226@@ -428,7 +506,58 @@
1227 self.assertFalse(param.name in ['ymb'])
1228 if param.name == 'yb':
1229 param.expr == 'ZERO'
1230-
1231+
1232+ def test_get_new_coupling_name(self):
1233+ """ test that the static function get_new_coupling_name
1234+ behaves as expected
1235+ """
1236+
1237+ # reject wrong input
1238+ self.assertRaises(AssertionError, import_ufo.RestrictModel.get_new_coupling_name,
1239+ '','','',0)
1240+ self.assertRaises(AssertionError, import_ufo.RestrictModel.get_new_coupling_name,
1241+ '','','',2.)
1242+ self.assertRaises(AssertionError, import_ufo.RestrictModel.get_new_coupling_name,
1243+ '','1','2',1)
1244+ self.assertRaises(AssertionError, import_ufo.RestrictModel.get_new_coupling_name,
1245+ '',1,1,1)
1246+ self.assertRaises(AssertionError, import_ufo.RestrictModel.get_new_coupling_name,
1247+ 1,'1','1',1)
1248+
1249+ # real test
1250+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1251+ 'GC1', 'GC2', 'GC2', 1), 'GC1')
1252+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1253+ 'GC1', 'GC2', '-GC2', 1), '-GC1')
1254+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1255+ 'GC1', '-GC2', 'GC2', 1), '-GC1')
1256+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1257+ 'GC1', '-GC2', '-GC2', 1), 'GC1')
1258+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1259+ '-GC1', 'GC2', 'GC2', 1), '-GC1')
1260+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1261+ '-GC1', 'GC2', '-GC2', 1), 'GC1')
1262+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1263+ '-GC1', '-GC2', 'GC2', 1), 'GC1')
1264+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1265+ '-GC1', '-GC2', '-GC2', 1), '-GC1')
1266+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1267+ 'GC1', 'GC2', 'GC2', -1), '-GC1')
1268+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1269+ 'GC1', 'GC2', '-GC2', -1), 'GC1')
1270+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1271+ 'GC1', '-GC2', 'GC2', -1), 'GC1')
1272+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1273+ 'GC1', '-GC2', '-GC2', -1), '-GC1')
1274+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1275+ '-GC1', 'GC2', 'GC2', -1), 'GC1')
1276+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1277+ '-GC1', 'GC2', '-GC2', -1), '-GC1')
1278+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1279+ '-GC1', '-GC2', 'GC2', -1), '-GC1')
1280+ self.assertEqual(import_ufo.RestrictModel.get_new_coupling_name(\
1281+ '-GC1', '-GC2', '-GC2', -1), 'GC1')
1282+
1283 def test_restrict_from_a_param_card(self):
1284 """ check the full restriction chain in one case b b~ h """
1285

Subscribers

People subscribed via source and target branches

to all changes: