Merge lp:~maddevelopers/mg5amcnlo/plugin_mode into lp:~maddevelopers/mg5amcnlo/2.5.0

Proposed by Olivier Mattelaer
Status: Merged
Merged at revision: 287
Proposed branch: lp:~maddevelopers/mg5amcnlo/plugin_mode
Merge into: lp:~maddevelopers/mg5amcnlo/2.5.0
Diff against target: 9201 lines (+3074/-1601)
116 files modified
UpdateNotes.txt (+15/-0)
VERSION (+1/-1)
aloha/aloha_writers.py (+15/-16)
aloha/template_files/ixxxxx.cc (+7/-7)
aloha/template_files/oxxxxx.cc (+12/-12)
aloha/template_files/txxxxx.cc (+5/-5)
aloha/template_files/vxxxxx.cc (+7/-7)
bin/mg5_aMC (+21/-4)
madgraph/core/base_objects.py (+11/-7)
madgraph/core/diagram_generation.py (+47/-5)
madgraph/interface/amcatnlo_interface.py (+7/-4)
madgraph/interface/amcatnlo_run_interface.py (+34/-4)
madgraph/interface/common_run_interface.py (+276/-84)
madgraph/interface/extended_cmd.py (+409/-28)
madgraph/interface/loop_interface.py (+315/-17)
madgraph/interface/madevent_interface.py (+6/-4)
madgraph/interface/madgraph_interface.py (+257/-265)
madgraph/interface/master_interface.py (+5/-3)
madgraph/interface/reweight_interface.py (+3/-0)
madgraph/iolibs/export_cpp.py (+461/-363)
madgraph/iolibs/export_fks.py (+38/-6)
madgraph/iolibs/export_v4.py (+379/-315)
madgraph/iolibs/file_writers.py (+2/-1)
madgraph/iolibs/group_subprocs.py (+2/-3)
madgraph/iolibs/template_files/read_slha.cc (+24/-26)
madgraph/iolibs/template_files/read_slha.h (+20/-18)
madgraph/iolibs/ufo_expression_parsers.py (+12/-1)
madgraph/loop/loop_diagram_generation.py (+4/-4)
madgraph/loop/loop_exporters.py (+70/-57)
madgraph/various/banner.py (+12/-5)
madgraph/various/misc.py (+90/-8)
madgraph/various/process_checks.py (+13/-21)
models/__init__.py (+2/-2)
models/check_param_card.py (+166/-29)
models/import_ufo.py (+2/-2)
models/model_reader.py (+19/-2)
models/usermod.py (+33/-8)
tests/IOTests.py (+3/-2)
tests/acceptance_tests/test_cmd.py (+4/-1)
tests/acceptance_tests/test_cmd_amcatnlo.py (+6/-1)
tests/acceptance_tests/test_cmd_madevent.py (+80/-3)
tests/acceptance_tests/test_export_fks.py (+23/-0)
tests/acceptance_tests/test_output_files.py (+2/-2)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_dxu_wp%V0_dxu_wp%COLLIER_interface.f (+2/-2)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_dxu_wp%V0_dxu_wp%CT_interface.f (+4/-4)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_dxu_wp%V0_dxu_wp%GOLEM_interface.f (+2/-2)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_dxu_wp%V0_dxu_wp%TIR_interface.f (+4/-50)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_dxu_wp%V0_dxu_wp%born_matrix.f (+4/-4)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_dxu_wp%V0_dxu_wp%loop_matrix.f (+3/-3)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_dxu_wp%V0_dxu_wp%mp_compute_loop_coefs.f (+2/-2)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_udx_wp%V0_udx_wp%COLLIER_interface.f (+2/-2)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_udx_wp%V0_udx_wp%CT_interface.f (+4/-4)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_udx_wp%V0_udx_wp%GOLEM_interface.f (+2/-2)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_udx_wp%V0_udx_wp%TIR_interface.f (+4/-50)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_udx_wp%V0_udx_wp%born_matrix.f (+4/-4)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_udx_wp%V0_udx_wp%loop_matrix.f (+3/-3)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_ppw_fksall/%SubProcesses%P0_udx_wp%V0_udx_wp%mp_compute_loop_coefs.f (+2/-2)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_tdecay_fksreal/%SubProcesses%P0_t_budx%matrix_1.f (+4/-4)
tests/input_files/IOTestsComparison/IOExportFKSTest/test_tdecay_fksreal/%SubProcesses%P0_t_budx%parton_lum_1.f (+2/-2)
tests/input_files/IOTestsComparison/LoopSquaredOrder_IOTest/Loop_sqso_uux_ddx/loop_matrix_QCDQEDpert_QCDsq_gt_0_QEDAmpAndQEDsq_gt_2.f (+1/-1)
tests/input_files/IOTestsComparison/LoopSquaredOrder_IOTest/Loop_sqso_uux_ddx/loop_matrix_QCDQEDpert_WGTsq_le_10_QEDAmpAndQEDsq_gt_2.f (+1/-1)
tests/input_files/IOTestsComparison/MECmdShell/check_html_long_process_strings/info.html (+2/-2)
tests/input_files/IOTestsComparison/MadLoop_output_from_the_interface/TIR_output/%ggttx_IOTest%SubProcesses%MadLoopCommons.f (+3/-3)
tests/input_files/IOTestsComparison/SquaredOrder_IOTest/sqso_uux_uuxuuxx/matrix_ampOrderQED2_eq_2_WGTsq_le_14_QCDsq_gt_4.f (+2/-2)
tests/input_files/IOTestsComparison/long_ML_SMQCD_default/dux_mumvmxg/%..%..%Source%MODEL%couplings.f (+3/-3)
tests/input_files/IOTestsComparison/long_ML_SMQCD_default/dux_mumvmxg/CT_interface.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_default/dux_mumvmxg/born_matrix.f (+2/-2)
tests/input_files/IOTestsComparison/long_ML_SMQCD_default/dux_mumvmxg/loop_matrix.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_default/dux_mumvmxg/mp_born_amps_and_wfs.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_default/gg_wmtbx/%..%..%Source%MODEL%couplings.f (+3/-3)
tests/input_files/IOTestsComparison/long_ML_SMQCD_default/gg_wmtbx/CT_interface.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_default/gg_wmtbx/born_matrix.f (+2/-2)
tests/input_files/IOTestsComparison/long_ML_SMQCD_default/gg_wmtbx/loop_matrix.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_default/gg_wmtbx/mp_born_amps_and_wfs.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_optimized/dux_mumvmxg/%..%..%Source%MODEL%couplings.f (+3/-3)
tests/input_files/IOTestsComparison/long_ML_SMQCD_optimized/dux_mumvmxg/CT_interface.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_optimized/dux_mumvmxg/TIR_interface.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_optimized/dux_mumvmxg/born_matrix.f (+2/-2)
tests/input_files/IOTestsComparison/long_ML_SMQCD_optimized/dux_mumvmxg/loop_matrix.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_optimized/dux_mumvmxg/mp_compute_loop_coefs.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_optimized/gg_wmtbx/%..%..%Source%MODEL%couplings.f (+3/-3)
tests/input_files/IOTestsComparison/long_ML_SMQCD_optimized/gg_wmtbx/CT_interface.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_optimized/gg_wmtbx/TIR_interface.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_optimized/gg_wmtbx/born_matrix.f (+2/-2)
tests/input_files/IOTestsComparison/long_ML_SMQCD_optimized/gg_wmtbx/loop_matrix.f (+1/-1)
tests/input_files/IOTestsComparison/long_ML_SMQCD_optimized/gg_wmtbx/mp_compute_loop_coefs.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_LoopInduced/gg_hh/%..%..%Source%MODEL%couplings.f (+3/-3)
tests/input_files/IOTestsComparison/short_ML_SMQCD_LoopInduced/gg_hh/CT_interface.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_LoopInduced/gg_hh/loop_matrix.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_LoopInduced/gg_hh/mp_born_amps_and_wfs.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_default/ddx_ttx/CT_interface.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_default/ddx_ttx/born_matrix.f (+2/-2)
tests/input_files/IOTestsComparison/short_ML_SMQCD_default/ddx_ttx/loop_matrix.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_default/ddx_ttx/mp_born_amps_and_wfs.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_default/gg_ttx/%..%..%Source%MODEL%couplings.f (+3/-3)
tests/input_files/IOTestsComparison/short_ML_SMQCD_default/gg_ttx/CT_interface.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_default/gg_ttx/born_matrix.f (+2/-2)
tests/input_files/IOTestsComparison/short_ML_SMQCD_default/gg_ttx/loop_matrix.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_default/gg_ttx/mp_born_amps_and_wfs.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_optimized/ddx_ttx/CT_interface.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_optimized/ddx_ttx/TIR_interface.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_optimized/ddx_ttx/born_matrix.f (+2/-2)
tests/input_files/IOTestsComparison/short_ML_SMQCD_optimized/ddx_ttx/loop_matrix.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_optimized/ddx_ttx/mp_compute_loop_coefs.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_optimized/gg_ttx/%..%..%Source%MODEL%couplings.f (+3/-3)
tests/input_files/IOTestsComparison/short_ML_SMQCD_optimized/gg_ttx/CT_interface.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_optimized/gg_ttx/TIR_interface.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_optimized/gg_ttx/born_matrix.f (+2/-2)
tests/input_files/IOTestsComparison/short_ML_SMQCD_optimized/gg_ttx/loop_matrix.f (+1/-1)
tests/input_files/IOTestsComparison/short_ML_SMQCD_optimized/gg_ttx/mp_compute_loop_coefs.f (+1/-1)
tests/unit_tests/core/test_base_objects.py (+1/-1)
tests/unit_tests/iolibs/test_export_cpp.py (+22/-22)
tests/unit_tests/iolibs/test_export_v4.py (+0/-2)
tests/unit_tests/iolibs/test_link_to_ufo.py (+1/-1)
tests/unit_tests/loop/test_loop_exporters.py (+3/-3)
tests/unit_tests/madweight/test_export_v4.py (+2/-2)
To merge this branch: bzr merge lp:~maddevelopers/mg5amcnlo/plugin_mode
Reviewer Review Type Date Requested Status
Valentin Hirschi Approve
Rikkert Frederix Abstain
marco zaro Pending
Review via email: mp+302218@code.launchpad.net

This proposal supersedes a proposal from 2016-06-20.

Description of the change

Hi Guys,

Just changing the target branch for this branch to 2.5.0.

For information I would like to have a freeze version of 2.5.0 the first week of September.
Such that we can play with it for a couple of weeks before releasing it a bit later.
So it would be great if we can move forward on this review (was proposed 2 month ago...)

If you do not want to review this, please abstain.

Cheers,

Olivier

Previous information on the merge request:

This is deep branch which only need to be merged in the next feature release (2.5.0 with collier/PY8)
I propose this for the next bug fixing release (2.4.3) just such that we can move forward on this review.

The changes are pretty simple but at the same time pretty deep.
This version has a new directory PLUGIN where the user can put code to modify the behavior of the code (mainly LO so far).

Three types of plugin can be created:
1) code adding/modifying command to the interface [need to run MG5aMC with ./bin/mg5_aMC --mode=PLUGINNAME]
   This is a mode which is going to be used by maddm for example

2) code defining one (or more) new output mode.
   This is a mode which is used by the MoMenta code (a C++ version of MadWeight develloped in CP3)
   This mode does not need any special command.
   just the usual "output MODE PATH" [where MODE correspond to one of the keyword defined in the plugin]

3) code defining a new/modifying the cluster support
   (just set cluster_type NAME)

So Nothing deep in term of functionality, but it required to re-factorise part of the code in order to have a uniform way to handle the various output mode that we are supporting internally so far.

The details on how to create one of those plugin are available here:
https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/Plugin

Cheers,

Olivier

PS: Valentin if you want to open such plugin idea to MadLoop. This is of course possible.

To post a comment you must log in.
Revision history for this message
Rikkert Frederix (frederix) wrote :

Hi Olivier,

I don't think I'm the right person for this review.
I've got a question, though. There seems to be many little changes in vendor/IREGI and vendor/Cuttools. Why? It doesn't seem related to this branch.

Best,
Rikkert

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

Hi Rik,

> I've got a question, though. There seems to be many little changes in vendor/IREGI and vendor/Cuttools. Why? It doesn’t seem related to this branch.

This branch also contains the latest version of 2.4.3 which are missing in 2.5.0.
This should explain those differences (I never touch expel. Valentin can you cross-check those differences?

Cheers,

Olivier

> On Aug 8, 2016, at 08:39, Rikkert Frederix <email address hidden> wrote:
>
> Review: Abstain
>
> Hi Olivier,
>
> I don't think I'm the right person for this review.
> I've got a question, though. There seems to be many little changes in vendor/IREGI and vendor/Cuttools. Why? It doesn't seem related to this branch.
>
> Best,
> Rikkert
>
> --
> https://code.launchpad.net/~maddevelopers/mg5amcnlo/plugin_mode/+merge/302218
> Your team MadDevelopers is subscribed to branch lp:~maddevelopers/mg5amcnlo/2.5.0.

432. By Valentin Hirschi

1. Restored the correct version of CutTools and IREGI which links against
   their own version of OneLOop with a dedicated namespace.

433. By Olivier Mattelaer

fix a problem with the computation of the dependent parameter in presence of scan/width computation

434. By Olivier Mattelaer

merge with branch question_for_reduction_tools_installation

435. By Olivier Mattelaer

re-allow the Auto in the reweight_card

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

Hi Olivier,

This is a great functionality, especially for the longer term! And if people use it and if there is a clear case for it, we will/should do this as well for NLO/MadLoop indeed.

I tried the examples and it seems to works fine. I would have to develop my own real non-trivial plugin to unravel potential problems, so I only have the following superficial remarks here:

a) For the interface plugin it would be cool if the prompt reflected which plugin the user is in (actually the prompt could be an attribute of the plugin, and if absent it is by default its name).
Maybe also mention on the wiki that people can define their own functions 'complete_<command_name>' and 'help_<command_name>' as well as putting them in the example helloworld.

b) For the output plugin, it would be nice if the user could also redefine what 'launch' does. For now the plugin user simply cannot launch on his own output.

c) I has already tested the cluster type of plugin with my implementation for the SLAC-lsf one, and you had fixed what I had noticed as not working, so this should be fine now.

d) Suggestion: It would be interesting to see if you could also automatically "install" a plugin from a repository somewhere.
So basically implement the command 'install --plugin=<plugin_name>' in madgraph_interface.
This command would look up the repository if the folder '<plugin_name>' exists on the repo and copy it locally in PLUGIN if it does.

e) You should maybe update the wiki page so as to describe the basic plugin 'user_filter.py'.

From the code standpoint, here are my also superficial remarks:

1) Out of curiosity, why was 'using namespace std' not OK for the C++ output?

2) What is the new 'partial_save' of the MG5aMC options?

3) Could we have the plugin user_filter also work for the loops? I can help with this.

If I were to check more detailed things in the code, I'd rather do it live on skype as it is more efficient this way.

Anyway, none of the above is crucial and the unit tests pass (acceptance running now, but so far they're fine).

I therefore accept the merge.

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

Approved

review: Approve
Revision history for this message
Sébastien Wertz (sebastien-wertz) wrote :

> I tried the examples and it seems to works fine. I would have to develop my
> own real non-trivial plugin to unravel potential problems, so I only have the
> following superficial remarks here:

> 1) Out of curiosity, why was 'using namespace std' not OK for the C++ output?

Hi Valentin,

If you want to check a "non-trivial" plugin, you can always try out the C++ one we've written for the MEM: https://github.com/MoMEMta/MoMEMta-MaGMEE. You won't be able to compile the resulting code without installing our framework, but the plugin output works nonetheless.

Regarding the 'using namespace' statements in C++, it's a problem if they are used in header files: any code directly or indirectly including those headers will get polluted by the namespace, which can cause collisions. Those statements should always only be included in non-header files.

Cheers,
Sébastien

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

Thanks a lot for this review

> a) For the interface plugin it would be cool if the prompt reflected which
> plugin the user is in (actually the prompt could be an attribute of the
> plugin, and if absent it is by default its name).

sounds too complicated.

> Maybe also mention on the wiki that people can define their own functions
> 'complete_<command_name>' and 'help_<command_name>' as well as putting them in
> the example helloworld.

Done

> b) For the output plugin, it would be nice if the user could also redefine
> what 'launch' does. For now the plugin user simply cannot launch on his own
> output.

Hum for the moment, I would see that as part of the interface plugin.
I also guess that they are less interest since the idea is typically to run externally to MGaMC

> d) Suggestion: It would be interesting to see if you could also automatically
> "install" a plugin from a repository somewhere.
> So basically implement the command 'install --plugin=<plugin_name>' in
> madgraph_interface.
> This command would look up the repository if the folder '<plugin_name>' exists
> on the repo and copy it locally in PLUGIN if it does.

I agree on the interest. So far no one really show interest in that direction.
If this happens then yes this can be done.

> e) You should maybe update the wiki page so as to describe the basic plugin
> 'user_filter.py'.

This is not really a plugin.
I have create another page for it (under the FAQ of the wiki)
https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/FAQ-General-15

> 2) What is the new 'partial_save' of the MG5aMC options?

Now you can do command like
save options collier
and only collier value will be modified in the mg5_configuration.txt

> 3) Could we have the plugin user_filter also work for the loops? I can help
> with this.

This should be trivial.
But with the level of your loop_filter, I guess that you will want something more refined than my dummy method. If you need help tell me.

> Anyway, none of the above is crucial and the unit tests pass (acceptance
> running now, but so far they're fine).
>
> I therefore accept the merge.

Great thanks.

Cheers,

Olivier

PS: Marco do you plan to review this branch? If not I plan to merge it on Monday. I can obviously wait if you want to take a look.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'PLUGIN'
2=== added file 'PLUGIN/__init__.py'
3=== modified file 'UpdateNotes.txt'
4--- UpdateNotes.txt 2016-08-01 10:08:21 +0000
5+++ UpdateNotes.txt 2016-08-18 22:31:39 +0000
6@@ -1,5 +1,20 @@
7 Update notes for MadGraph5_aMC@NLO (in reverse time order)
8
9+2.5.0
10+ OM: Modify the structure of the output format such that all the internal format have the same structure
11+ OM: Adding the Plugin directory. Three kind of plugin are currently supported
12+ - plugin defining a new type of output format
13+ - plugin defining a new type of cluster handling
14+ - plugin modifying the main interface of MG5aMCnlo
15+ More informations/examples are available here:
16+ https://cp3.irmp.ucl.ac.be/projects/madgraph/wiki/Plugin
17+ VH: adding the possibility to install COLLIER and to use it to reduce the loop-matrix element
18+ OM+VH: At the first loop/NLO computation, a new question will now be asked to choose which program
19+ to install to compute the loop. You can still install additional method later via the "install" command
20+ OM: add an automatic update of the param_card to write the correct value for all dependent parameter.
21+ OM: add the check that the param_card is compatible with the model restriction.
22+ OM+VH:
23+
24 2.4.3 (01/08/16)
25 OM: Reduce the amount of log file/output generated for LO run (output can use up to three times less output).
26 OM: For the LO combination of events (unweighting) pass to the method previously used for loop-induced.
27
28=== modified file 'VERSION'
29--- VERSION 2016-08-01 10:08:21 +0000
30+++ VERSION 2016-08-18 22:31:39 +0000
31@@ -1,4 +1,4 @@
32-version = 2.4.3
33+version = 2.5.0.alpha
34 date = 2016-08-01
35
36
37
38=== modified file 'aloha/aloha_writers.py'
39--- aloha/aloha_writers.py 2016-07-06 08:54:04 +0000
40+++ aloha/aloha_writers.py 2016-08-18 22:31:39 +0000
41@@ -468,10 +468,10 @@
42 'log': 'log(dble(%s))',
43 'asin': 'asin(dble(%s))',
44 'acos': 'acos(dble(%s))',
45- 'abs': 'abs(%s)',
46- 'fabs': 'abs(%s)',
47- 'math.abs': 'abs(%s)',
48- 'cmath.abs': 'abs(%s)',
49+ 'abs': 'std::abs(%s)',
50+ 'fabs': 'std::abs(%s)',
51+ 'math.abs': 'std::abs(%s)',
52+ 'cmath.abs': 'std::abs(%s)',
53 '':'(%s)'
54 }
55
56@@ -1255,14 +1255,14 @@
57 writer = writers.CPPWriter
58
59 type2def = {}
60- type2def['int'] = 'int'
61+ type2def['int'] = 'int '
62 type2def['double'] = 'double '
63- type2def['complex'] = 'complex<double> '
64+ type2def['complex'] = 'std::complex<double> '
65
66 #variable overwritten by gpu
67 realoperator = '.real()'
68 imagoperator = '.imag()'
69- ci_definition = ' complex<double> cI = complex<double>(0.,1.);\n'
70+ ci_definition = 'static std::complex<double> cI = std::complex<double>(0.,1.);\n'
71
72
73 def change_number_format(self, number):
74@@ -1335,7 +1335,7 @@
75 'sqrt': 'sqrt(%s)',
76 'complexconjugate': 'conj(dcmplx(%s))',
77 '/' : '{0}/%s'.format(one),
78- 'abs': 'abs(%s)'
79+ 'abs': 'std::abs(%s)'
80 }
81
82 if fct in self.fct_format:
83@@ -1375,10 +1375,10 @@
84 args.append('%s%s%s'% (type, argname, list_arg))
85
86 if not self.offshell:
87- output = 'complex<double> & vertex'
88+ output = 'std::complex<double> & vertex'
89 #self.declaration.add(('complex','vertex'))
90 else:
91- output = 'complex<double> %(spin)s%(id)d[]' % {
92+ output = 'std::complex<double> %(spin)s%(id)d[]' % {
93 'spin': self.particles[self.outgoing -1],
94 'id': self.outgoing}
95 self.declaration.add(('list_complex', output))
96@@ -1450,7 +1450,7 @@
97
98 for i,type in enumerate(self.particles):
99 if self.declaration.is_used('OM%s' % (i+1)):
100- out.write(" OM{0} = {1};\n if (M{0} != {1})\n OM{0}={2}/pow(M{0},2);\n".format(
101+ out.write(" OM{0} = {1};\n if (M{0} != {1})\n OM{0}={2}/(M{0}*M{0});\n".format(
102 i+1, self.change_number_format(0), self.change_number_format(1)))
103
104 if i+1 == self.outgoing:
105@@ -1551,13 +1551,13 @@
106 out.write(' denom = %(COUP)s/(%(denom)s)\n' % {'COUP': coup_name,\
107 'denom':self.write_obj(self.routine.denominator)})
108 else:
109- out.write(' denom = %(coup)s/(pow(P%(i)s[0],2)-pow(P%(i)s[1],2)-pow(P%(i)s[2],2)-pow(P%(i)s[3],2) - M%(i)s * (M%(i)s -cI* W%(i)s));\n' % \
110+ out.write(' denom = %(coup)s/((P%(i)s[0]*P%(i)s[0])-(P%(i)s[1]*P%(i)s[1])-(P%(i)s[2]*P%(i)s[2])-(P%(i)s[3]*P%(i)s[3]) - M%(i)s * (M%(i)s -cI* W%(i)s));\n' % \
111 {'i': self.outgoing, 'coup': coup_name})
112 else:
113 if self.routine.denominator:
114 raise Exception, 'modify denominator are not compatible with complex mass scheme'
115
116- out.write(' denom = %(coup)s/(pow(P%(i)s[0],2)-pow(P%(i)s[1],2)-pow(P%(i)s[2],2)-pow(P%(i)s[3],2) - pow(M%(i)s,2));\n' % \
117+ out.write(' denom = %(coup)s/((P%(i)s[0]*P%(i)s[0])-(P%(i)s[1]*P%(i)s[1])-(P%(i)s[2]*P%(i)s[2])-(P%(i)s[3]*P%(i)s[3]) - (M%(i)s*M%(i)s));\n' % \
118 {'i': self.outgoing, 'coup': coup_name})
119 self.declaration.add(('complex','denom'))
120 if aloha.loop_mode:
121@@ -1574,7 +1574,7 @@
122 self.write_obj(numerator.get_rep(ind))))
123 return out.getvalue()
124
125- remove_double = re.compile('complex<double> (?P<name>[\w]+)\[\]')
126+ remove_double = re.compile('std::complex<double> (?P<name>[\w]+)\[\]')
127 def define_symmetry(self, new_nb, couplings=None):
128 """Write the call for symmetric routines"""
129 number = self.offshell
130@@ -1594,8 +1594,7 @@
131 if not self.mode == 'no_include':
132 h_string.write('#ifndef '+ self.name + '_guard\n')
133 h_string.write('#define ' + self.name + '_guard\n')
134- h_string.write('#include <complex>\n')
135- h_string.write('using namespace std;\n\n')
136+ h_string.write('#include <complex>\n\n')
137
138 h_header = self.get_header_txt(mode='no_include__is_h', couplings=couplings)
139 h_string.write(h_header)
140
141=== modified file 'aloha/template_files/ixxxxx.cc'
142--- aloha/template_files/ixxxxx.cc 2012-06-13 16:40:13 +0000
143+++ aloha/template_files/ixxxxx.cc 2016-08-18 22:31:39 +0000
144@@ -10,9 +10,9 @@
145 fi[1] = complex<double> (-p[1]*nsf,-p[2]*nsf);
146 nh = nhel*nsf;
147 if (fmass != 0.0) {
148- pp = min(p[0],pow((pow(p[1],2)+pow(p[2],2)+pow(p[3],2)),0.5));
149+ pp = min(p[0],sqrt(p[1]*p[1]+p[2]*p[2]+p[3]*p[3]));
150 if (pp == 0.0){
151- sqm[0] = pow(abs(fmass),0.5);
152+ sqm[0] = sqrt(std::abs(fmass));
153 sqm[1] = Sgn(sqm[0],fmass);
154 ip = (1+nh)/2;
155 im = (1-nh)/2;
156@@ -24,19 +24,19 @@
157 else{
158 sf[0] = (1+nsf+(1-nsf)*nh)*0.5;
159 sf[1] = (1+nsf-(1-nsf)*nh)*0.5;
160- omega[0] = pow(p[0]+pp,0.5);
161+ omega[0] = sqrt(p[0]+pp);
162 omega[1] = fmass/omega[0];
163 ip = (1+nh)/2;
164 im = (1-nh)/2;
165 sfomega[0] = sf[0]*omega[ip];
166 sfomega[1] = sf[1]*omega[im];
167 pp3 = max(pp+p[3], 0.0);
168- chi[0] = complex<double>(pow(pp3*0.5/pp,0.5),0);
169+ chi[0] = complex<double>(sqrt(pp3*0.5/pp),0);
170 if (pp3 == 0.0){
171 chi[1] = complex<double> (-nh,0);
172 }
173 else{
174- chi[1] = complex<double> (nh*p[1],p[2])/pow(2.0*pp*pp3,0.5);
175+ chi[1] = complex<double> (nh*p[1],p[2])/sqrt(2.0*pp*pp3);
176 }
177 fi[2] = sfomega[0]*chi[im];
178 fi[3] = sfomega[0]*chi[ip];
179@@ -49,10 +49,10 @@
180 sqp0p3 = 0.0;
181 }
182 else{
183- sqp0p3 = pow(max(p[0]+p[3],0.0),0.5)*nsf;}
184+ sqp0p3 = sqrt(max(p[0]+p[3],0.0))*nsf;}
185 chi[0] = complex<double>(sqp0p3,0.0);
186 if (sqp0p3 ==0.0){
187- chi[1] = complex<double>(-nhel*pow(2.0*p[0],0.5),0.0);}
188+ chi[1] = complex<double>(-nhel*sqrt(2.0*p[0]),0.0);}
189 else{
190 chi[1] = complex<double>(nh*p[1],p[2])/sqp0p3;}
191 if (nh == 1) {
192
193=== modified file 'aloha/template_files/oxxxxx.cc'
194--- aloha/template_files/oxxxxx.cc 2013-06-06 13:29:17 +0000
195+++ aloha/template_files/oxxxxx.cc 2016-08-18 22:31:39 +0000
196@@ -10,34 +10,34 @@
197 fo[1] = complex<double>(p[1]*nsf,p[2]*nsf);
198 nh = nhel*nsf;
199 if (fmass != 0.000){
200- pp = min(p[0],pow(pow(p[1],2)+pow(p[2],2)+pow(p[3],2),0.5));
201+ pp = min(p[0],sqrt((p[1]*p[1])+(p[2]*p[2])+(p[3]*p[3])));
202 if (pp == 0.000){
203- sqm[0] = pow(abs(fmass),0.5);
204+ sqm[0] = sqrt(std::abs(fmass));
205 sqm[1] = Sgn(sqm[0],fmass);
206 ip = -((1-nh)/2) * nhel ;
207 im = (1+nh)/2 * nhel;
208- fo[2] = im *sqm[abs(ip)];
209- fo[3] = ip*nsf*sqm[abs(ip)];
210- fo[4] = im*nsf*sqm[abs(im)];
211- fo[5] = ip*sqm[abs(im)];
212+ fo[2] = im *sqm[std::abs(ip)];
213+ fo[3] = ip*nsf*sqm[std::abs(ip)];
214+ fo[4] = im*nsf*sqm[std::abs(im)];
215+ fo[5] = ip*sqm[std::abs(im)];
216 }
217 else{
218- pp = min(p[0],pow(pow(p[1],2)+pow(p[2],2)+pow(p[3],2),0.5));
219+ pp = min(p[0],sqrt((p[1]*p[1])+(p[2]*p[2])+(p[3]*p[3])));
220 sf[0] = double(1+nsf+(1-nsf)*nh)*0.5;
221 sf[1] = double(1+nsf-(1-nsf)*nh)*0.5;
222- omega[0] = pow(p[0]+pp,0.5);
223+ omega[0] = sqrt(p[0]+pp);
224 omega[1] = fmass/omega[0];
225 ip = (1+nh)/2 ;
226 im = (1-nh)/2 ;
227 sfomeg[0] = sf[0]*omega[ip];
228 sfomeg[1] = sf[1]*omega[im];
229 pp3 = max(pp+p[3],0.00);
230- chi[0] = complex<double>(pow(pp3*0.5/pp,0.5),0.00);
231+ chi[0] = complex<double>(sqrt(pp3*0.5/pp),0.00);
232 if (pp3 == 0.00){
233 chi[1] = complex<double>(-nh,0.00);
234 }
235 else{
236- chi[1] = complex<double>(nh*p[1],-p[2])/pow(2.0*pp*pp3,0.5);
237+ chi[1] = complex<double>(nh*p[1],-p[2])/sqrt(2.0*pp*pp3);
238 }
239 fo[2] = sfomeg[1]*chi[im];
240 fo[3] = sfomeg[1]*chi[ip];
241@@ -50,11 +50,11 @@
242 sqp0p3 = 0.00;
243 }
244 else{
245- sqp0p3 = pow(max(p[0]+p[3],0.00),0.5)*nsf;
246+ sqp0p3 = sqrt(max(p[0]+p[3],0.00))*nsf;
247 }
248 chi[0] = complex<double>(sqp0p3,0.00);
249 if(sqp0p3 == 0.000){
250- chi[1] = complex<double>(-nhel,0.00)*pow(2.0*p[0],0.5);
251+ chi[1] = complex<double>(-nhel,0.00)*sqrt(2.0*p[0]);
252 }
253 else{
254 chi[1] = complex<double>(nh*p[1],-p[2])/sqp0p3;
255
256=== modified file 'aloha/template_files/txxxxx.cc'
257--- aloha/template_files/txxxxx.cc 2013-05-07 06:35:39 +0000
258+++ aloha/template_files/txxxxx.cc 2016-08-18 22:31:39 +0000
259@@ -11,12 +11,12 @@
260 double pt, pt2, pp, pzpt, emp, sqh, sqs;
261 int i, j;
262
263- sqh = pow( 0.5, 0.5 );
264- sqs = pow( 0.5/3, 0.5 );
265+ sqh = sqrt( 0.5);
266+ sqs = sqrt( 0.5/3);
267
268 pt2 = p[1]*p[1] + p[2]*p[2];
269- pp = min( p[0], pow( pt2+p[3]*p[3], 0.5 ) );
270- pt = min( pp, pow( pt2, 0.5 ) );
271+ pp = min( p[0], sqrt( pt2+p[3]*p[3]) );
272+ pt = min( pp, sqrt( pt2) );
273
274 ft[4][0] = complex<double>( p[0]*nst, p[3]*nst );
275 ft[5][0] = complex<double>( p[1]*nst, p[2]*nst );
276@@ -81,7 +81,7 @@
277 }
278
279 // construct eps0
280- if( fabs(nhel) <= 1 )
281+ if( std::labs(nhel) <= 1 )
282 {
283 if( pp == 0 )
284 {
285
286=== modified file 'aloha/template_files/vxxxxx.cc'
287--- aloha/template_files/vxxxxx.cc 2012-06-13 16:40:13 +0000
288+++ aloha/template_files/vxxxxx.cc 2016-08-18 22:31:39 +0000
289@@ -5,16 +5,16 @@
290 void vxxxxx(double p[4],double vmass,int nhel,int nsv, complex<double> vc[6]){
291 double hel,hel0,pt,pt2,pp,pzpt,emp,sqh;
292 int nsvahl;
293- sqh = pow(0.5,0.5);
294+ sqh = sqrt(0.5);
295 hel = double(nhel);
296- nsvahl = nsv*abs(hel);
297- pt2 = pow(p[1],2)+pow(p[2],2);
298- pp = min(p[0],pow(pt2+pow(p[3],2),0.5));
299- pt =min(pp,pow(pt2,0.5));
300+ nsvahl = nsv*std::abs(hel);
301+ pt2 = (p[1]*p[1])+(p[2]*p[2]);
302+ pp = min(p[0],sqrt(pt2+(p[3]*p[3])));
303+ pt =min(pp,sqrt(pt2));
304 vc[0] = complex<double>(p[0]*nsv,p[3]*nsv);
305 vc[1] = complex<double>(p[1]*nsv,p[2]*nsv);
306 if (vmass != 0.0){
307- hel0 = 1.0-abs(hel);
308+ hel0 = 1.0-std::abs(hel);
309 if( pp == 0.0 ){
310 vc[2] = complex<double>(0.0,0.0);
311 vc[3] = complex<double>(-hel*sqh,0.0);
312@@ -38,7 +38,7 @@
313 }
314 else{
315 pp = p[0];
316- pt = pow(pow(p[1],2)+pow(p[2],2),0.5);
317+ pt = sqrt((p[1]*p[1])+(p[2]*p[2]));
318 vc[2] = complex<double>(0.0,0.0);
319 vc[5] = complex<double>(hel*pt/pp*sqh,0.0);
320 if (pt != 0.0) {
321
322=== modified file 'bin/mg5_aMC'
323--- bin/mg5_aMC 2016-03-03 16:31:52 +0000
324+++ bin/mg5_aMC 2016-08-18 22:31:39 +0000
325@@ -45,6 +45,9 @@
326 help='force to be in secure mode')
327 parser.add_option("","--debug", action="store_true", default=False, dest='debug', \
328 help='force to launch debug mode')
329+parser.add_option("-m", "--mode", dest="plugin",
330+ help="Define some additional command provide by a PLUGIN")
331+
332 (options, args) = parser.parse_args()
333 if len(args) == 0:
334 args = ''
335@@ -119,6 +122,24 @@
336 pass
337 import madgraph.interface.master_interface as interface
338
339+if options.plugin:
340+ if not os.path.exists(os.path.join(root_path, 'PLUGIN', options.plugin)):
341+ print "ERROR: %s is not present in the PLUGIN directory. Please install it first"
342+ __import__('PLUGIN.%s' % options.plugin)
343+ plugin = sys.modules['PLUGIN.%s' % options.plugin]
344+ if not plugin.new_interface:
345+ logging.warning("Plugin: %s do not define dedicated interface and should be used without the --mode options" % options.plugin)
346+ sys.exit()
347+ import madgraph.various.misc as misc
348+ if not misc.is_plugin_supported(plugin):
349+ sys.exit()
350+ cmd_line = plugin.new_interface(mgme_dir = options.mgme_dir)
351+ cmd_line.plugin=options.plugin
352+elif options.web:
353+ cmd_line = interface.MasterCmdWeb()
354+else:
355+ cmd_line = interface.MasterCmd(mgme_dir = options.mgme_dir)
356+
357 # Call the cmd interface main loop
358 try:
359 if options.file or args:
360@@ -128,14 +149,12 @@
361 else:
362 input_file = os.path.realpath(options.file)
363 if options.web:
364- cmd_line = interface.MasterCmdWeb()
365 cmd_line.debug_output = os.path.join(os.path.dirname(input_file),'generation.log')
366 cmd_line.use_rawinput = False
367 cmd_line.haspiping = False
368 cmd_line.run_cmd('import ' + input_file)
369 cmd_line.run_cmd('quit')
370 else:
371- cmd_line = interface.MasterCmd(mgme_dir = options.mgme_dir)
372 cmd_line.use_rawinput = False
373 cmd_line.haspiping = False
374 cmd_line.run_cmd('import ' + input_file)
375@@ -147,10 +166,8 @@
376 os.environ['MADGRAPH_DATA'] = root_path
377 os.environ['MADGRAPH_BASE'] = os.path.join(root_path,'input')
378 os.environ['REMOTE_USER'] = 'webmode'
379- cmd_line = interface.MasterCmdWeb()
380 cmd_line.cmdloop()
381 else:
382- cmd_line = interface.MasterCmd(mgme_dir = options.mgme_dir)
383 cmd_line.cmdloop()
384 except KeyboardInterrupt:
385 print 'writting history and quit on KeyboardInterrupt'
386
387=== modified file 'madgraph/core/base_objects.py'
388--- madgraph/core/base_objects.py 2016-08-14 00:17:23 +0000
389+++ madgraph/core/base_objects.py 2016-08-18 22:31:39 +0000
390@@ -1587,15 +1587,19 @@
391 return [c for c in range(1, len(self.get('particles')) + 1) if \
392 c not in self.get('particle_dict').keys()][0]
393
394- def write_param_card(self):
395+ def write_param_card(self, filepath=None):
396 """Write out the param_card, and return as string."""
397
398 import models.write_param_card as writer
399- out = StringIO.StringIO() # it's suppose to be written in a file
400- param = writer.ParamCardWriter(self)
401- param.define_output_file(out)
402- param.write_card()
403- return out.getvalue()
404+ if not filepath:
405+ out = StringIO.StringIO() # it's suppose to be written in a file
406+ else:
407+ out = filepath
408+ param = writer.ParamCardWriter(self, filepath=out)
409+ if not filepath:
410+ return out.getvalue()
411+ else:
412+ return param
413
414 @ staticmethod
415 def load_default_name():
416@@ -3014,7 +3018,7 @@
417 if self['constrained_orders']:
418 mystr = mystr + " ".join('%s%s%d' % (key,
419 self['constrained_orders'][key][1], self['constrained_orders'][key][0])
420- for (key,(value,type)) in sorted(self['constrained_orders'].keys())) + ' '
421+ for key in sorted(self['constrained_orders'].keys())) + ' '
422
423 # Add perturbation_couplings
424 if self['perturbation_couplings']:
425
426=== modified file 'madgraph/core/diagram_generation.py'
427--- madgraph/core/diagram_generation.py 2016-02-27 14:33:01 +0000
428+++ madgraph/core/diagram_generation.py 2016-08-18 22:31:39 +0000
429@@ -496,7 +496,7 @@
430
431 return self.get('process').get('perturbation_couplings')
432
433- def generate_diagrams(self, returndiag=False):
434+ def generate_diagrams(self, returndiag=False, diagram_filter=False):
435 """Generate diagrams. Algorithm:
436
437 1. Define interaction dictionaries:
438@@ -792,6 +792,9 @@
439 if not returndiag and len(res)>0:
440 res = self.apply_squared_order_constraints(res)
441
442+ if diagram_filter:
443+ res = self.apply_user_filter(res)
444+
445 # Replace final id=0 vertex if necessary
446 if not process.get('is_decay_chain'):
447 for diagram in res:
448@@ -884,6 +887,41 @@
449
450 return res
451
452+ def apply_user_filter(self, diag_list):
453+ """Applies the user specified squared order constraints on the diagram
454+ list in argument."""
455+
456+ if True:
457+ try:
458+ from PLUGIN.user_filter import remove_diag
459+ except ImportError:
460+ raise MadGraph5Error, 'user filter required to be defined in PLUGIN/user_filter.py with the function remove_diag(ONEDIAG) which returns True if the daigram has to be removed'
461+ else:
462+ #example and simple tests
463+ def remove_diag(diag):
464+ for vertex in diag['vertices']: #last
465+ if vertex['id'] == 0: #special final vertex
466+ continue
467+ if vertex['legs'][-1]['number'] < 3: #this means T-channel
468+ if abs(vertex['legs'][-1]['id']) <6:
469+ return True
470+ return False
471+
472+ res = diag_list.__class__()
473+ nb_removed = 0
474+ for diag in diag_list:
475+ if remove_diag(diag):
476+ nb_removed +=1
477+ else:
478+ res.append(diag)
479+
480+ if nb_removed:
481+ logger.warning('Diagram filter is ON and removed %s diagrams for this subprocess.' % nb_removed)
482+
483+ return res
484+
485+
486+
487 def create_diagram(self, vertexlist):
488 """ Return a Diagram created from the vertex list. This function can be
489 overloaded by daughter classes."""
490@@ -1526,7 +1564,7 @@
491
492 def __init__(self, argument=None, collect_mirror_procs = False,
493 ignore_six_quark_processes = [], optimize=False,
494- loop_filter=None):
495+ loop_filter=None, diagram_filter=None):
496 """Allow initialization with ProcessDefinition or
497 ProcessDefinitionList
498 optimize allows to use param_card information. (usefull for 1-.N)"""
499@@ -1548,6 +1586,7 @@
500 self['ignore_six_quark_processes'] = ignore_six_quark_processes
501 self['use_numerical'] = optimize
502 self['loop_filter'] = loop_filter
503+ self['diagram_filter'] = diagram_filter # only True/False so far
504
505 if isinstance(argument, base_objects.ProcessDefinition) or \
506 isinstance(argument, base_objects.ProcessDefinitionList):
507@@ -1598,7 +1637,8 @@
508 self.get('collect_mirror_procs'),
509 self.get('ignore_six_quark_processes'),
510 self['use_numerical'],
511- loop_filter=self['loop_filter']))
512+ loop_filter=self['loop_filter'],
513+ diagram_filter=self['diagram_filter']))
514
515 return MultiProcess.__bases__[0].get(self, name) # call the mother routine
516
517@@ -1612,7 +1652,8 @@
518 collect_mirror_procs = False,
519 ignore_six_quark_processes = [],
520 use_numerical=False,
521- loop_filter=None):
522+ loop_filter=None,
523+ diagram_filter=False):
524 """Generate amplitudes in a semi-efficient way.
525 Make use of crossing symmetry for processes that fail diagram
526 generation, but not for processes that succeed diagram
527@@ -1682,6 +1723,7 @@
528 sorted_legs = sorted([(l,i+1) for (i,l) in \
529 enumerate(legs.get_outgoing_id_list(model))])
530 permutation = [l[1] for l in sorted_legs]
531+
532 sorted_legs = array.array('i', [l[0] for l in sorted_legs])
533
534 # Check for six-quark processes
535@@ -1769,7 +1811,7 @@
536 loop_filter=loop_filter)
537
538 try:
539- result = amplitude.generate_diagrams()
540+ result = amplitude.generate_diagrams(diagram_filter=diagram_filter)
541 except InvalidCmd as error:
542 failed_procs.append(sorted_legs)
543 else:
544
545=== modified file 'madgraph/interface/amcatnlo_interface.py'
546--- madgraph/interface/amcatnlo_interface.py 2016-05-24 09:52:16 +0000
547+++ madgraph/interface/amcatnlo_interface.py 2016-08-18 22:31:39 +0000
548@@ -45,9 +45,11 @@
549 import madgraph.fks.fks_helas_objects as fks_helas
550 import madgraph.iolibs.export_fks as export_fks
551 import madgraph.iolibs.export_v4 as export_v4
552+import madgraph.iolibs.helas_call_writers as helas_call_writers
553 import madgraph.loop.loop_base_objects as loop_base_objects
554 import madgraph.core.diagram_generation as diagram_generation
555 import madgraph.core.helas_objects as helas_objects
556+
557 import madgraph.various.cluster as cluster
558 import madgraph.various.misc as misc
559 import madgraph.various.banner as banner_mod
560@@ -261,7 +263,7 @@
561 return self.list_completion(text, content)
562
563
564- def complete_launch(self, text, line, begidx, endidx):
565+ def complete_launch(self, text, line, begidx, endidx, formatting=True):
566 """ complete the launch command"""
567 args = self.split_arg(line[0:begidx])
568
569@@ -299,7 +301,7 @@
570 out['Options'] = self.list_completion(text, opt, line)
571
572
573- return self.deal_multiple_categories(out)
574+ return self.deal_multiple_categories(out, formatting)
575
576 class HelpFKS(mg_interface.HelpToCmd):
577
578@@ -562,6 +564,7 @@
579 def export(self, nojpeg = False, main_file_name = "", group_processes=False):
580 """Export a generated amplitude to file"""
581
582+ self._curr_helas_model = helas_call_writers.FortranUFOHelasCallWriter(self._curr_model)
583 def generate_matrix_elements(self, group=False):
584 """Helper function to generate the matrix elements before
585 exporting"""
586@@ -659,14 +662,14 @@
587 #me is a FKSHelasProcessFromReals
588 calls = calls + \
589 self._curr_exporter.generate_directories_fks(me,
590- self._curr_fortran_model,
591+ self._curr_helas_model,
592 ime, len(self._curr_matrix_elements.get('matrix_elements')),
593 path,self.options['OLP'])
594 self._fks_directories.extend(self._curr_exporter.fksdirs)
595 self.born_processes_for_olp.append(me.born_matrix_element.get('processes')[0])
596 else:
597 glob_directories_map.append(\
598- [self._curr_exporter, me, self._curr_fortran_model,
599+ [self._curr_exporter, me, self._curr_helas_model,
600 ime, len(self._curr_matrix_elements.get('matrix_elements')),
601 path, self.options['OLP']])
602
603
604=== modified file 'madgraph/interface/amcatnlo_run_interface.py'
605--- madgraph/interface/amcatnlo_run_interface.py 2016-07-02 20:34:59 +0000
606+++ madgraph/interface/amcatnlo_run_interface.py 2016-08-18 22:31:39 +0000
607@@ -87,7 +87,7 @@
608 import madgraph.various.shower_card as shower_card
609 import madgraph.various.FO_analyse_card as analyse_card
610 import madgraph.various.histograms as histograms
611- from madgraph import InvalidCmd, aMCatNLOError, MadGraph5Error
612+ from madgraph import InvalidCmd, aMCatNLOError, MadGraph5Error,MG5DIR
613
614 class aMCatNLOError(Exception):
615 pass
616@@ -774,7 +774,7 @@
617 opts += opt._long_opts + opt._short_opts
618 return self.list_completion(text, opts, line)
619
620- def complete_banner_run(self, text, line, begidx, endidx):
621+ def complete_banner_run(self, text, line, begidx, endidx, formatting=True):
622 "Complete the banner run command"
623 try:
624
625@@ -812,7 +812,7 @@
626 run_list = [n.rsplit('/',2)[1] for n in run_list]
627 possibilites['RUN Name'] = self.list_completion(text, run_list)
628
629- return self.deal_multiple_categories(possibilites)
630+ return self.deal_multiple_categories(possibilites, formatting)
631
632
633 except Exception, error:
634@@ -1247,6 +1247,7 @@
635 with misc.TMP_variable(self, 'allow_notification_center', False):
636 for i,card in enumerate(param_card_iterator):
637 card.write(pjoin(self.me_dir,'Cards','param_card.dat'))
638+ self.check_param_card(pjoin(self.me_dir,'Cards','param_card.dat'), dependent=True)
639 if not options['force']:
640 options['force'] = True
641 if options['run_name']:
642@@ -2127,7 +2128,36 @@
643 """setup the number of cores for multicore, and the cluster-type for cluster runs"""
644 if self.cluster_mode == 1:
645 cluster_name = self.options['cluster_type']
646- self.cluster = cluster.from_name[cluster_name](**self.options)
647+ try:
648+ self.cluster = cluster.from_name[cluster_name](**self.options)
649+ except KeyError:
650+ if aMCatNLO and ('mg5_path' not in self.options or not self.options['mg5_path']):
651+ raise self.InvalidCmd('%s not native cluster type and not MG5aMC found to check for plugin' % cluster_name)
652+ elif aMCatNLO:
653+ mg5dir = self.options['mg5_path']
654+ if mg5dir not in sys.path:
655+ sys.path.append(mg5dir)
656+ else:
657+ mg5dir = MG5DIR
658+ # Check if a plugin define this type of cluster
659+ # check for PLUGIN format
660+ for plug in os.listdir(pjoin(mg5dir, 'PLUGIN')):
661+ if os.path.exists(pjoin(mg5dir, 'PLUGIN', plug, '__init__.py')):
662+ try:
663+ __import__('PLUGIN.%s' % plug)
664+ except Exception, error:
665+ logger.critical('plugin directory %s fail to be loaded. Please check it', plug)
666+ continue
667+ plugin = sys.modules['PLUGIN.%s' % plug]
668+ if not hasattr(plugin, 'new_cluster'):
669+ continue
670+ if not misc.is_plugin_supported(plugin):
671+ continue
672+ if cluster_name in plugin.new_cluster:
673+ logger.info("cluster handling will be done with PLUGIN: %s" % plug,'$MG:color:BLACK')
674+ self.cluster = plugin.new_cluster[cluster_name](**self.options)
675+ break
676+
677 if self.cluster_mode == 2:
678 try:
679 import multiprocessing
680
681=== modified file 'madgraph/interface/common_run_interface.py'
682--- madgraph/interface/common_run_interface.py 2016-07-29 15:27:30 +0000
683+++ madgraph/interface/common_run_interface.py 2016-08-18 22:31:39 +0000
684@@ -739,12 +739,25 @@
685 param = param_card['decay'].get((part.pdg_code,))
686
687 if param.value != 0:
688- logger.info('''For gauge cancellation, the width of \'%s\' has been set to zero.'''
689+ logger.info('''For gauge cancellation, the width of \'%s\' has been set to zero.'''\
690 % part.name,'$MG:color:BLACK')
691 param.value = 0
692
693 param_card.write_inc_file(outfile, ident_card, default)
694
695+ def get_model(self):
696+ """return the model related to this process"""
697+
698+ if self.options['mg5_path']:
699+ sys.path.append(self.options['mg5_path'])
700+ import models.import_ufo as import_ufo
701+ with misc.MuteLogger(['madgraph.model'],[50]):
702+ out= import_ufo.import_model(pjoin(self.me_dir,'bin','internal','ufomodel'))
703+ return out
704+ elif self.mother:
705+ return self.mother._curr_model
706+ else:
707+ return None
708
709 def ask_edit_cards(self, cards, mode='fixed', plot=True, first_cmd=None):
710 """ """
711@@ -1685,16 +1698,47 @@
712 if self.cluster_mode == 1:
713 opt = self.options
714 cluster_name = opt['cluster_type']
715- self.cluster = cluster.from_name[cluster_name](**opt)
716-
717-
718- def check_param_card(self, path, run=True):
719+ if cluster_name in cluster.from_name:
720+ self.cluster = cluster.from_name[cluster_name](**opt)
721+ else:
722+ if MADEVENT and ('mg5_path' not in self.options or not self.options['mg5_path']):
723+ raise self.InvalidCmd('%s not native cluster type and not MG5aMC found to check for plugin')
724+ elif MADEVENT:
725+ mg5dir = self.options['mg5_path']
726+ if mg5dir not in sys.path:
727+ sys.path.append(mg5dir)
728+ else:
729+ mg5dir = MG5DIR
730+ # Check if a plugin define this type of cluster
731+ # check for PLUGIN format
732+ for plug in os.listdir(pjoin(mg5dir, 'PLUGIN')):
733+ if os.path.exists(pjoin(mg5dir, 'PLUGIN', plug, '__init__.py')):
734+ try:
735+ __import__('PLUGIN.%s' % plug)
736+ except Exception, error:
737+ logger.critical('plugin directory %s fail to be loaded. Please check it', plug)
738+ continue
739+ plugin = sys.modules['PLUGIN.%s' % plug]
740+ if not hasattr(plugin, 'new_cluster'):
741+ continue
742+ if not misc.is_plugin_supported(plugin):
743+ continue
744+ if cluster_name in plugin.new_cluster:
745+ logger.info("cluster handling will be done with PLUGIN: %s" % plug,'$MG:color:BLACK')
746+ self.cluster = plugin.new_cluster[cluster_name](**opt)
747+ break
748+ else:
749+ raise self.InvalidCmd, "%s is not recognized as a supported cluster format." % cluster_name
750+
751+
752+ def check_param_card(self, path, run=True, dependent=False):
753 """
754 1) Check that no scan parameter are present
755 2) Check that all the width are define in the param_card.
756 - If a scan parameter is define. create the iterator and recall this fonction
757 on the first element.
758- - If some width are set on 'Auto', call the computation tools."""
759+ - If some width are set on 'Auto', call the computation tools.
760+ 3) if dependent is on True check for dependent parameter (automatic for scan)"""
761
762 pattern_scan = re.compile(r'''^(decay)?[\s\d]*scan''', re.I+re.M)
763 pattern_width = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I)
764@@ -1709,7 +1753,7 @@
765 self.param_card_iterator = main_card
766 first_card = main_card.next(autostart=True)
767 first_card.write(path)
768- return self.check_param_card(path, run)
769+ return self.check_param_card(path, run, dependent=True)
770
771 pdg_info = pattern_width.findall(text)
772 if pdg_info:
773@@ -1720,13 +1764,18 @@
774 if not has_nlo:
775 self.do_compute_widths('%s %s' % (' '.join(pdg), path))
776 else:
777- self.do_compute_widths('%s %s --nlo' % (' '.join(pdg), path))
778+ self.do_compute_widths('%s %s --nlo' % (' '.join(pdg), path))
779 else:
780 logger.info('''Some width are on Auto in the card.
781 Those will be computed as soon as you have finish the edition of the cards.
782 If you want to force the computation right now and being able to re-edit
783 the cards afterwards, you can type \"compute_wdiths\".''')
784-
785+
786+ if dependent:
787+ card = check_param_card.ParamCard(path)
788+ AskforEditCard.update_dependent(self, self.me_dir, card, path, timer=20)
789+
790+ return
791
792 def add_error_log_in_html(self, errortype=None):
793 """If a ME run is currently running add a link in the html output"""
794@@ -2138,7 +2187,7 @@
795
796
797
798- def complete_compute_widths(self, text, line, begidx, endidx):
799+ def complete_compute_widths(self, text, line, begidx, endidx, formatting=True):
800 "Complete the compute_widths command"
801
802 args = self.split_arg(line[0:begidx])
803@@ -2158,7 +2207,7 @@
804 ['--path=', '--output=', '--min_br=0.\$', '--nlo',
805 '--precision_channel=0.\$', '--body_decay='])
806
807- return self.deal_multiple_categories(completion)
808+ return self.deal_multiple_categories(completion, formatting)
809
810
811 def update_make_opts(self):
812@@ -2376,7 +2425,7 @@
813 filename = pdf_info[filename]['filename']
814
815 if os.path.exists(pjoin(pdfsets_dir, filename)):
816- logger.debug('%s is already present in %s', (filename, pdfsets_dir))
817+ logger.debug('%s is already present in %s', filename, pdfsets_dir)
818 return
819
820 logger.info('Trying to download %s' % filename)
821@@ -2530,38 +2579,76 @@
822 'fixed_scale': ['run_card fixed_fac_scale T', 'run_card fixed_ren_scale T', 'run_card scale %(0)s', 'run_card dsqrt_q2fact1 %(0)s' ,'run_card dsqrt_q2fact2 %(0)s'],
823 }
824
825- def __init__(self, question, cards=[], mode='auto', *args, **opt):
826-
827+ def load_default(self):
828+ """ define all default variable. No load of card here.
829+ This allow to subclass this class and just change init and still have
830+ all variables defined."""
831+
832+ self.me_dir = None
833+ self.param_card = None
834+ self.run_card = {}
835+ self.pname2block = {}
836+ self.conflict = []
837+ self.restricted_value = {}
838+ self.mode = ''
839+ self.cards = []
840+ self.run_set = []
841+ self.has_mw = False
842+ self.has_ml = False
843+ self.has_shower = False
844+ self.paths = {}
845+
846+ def define_paths(self, **opt):
847+
848 # Initiation
849 if 'pwd' in opt:
850 self.me_dir = opt['pwd']
851- del opt['pwd']
852-
853- cmd.OneLinePathCompletion.__init__(self, question, *args, **opt)
854-
855+ elif 'mother_interface' in opt:
856+ self.mother_interface = opt['mother_interface']
857 if not hasattr(self, 'me_dir') or not self.me_dir:
858 self.me_dir = self.mother_interface.me_dir
859-
860- # read the card
861+
862+ #define paths
863+ self.paths['param'] = pjoin(self.me_dir,'Cards','param_card.dat')
864+ self.paths['param_default'] = pjoin(self.me_dir,'Cards','param_card_default.dat')
865+ self.paths['run'] = pjoin(self.me_dir,'Cards','run_card.dat')
866+ self.paths['run_default'] = pjoin(self.me_dir,'Cards','run_card_default.dat')
867+ self.paths['transfer'] =pjoin(self.me_dir,'Cards','transfer_card.dat')
868+ self.paths['MadWeight'] =pjoin(self.me_dir,'Cards','MadWeight_card.dat')
869+ self.paths['MadWeight_default'] =pjoin(self.me_dir,'Cards','MadWeight_card_default.dat')
870+ self.paths['ML'] =pjoin(self.me_dir,'Cards','MadLoopParams.dat')
871+ self.paths['shower'] = pjoin(self.me_dir,'Cards','shower_card.dat')
872+ self.paths['shower_default'] = pjoin(self.me_dir,'Cards','shower_card_default.dat')
873+ self.paths['pythia'] =pjoin(self.me_dir, 'Cards','pythia_card.dat')
874+ self.paths['madspin_default'] = pjoin(self.me_dir,'Cards/madspin_card_default.dat')
875+ self.paths['madspin'] = pjoin(self.me_dir,'Cards/madspin_card.dat')
876+ self.paths['reweight'] = pjoin(self.me_dir,'Cards','reweight_card.dat')
877+ self.paths['delphes'] = pjoin(self.me_dir,'Cards','delphes_card.dat')
878+
879+ def __init__(self, question, cards=[], mode='auto', *args, **opt):
880+
881+ self.load_default()
882+ self.define_paths(**opt)
883+ cmd.OneLinePathCompletion.__init__(self, question, *args, **opt)
884
885
886 try:
887- self.param_card = check_param_card.ParamCard(pjoin(self.me_dir,'Cards','param_card.dat'))
888+ self.param_card = check_param_card.ParamCard(self.paths['param'])
889 except (check_param_card.InvalidParamCard, ValueError) as e:
890 logger.error('Current param_card is not valid. We are going to use the default one.')
891 logger.error('problem detected: %s' % e)
892 files.cp(pjoin(self.me_dir,'Cards','param_card_default.dat'),
893 pjoin(self.me_dir,'Cards','param_card.dat'))
894- self.param_card = check_param_card.ParamCard(pjoin(self.me_dir,'Cards','param_card.dat'))
895- default_param = check_param_card.ParamCard(pjoin(self.me_dir,'Cards','param_card_default.dat'))
896+ self.param_card = check_param_card.ParamCard(self.paths['param'])
897+ default_param = check_param_card.ParamCard(self.paths['param_default'])
898
899
900 try:
901- self.run_card = banner_mod.RunCard(pjoin(self.me_dir,'Cards','run_card.dat'))
902+ self.run_card = banner_mod.RunCard(self.paths['run'])
903 except IOError:
904 self.run_card = {}
905 try:
906- run_card_def = banner_mod.RunCard(pjoin(self.me_dir,'Cards','run_card_default.dat'))
907+ run_card_def = banner_mod.RunCard(self.paths['run_default'])
908 except IOError:
909 run_card_def = {}
910
911@@ -2596,7 +2683,7 @@
912 self.do_change_tf = self.mother_interface.do_define_transfer_fct
913 self.complete_change_tf = self.mother_interface.complete_define_transfer_fct
914 self.help_change_tf = self.mother_interface.help_define_transfer_fct
915- if not os.path.exists(pjoin(self.me_dir,'Cards','transfer_card.dat')):
916+ if not os.path.exists(self.paths['transfer']):
917 logger.warning('No transfer function currently define. Please use the change_tf command to define one.')
918
919
920@@ -2605,7 +2692,7 @@
921 import madgraph.madweight.Cards as mwcards
922 except:
923 import internal.madweight.Cards as mwcards
924- self.mw_card = mwcards.Card(pjoin(self.me_dir,'Cards','MadWeight_card.dat'))
925+ self.mw_card = mwcards.Card(self.paths['MadWeight'])
926 self.mw_card = self.mw_card.info
927 self.mw_vars = []
928 for key in self.mw_card:
929@@ -2625,9 +2712,9 @@
930
931 #check if MadLoopParams.dat is present:
932 self.has_ml = False
933- if os.path.isfile(pjoin(self.me_dir,'Cards','MadLoopParams.dat')):
934+ if os.path.isfile(self.paths['ML']):
935 self.has_ml = True
936- self.MLcard = banner_mod.MadLoopParam(pjoin(self.me_dir,'Cards','MadLoopParams.dat'))
937+ self.MLcard = banner_mod.MadLoopParam(self.paths['ML'])
938 self.MLcardDefault = banner_mod.MadLoopParam()
939
940 self.ml_vars = [k.lower() for k in self.MLcard.keys()]
941@@ -2648,7 +2735,7 @@
942 import madgraph.various.shower_card as showercards
943 except:
944 import internal.shower_card as showercards
945- self.shower_card = showercards.ShowerCard(pjoin(self.me_dir,'Cards','shower_card.dat'))
946+ self.shower_card = showercards.ShowerCard(self.paths['shower'])
947 self.shower_vars = self.shower_card.keys()
948
949 # check for conflict with run_card/param_card
950@@ -2660,7 +2747,7 @@
951 self.conflict.append(var)
952
953
954- def complete_set(self, text, line, begidx, endidx):
955+ def complete_set(self, text, line, begidx, endidx, formatting=True):
956 """ Complete the set command"""
957
958 prev_timer = signal.alarm(0) # avoid timer if any
959@@ -2838,7 +2925,7 @@
960 possibilities['Special value'] = self.list_completion(text, opts)
961 possibilities['MadWeight Card id' ] = self.list_completion(text, ids)
962
963- return self.deal_multiple_categories(possibilities)
964+ return self.deal_multiple_categories(possibilities, formatting)
965
966 def do_set(self, line):
967 """ edit the value of one parameter in the card"""
968@@ -2893,7 +2980,7 @@
969
970 # Special case for the qcut value
971 if args[0].lower() == 'qcut':
972- pythia_path = pjoin(self.me_dir, 'Cards','pythia_card.dat')
973+ pythia_path = self.paths['pythia']
974 if os.path.exists(pythia_path):
975 logger.info('add line QCUT = %s in pythia_card.dat' % args[1])
976 p_card = open(pythia_path,'r').read()
977@@ -2907,7 +2994,7 @@
978 return
979 # Special case for the showerkt value
980 if args[0].lower() == 'showerkt':
981- pythia_path = pjoin(self.me_dir, 'Cards','pythia_card.dat')
982+ pythia_path = self.paths['pythia']
983 if os.path.exists(pythia_path):
984 logger.info('add line SHOWERKT = %s in pythia_card.dat' % args[1].upper())
985 p_card = open(pythia_path,'r').read()
986@@ -2943,14 +3030,13 @@
987 if args[0] in ['run_card', 'param_card', 'MadWeight_card', 'shower_card']:
988 if args[1] == 'default':
989 logging.info('replace %s by the default card' % args[0])
990- files.cp(pjoin(self.me_dir,'Cards','%s_default.dat' % args[0]),
991- pjoin(self.me_dir,'Cards','%s.dat'% args[0]))
992+ files.cp(self.paths['%s_default' %args[0][:-5]], self.paths[args[0][:-5]])
993 if args[0] == 'param_card':
994- self.param_card = check_param_card.ParamCard(pjoin(self.me_dir,'Cards','param_card.dat'))
995+ self.param_card = check_param_card.ParamCard(self.paths['param'])
996 elif args[0] == 'run_card':
997- self.run_card = banner_mod.RunCard(pjoin(self.me_dir,'Cards','run_card.dat'))
998+ self.run_card = banner_mod.RunCard(self.paths['run'])
999 elif args[0] == 'shower_card':
1000- self.shower_card = shower_card_mod.ShowerCard(pjoin(self.me_dir,'Cards','shower_card.dat'))
1001+ self.shower_card = shower_card_mod.ShowerCard(self.paths['shower'])
1002 return
1003 else:
1004 card = args[0]
1005@@ -2963,7 +3049,7 @@
1006 if args[1] == 'default':
1007 logging.info('replace MadLoopParams.dat by the default card')
1008 self.MLcard = banner_mod.MadLoopParam(self.MLcardDefault)
1009- self.MLcard.write(pjoin(self.me_dir,'Cards','MadLoopParams.dat'),
1010+ self.MLcard.write(self.paths['ML'],
1011 commentdefault=True)
1012 return
1013 else:
1014@@ -2975,8 +3061,7 @@
1015 elif args[0] in ['madspin_card']:
1016 if args[1] == 'default':
1017 logging.info('replace madspin_card.dat by the default card')
1018- files.cp(pjoin(self.me_dir,'Cards/madspin_card_default.dat'),
1019- pjoin(self.me_dir,'Cards/madspin_card.dat'))
1020+ files.cp(self.paths['MS_default'], self.paths['madspin'])
1021 return
1022 else:
1023 logger.warning("""Command set not allowed for modifying the madspin_card.
1024@@ -2995,7 +3080,7 @@
1025 logger.warning(text)
1026
1027 if args[start+1] == 'default':
1028- default = banner_mod.RunCard(pjoin(self.me_dir,'Cards','run_card_default.dat'))
1029+ default = banner_mod.RunCard(self.paths['run_default'])
1030 if args[start] in default.keys():
1031 self.setR(args[start],default[args[start]])
1032 else:
1033@@ -3011,8 +3096,7 @@
1034 except NameError:
1035 val = args[start+1]
1036 self.setR(args[start], val)
1037- self.run_card.write(pjoin(self.me_dir,'Cards','run_card.dat'),
1038- pjoin(self.me_dir,'Cards','run_card_default.dat'))
1039+ self.run_card.write(self.paths['run'], self.paths['run_default'])
1040
1041 ### PARAM_CARD WITH BLOCK NAME -----------------------------------------
1042 elif (args[start] in self.param_card or args[start] == 'width') \
1043@@ -3052,7 +3136,7 @@
1044 continue
1045 else:
1046 self.setP(args[start], key, args[-1])
1047- self.param_card.write(pjoin(self.me_dir,'Cards','param_card.dat'))
1048+ self.param_card.write(self.paths['param'])
1049 return
1050 logger.warning('invalid set command %s (failed to identify LHA information)' % line)
1051 return
1052@@ -3078,7 +3162,7 @@
1053 else:
1054 logger.warning('invalid set command %s' % line)
1055 return
1056- self.param_card.write(pjoin(self.me_dir,'Cards','param_card.dat'))
1057+ self.param_card.write(self.paths['param'])
1058
1059 # PARAM_CARD NO BLOCK NAME ---------------------------------------------
1060 elif args[start] in self.pname2block and card != 'run_card':
1061@@ -3113,7 +3197,7 @@
1062 name = args[start+1]
1063 value = args[start+2:]
1064 self.setM(block, name, value)
1065- self.mw_card.write(pjoin(self.me_dir,'Cards','MadWeight_card.dat'))
1066+ self.mw_card.write(self.paths['MadWeight'])
1067
1068 # MadWeight_card NO Block name -----------------------------------------
1069 elif self.has_mw and args[start] in self.mw_vars \
1070@@ -3135,7 +3219,7 @@
1071 name = args[start]
1072 value = args[start+1:]
1073 self.setM(block, name, value)
1074- self.mw_card.write(pjoin(self.me_dir,'Cards','MadWeight_card.dat'))
1075+ self.mw_card.write(self.paths['MadWeight'])
1076
1077 # MadWeight_card New Block ---------------------------------------------
1078 elif self.has_mw and args[start].startswith('mw_') and len(args[start:]) == 3\
1079@@ -3144,7 +3228,7 @@
1080 name = args[start+1]
1081 value = args[start+2]
1082 self.setM(block, name, value)
1083- self.mw_card.write(pjoin(self.me_dir,'Cards','MadWeight_card.dat'))
1084+ self.mw_card.write(self.paths['MadWeight'])
1085
1086 #### SHOWER CARD
1087 elif self.has_shower and args[start].lower() in [l.lower() for l in \
1088@@ -3159,19 +3243,19 @@
1089 return
1090
1091 if args[start+1].lower() == 'default':
1092- default = shower_card_mod.ShowerCard(pjoin(self.me_dir,'Cards','shower_card_default.dat'))
1093+ default = shower_card_mod.ShowerCard(self.paths['shower_default'])
1094 if args[start] in default.keys():
1095- self.shower_card.set_param(args[start],default[args[start]],pjoin(self.me_dir,'Cards','shower_card.dat'))
1096+ self.shower_card.set_param(args[start],default[args[start]], self.paths['shower'])
1097 else:
1098 logger.info('remove information %s from the shower_card' % args[start])
1099 del self.shower_card[args[start]]
1100 elif args[start+1].lower() in ['t','.true.','true']:
1101- self.shower_card.set_param(args[start],'.true.',pjoin(self.me_dir,'Cards','shower_card.dat'))
1102+ self.shower_card.set_param(args[start],'.true.',self.paths['shower'])
1103 elif args[start+1].lower() in ['f','.false.','false']:
1104- self.shower_card.set_param(args[start],'.false.',pjoin(self.me_dir,'Cards','shower_card.dat'))
1105+ self.shower_card.set_param(args[start],'.false.',self.paths['shower'])
1106 else:
1107 args_str = ' '.join(str(a) for a in args[start+1:len(args)])
1108- self.shower_card.set_param(args[start],args_str,pjoin(self.me_dir,'Cards','shower_card.dat'))
1109+ self.shower_card.set_param(args[start],args_str,self.paths['shower'])
1110
1111 # MadLoop Parameter ---------------------------------------------------
1112 elif self.has_ml and args[start] in self.ml_vars \
1113@@ -3189,7 +3273,7 @@
1114 value = args[start+1]
1115 default = False
1116 self.setML(args[start], value, default=default)
1117- self.MLcard.write(pjoin(self.me_dir,'Cards','MadLoopParams.dat'),
1118+ self.MLcard.write(self.paths['ML'],
1119 commentdefault=True)
1120
1121 #INVALID --------------------------------------------------------------
1122@@ -3209,7 +3293,7 @@
1123 logger.info('name %s was not present in the block %s for the current MadWeight card. We are adding it' % (name,block),'$MG:color:BLACK')
1124 if value == 'default':
1125 import madgraph.madweight.Cards as mwcards
1126- mw_default = mwcards.Card(pjoin(self.me_dir,'Cards','MadWeight_card_default.dat'))
1127+ mw_default = mwcards.Card(self.paths['MadWeight_default'])
1128 try:
1129 value = mw_default[block][name]
1130 except KeyError:
1131@@ -3227,7 +3311,7 @@
1132 self.mw_card[block][name] = value
1133
1134 def setR(self, name, value):
1135- logger.info('modify parameter %s of the run_card.dat to %s' % (name, value))
1136+ logger.info('modify parameter %s of the run_card.dat to %s' % (name, value),'$MG:color:BLACK')
1137 self.run_card.set(name, value, user=True)
1138
1139 def setML(self, name, value, default=False):
1140@@ -3237,7 +3321,7 @@
1141 except Exception, error:
1142 logger.warning("Fail to change parameter. Please Retry. Reason: %s." % error)
1143 return
1144- logger.info('modify parameter %s of the MadLoopParam.dat to %s' % (name, value))
1145+ logger.info('modify parameter %s of the MadLoopParam.dat to %s' % (name, value),'$MG:color:BLACK')
1146 if default and name.lower() in self.MLcard.user_set:
1147 self.MLcard.user_set.remove(name.lower())
1148
1149@@ -3245,7 +3329,7 @@
1150 if isinstance(value, str):
1151 value = value.lower()
1152 if value == 'default':
1153- default = check_param_card.ParamCard(pjoin(self.me_dir,'Cards','param_card_default.dat'))
1154+ default = check_param_card.ParamCard(self.paths['param_default'])
1155 value = default[block].param_dict[lhaid].value
1156
1157 elif value in ['auto', 'auto@nlo']:
1158@@ -3288,7 +3372,7 @@
1159 not self.run_card['store_rwgt_info']:
1160 #check if a NLO reweighting is required
1161 re_pattern = re.compile(r'''^\s*change\s*mode\s* (LO\+NLO|LO|NLO)\s*(?:#|$)''', re.M+re.I)
1162- text = open(pjoin(self.me_dir,'Cards','reweight_card.dat')).read()
1163+ text = open(self.paths['reweight']).read()
1164 options = re_pattern.findall(text)
1165 if any(o in ['NLO', 'LO+NLO'] for o in options):
1166 logger.info('NLO reweighting is on ON. Automatically set store_rwgt_info to True', '$MG:color:BLACK' )
1167@@ -3302,15 +3386,89 @@
1168 logger.warning('No transfer function currently define. Please use the change_tf command to define one.')
1169
1170 def postcmd(self, stop, line):
1171-
1172 ending_question = cmd.OneLinePathCompletion.postcmd(self,stop,line)
1173+
1174 if ending_question:
1175 self.check_card_consistency()
1176+ self.do_update_dependent('', timer=20)
1177 return ending_question
1178
1179+ def do_update_dependent(self, line, timer=0):
1180+ """Change the mass/width of particles which are not free parameter for the
1181+ model."""
1182+ if not self.mother_interface:
1183+ logger.warning('Failed to update dependent parameter. This might create trouble for external program (like MadSpin/shower/...)')
1184+
1185+ pattern_width = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I)
1186+ pattern_scan = re.compile(r'''^(decay)?[\s\d]*scan''', re.I+re.M)
1187+ param_text= open(self.paths['param']).read()
1188+
1189+ if pattern_scan.search(param_text):
1190+ #for block, key in self.restricted_value:
1191+ # self.param_card[block].get(key).value = -9.999e-99
1192+ # self.param_card.write(self.paths['param'])
1193+ return
1194+ elif pattern_width.search(param_text):
1195+ self.do_compute_widths('')
1196+ self.param_card = check_param_card.ParamCard(self.paths['param'])
1197+
1198+ # calling the routine doing the work
1199+ self.update_dependent(self.mother_interface, self.me_dir, self.param_card,
1200+ self.paths['param'], timer)
1201+
1202+ @staticmethod
1203+ def update_dependent(mecmd, me_dir, param_card, path ,timer=0):
1204+ """static method which can also be called from outside the class
1205+ usefull in presence of scan.
1206+ return if the param_card was updated or not
1207+ """
1208+ modify = True
1209+ class TimeOutError(Exception):
1210+ pass
1211+ def handle_alarm(signum, frame):
1212+ raise TimeOutError
1213+ signal.signal(signal.SIGALRM, handle_alarm)
1214+ if timer:
1215+ signal.alarm(timer)
1216+ log_level=30
1217+ else:
1218+ log_level=20
1219+ # Try to load the model in the limited amount of time allowed
1220+ try:
1221+ model = mecmd.get_model()
1222+ signal.alarm(0)
1223+ except TimeOutError:
1224+ logger.warning('The model takes too long to load so we bypass the updating of dependent parameter.\n'+\
1225+ 'This might create trouble for external program (like MadSpin/shower/...)\n'+\
1226+ 'The update can be forced without timer by typing \'update_dependent\' at the time of the card edition')
1227+ modify =False
1228+ except Exception:
1229+ logger.warning('Failed to update dependent parameter. This might create trouble for external program (like MadSpin/shower/...)')
1230+ signal.alarm(0)
1231+ else:
1232+ restrict_card = pjoin(me_dir,'Source','MODEL','param_card_rule.dat')
1233+ if not os.path.exists(restrict_card):
1234+ restrict_card = None
1235+ #restrict_card = None
1236+ if model:
1237+ modify = param_card.update_dependent(model, restrict_card, log_level)
1238+ if modify and path:
1239+ param_card.write(path)
1240+ else:
1241+ logger.warning('missing MG5aMC code. Fail to update dependent parameter. This might create trouble for program like MadSpin/shower/...')
1242+
1243+ if log_level==20:
1244+ logger.info('param_card up to date.')
1245+
1246+ return modify
1247+
1248+
1249+
1250+
1251 def check_answer_consistency(self):
1252 """function called if the code reads a file"""
1253- self.check_card_consistency()
1254+ self.check_card_consistency()
1255+ self.do_update_dependent('', timer=20)
1256
1257 def help_set(self):
1258 '''help message for set'''
1259@@ -3354,11 +3512,11 @@
1260 elif os.path.isfile(line):
1261 self.copy_file(line)
1262 self.value = 'repeat'
1263- elif os.path.exists(pjoin(self.me_dir, line)):
1264+ elif self.me_dir and os.path.exists(pjoin(self.me_dir, line)):
1265 self.copy_file(pjoin(self.me_dir,line))
1266 self.value = 'repeat'
1267 elif line.strip() != '0' and line.strip() != 'done' and \
1268- str(line) != 'EOF' and line.strip() in self.allow_arg:
1269+ str(line) != 'EOF' and line.strip() in self.allow_arg:
1270 self.open_file(line)
1271 self.value = 'repeat'
1272 else:
1273@@ -3369,7 +3527,7 @@
1274 def do_decay(self, line):
1275 """edit the madspin_card to define the decay of the associate particle"""
1276 signal.alarm(0) # avoid timer if any
1277- path = pjoin(self.me_dir,'Cards','madspin_card.dat')
1278+ path = self.paths['madspin']
1279
1280 if 'madspin_card.dat' not in self.cards or not os.path.exists(path):
1281 logger.warning("Command decay not valid. Since MadSpin is not available.")
1282@@ -3405,7 +3563,7 @@
1283
1284 def do_compute_widths(self, line):
1285 signal.alarm(0) # avoid timer if any
1286- path = pjoin(self.me_dir,'Cards','param_card.dat')
1287+ path = self.paths['param']
1288 pattern = re.compile(r'''decay\s+(\+?\-?\d+)\s+auto(@NLO|)''',re.I)
1289 text = open(path).read()
1290 pdg_info = pattern.findall(text)
1291@@ -3454,7 +3612,7 @@
1292 print ' If you specify some names after the command (i.e. asperge m1 m2) then ASperGe will only'
1293 print ' diagonalize the associate mass matrices (here m1 and m2).'
1294
1295- def complete_asperge(self, text, line, begidx, endidx):
1296+ def complete_asperge(self, text, line, begidx, endidx, formatting=True):
1297 signal.alarm(0) # avoid timer if any
1298
1299 blockname = self.pname2block.keys()
1300@@ -3465,7 +3623,7 @@
1301 output = {'Mixing matrices': self.list_completion(text, valid, line),
1302 'Other potential valid input': self.list_completion(text, potential, line)}
1303
1304- return self.deal_multiple_categories(output)
1305+ return self.deal_multiple_categories(output, formatting)
1306
1307
1308 def do_asperge(self, line):
1309@@ -3489,7 +3647,7 @@
1310 return
1311
1312 opts = line.split()
1313- card = pjoin(self.me_dir,'Cards', 'param_card.dat')
1314+ card = self.paths['param']
1315 logger.info('running ASperGE')
1316 returncode = misc.call([pjoin(path,'ASperGe'), card, '%s.new' % card] + opts)
1317 if returncode:
1318@@ -3521,7 +3679,7 @@
1319 logger.warning('Fail to determine the type of the file. Not copied')
1320 if card_name != 'banner':
1321 logger.info('copy %s as %s' % (path, card_name))
1322- files.cp(path, pjoin(self.me_dir, 'Cards', card_name))
1323+ files.cp(path, self.paths[card_name.split('_',1)[0]])
1324 elif card_name == 'banner':
1325 banner_mod.split_banner(path, self.mother_interface.me_dir, proc_card=False)
1326 logger.info('Splitting the banner in it\'s component')
1327@@ -3530,7 +3688,11 @@
1328
1329 def open_file(self, answer):
1330 """open the file"""
1331- me_dir = self.mother_interface.me_dir
1332+ try:
1333+ me_dir = self.mother_interface.me_dir
1334+ except:
1335+ me_dir = None
1336+
1337 if answer.isdigit():
1338 if answer == '9':
1339 answer = 'plot'
1340@@ -3540,14 +3702,17 @@
1341 answer = answer.replace('madweight', 'MadWeight')
1342
1343 if 'MadLoopParams' in answer:
1344- answer = pjoin(me_dir,'Cards','MadLoopParams.dat')
1345+ answer = self.paths['ML']
1346 if not '.dat' in answer and not '.lhco' in answer:
1347 if answer != 'trigger':
1348- path = pjoin(me_dir,'Cards','%s_card.dat' % answer)
1349+ path = self.paths[answer]
1350 else:
1351- path = pjoin(me_dir,'Cards','delphes_trigger.dat')
1352+ path = self.paths['delphes']
1353 elif not '.lhco' in answer:
1354- path = pjoin(me_dir, 'Cards', answer)
1355+ if '_' in answer:
1356+ path = self.paths[answer.split('_')[0]]
1357+ else:
1358+ path = pjoin(me_dir, 'Cards', answer)
1359 else:
1360 path = pjoin(me_dir, self.mw_card['mw_run']['inputfile'])
1361 if not os.path.exists(path):
1362@@ -3574,7 +3739,7 @@
1363 raise
1364
1365 # reload object to have it in sync
1366- if path == pjoin(self.me_dir,'Cards','param_card.dat'):
1367+ if path == self.paths['param']:
1368 try:
1369 self.param_card = check_param_card.ParamCard(path)
1370 except (check_param_card.InvalidParamCard, ValueError) as e:
1371@@ -3582,14 +3747,41 @@
1372 logger.error('problem detected: %s' % e)
1373 logger.error('Please re-open the file and fix the problem.')
1374 logger.warning('using the \'set\' command without opening the file will discard all your manual change')
1375- elif path == pjoin(self.me_dir,'Cards','run_card.dat'):
1376- self.run_card = banner_mod.RunCard(pjoin(self.me_dir,'Cards','run_card.dat'))
1377- elif path == pjoin(self.me_dir,'Cards','MadLoopParams.dat'):
1378- self.MLcard = banner_mod.MadLoopParam(pjoin(self.me_dir,'Cards','MadLoopParams.dat'))
1379- elif path == pjoin(self.me_dir,'Cards','MadWeight_card.dat'):
1380+ elif path == self.paths['run']:
1381+ self.run_card = banner_mod.RunCard(path)
1382+ elif path == self.paths['ML']:
1383+ self.MLcard = banner_mod.MadLoopParam(path)
1384+ elif path == self.paths['MadWeight']:
1385 try:
1386 import madgraph.madweight.Cards as mwcards
1387 except:
1388 import internal.madweight.Cards as mwcards
1389- self.mw_card = mwcards.Card(pjoin(self.me_dir,'Cards','MadWeight_card.dat'))
1390-
1391+ self.mw_card = mwcards.Card(path)
1392+ return path
1393+
1394+class EditParamCard(AskforEditCard):
1395+ """a dedicated module for the param"""
1396+
1397+ special_shortcut ={}
1398+
1399+ def __init__(self, question, card=[], mode='auto', *args, **opt):
1400+
1401+ self.load_default()
1402+ cmd.OneLinePathCompletion.__init__(self, question, *args, **opt)
1403+ if os.path.isfile(card[0]):
1404+ self.param_card = check_param_card.ParamCard(card[0])
1405+ self.paths['param'] = card[0]
1406+ if os.path.isfile(card[0].replace('.dat', '_default.dat')):
1407+ self.paths['param_default'] = card[0].replace('.dat', '_default.dat')
1408+ else:
1409+ self.paths['param_default'] = card[0]
1410+ else:
1411+ raise Exception, 'path %s do not exists' % card[0]
1412+
1413+ self.pname2block, self.restricted_value = self.param_card.analyze_param_card()
1414+ self.cards=['param']
1415+
1416+ def do_asperge(self, *args, **opts):
1417+ "Not available"
1418+ logger.warning("asperge not available in this mode")
1419+
1420
1421=== modified file 'madgraph/interface/extended_cmd.py'
1422--- madgraph/interface/extended_cmd.py 2016-06-20 10:26:01 +0000
1423+++ madgraph/interface/extended_cmd.py 2016-08-18 22:31:39 +0000
1424@@ -15,7 +15,6 @@
1425 """ A file containing different extension of the cmd basic python library"""
1426
1427
1428-import cmd
1429 import logging
1430 import os
1431 import pydoc
1432@@ -68,22 +67,386 @@
1433 return
1434 return deco_f
1435 return deco_debug
1436-
1437+
1438+import string
1439+
1440+# The following is copy from the standard cmd routine but pass in new class type
1441+__all__ = ["Cmd"]
1442+PROMPT = '(Cmd) '
1443+IDENTCHARS = string.ascii_letters + string.digits + '_'
1444+class OriginalCmd(object):
1445+ """A simple framework for writing line-oriented command interpreters.
1446+
1447+ These are often useful for test harnesses, administrative tools, and
1448+ prototypes that will later be wrapped in a more sophisticated interface.
1449+
1450+ A Cmd instance or subclass instance is a line-oriented interpreter
1451+ framework. There is no good reason to instantiate Cmd itself; rather,
1452+ it's useful as a superclass of an interpreter class you define yourself
1453+ in order to inherit Cmd's methods and encapsulate action methods.
1454+
1455+ """
1456+ prompt = PROMPT
1457+ identchars = IDENTCHARS
1458+ ruler = '='
1459+ lastcmd = ''
1460+ intro = None
1461+ doc_leader = ""
1462+ doc_header = "Documented commands (type help <topic>):"
1463+ misc_header = "Miscellaneous help topics:"
1464+ undoc_header = "Undocumented commands:"
1465+ nohelp = "*** No help on %s"
1466+ use_rawinput = 1
1467+
1468+ def __init__(self, completekey='tab', stdin=None, stdout=None,**opt):
1469+ """Instantiate a line-oriented interpreter framework.
1470+
1471+ The optional argument 'completekey' is the readline name of a
1472+ completion key; it defaults to the Tab key. If completekey is
1473+ not None and the readline module is available, command completion
1474+ is done automatically. The optional arguments stdin and stdout
1475+ specify alternate input and output file objects; if not specified,
1476+ sys.stdin and sys.stdout are used.
1477+
1478+ """
1479+ import sys
1480+ if stdin is not None:
1481+ self.stdin = stdin
1482+ else:
1483+ self.stdin = sys.stdin
1484+ if stdout is not None:
1485+ self.stdout = stdout
1486+ else:
1487+ self.stdout = sys.stdout
1488+ self.cmdqueue = []
1489+ self.completekey = completekey
1490+ self.cmd_options = opt
1491+
1492+ def cmdloop(self, intro=None):
1493+ """Repeatedly issue a prompt, accept input, parse an initial prefix
1494+ off the received input, and dispatch to action methods, passing them
1495+ the remainder of the line as argument.
1496+
1497+ """
1498+
1499+ self.preloop()
1500+ if self.use_rawinput and self.completekey:
1501+ try:
1502+ import readline
1503+ self.old_completer = readline.get_completer()
1504+ readline.set_completer(self.complete)
1505+ readline.parse_and_bind(self.completekey+": complete")
1506+ except ImportError:
1507+ pass
1508+ try:
1509+ if intro is not None:
1510+ self.intro = intro
1511+ if self.intro:
1512+ self.stdout.write(str(self.intro)+"\n")
1513+ stop = None
1514+ while not stop:
1515+ if self.cmdqueue:
1516+ line = self.cmdqueue.pop(0)
1517+ else:
1518+ if self.use_rawinput:
1519+ try:
1520+ line = raw_input(self.prompt)
1521+ except EOFError:
1522+ line = 'EOF'
1523+ else:
1524+ self.stdout.write(self.prompt)
1525+ self.stdout.flush()
1526+ line = self.stdin.readline()
1527+ if not len(line):
1528+ line = 'EOF'
1529+ else:
1530+ line = line.rstrip('\r\n')
1531+ line = self.precmd(line)
1532+ stop = self.onecmd(line)
1533+ stop = self.postcmd(stop, line)
1534+ self.postloop()
1535+ finally:
1536+ if self.use_rawinput and self.completekey:
1537+ try:
1538+ import readline
1539+ readline.set_completer(self.old_completer)
1540+ except ImportError:
1541+ pass
1542+
1543+
1544+ def precmd(self, line):
1545+ """Hook method executed just before the command line is
1546+ interpreted, but after the input prompt is generated and issued.
1547+
1548+ """
1549+ return line
1550+
1551+ def postcmd(self, stop, line):
1552+ """Hook method executed just after a command dispatch is finished."""
1553+ return stop
1554+
1555+ def preloop(self):
1556+ """Hook method executed once when the cmdloop() method is called."""
1557+ pass
1558+
1559+ def postloop(self):
1560+ """Hook method executed once when the cmdloop() method is about to
1561+ return.
1562+
1563+ """
1564+ pass
1565+
1566+ def parseline(self, line):
1567+ """Parse the line into a command name and a string containing
1568+ the arguments. Returns a tuple containing (command, args, line).
1569+ 'command' and 'args' may be None if the line couldn't be parsed.
1570+ """
1571+ line = line.strip()
1572+ if not line:
1573+ return None, None, line
1574+ elif line[0] == '?':
1575+ line = 'help ' + line[1:]
1576+ elif line[0] == '!':
1577+ if hasattr(self, 'do_shell'):
1578+ line = 'shell ' + line[1:]
1579+ else:
1580+ return None, None, line
1581+ i, n = 0, len(line)
1582+ while i < n and line[i] in self.identchars: i = i+1
1583+ cmd, arg = line[:i], line[i:].strip()
1584+ return cmd, arg, line
1585+
1586+ def onecmd(self, line):
1587+ """Interpret the argument as though it had been typed in response
1588+ to the prompt.
1589+
1590+ This may be overridden, but should not normally need to be;
1591+ see the precmd() and postcmd() methods for useful execution hooks.
1592+ The return value is a flag indicating whether interpretation of
1593+ commands by the interpreter should stop.
1594+
1595+ """
1596+ cmd, arg, line = self.parseline(line)
1597+ if not line:
1598+ return self.emptyline()
1599+ if cmd is None:
1600+ return self.default(line)
1601+ self.lastcmd = line
1602+ if cmd == '':
1603+ return self.default(line)
1604+ else:
1605+ try:
1606+ func = getattr(self, 'do_' + cmd)
1607+ except AttributeError:
1608+ return self.default(line)
1609+ return func(arg)
1610+
1611+ def emptyline(self):
1612+ """Called when an empty line is entered in response to the prompt.
1613+
1614+ If this method is not overridden, it repeats the last nonempty
1615+ command entered.
1616+
1617+ """
1618+ if self.lastcmd:
1619+ return self.onecmd(self.lastcmd)
1620+
1621+ def default(self, line):
1622+ """Called on an input line when the command prefix is not recognized.
1623+
1624+ If this method is not overridden, it prints an error message and
1625+ returns.
1626+
1627+ """
1628+ self.stdout.write('*** Unknown syntax: %s\n'%line)
1629+
1630+ def completedefault(self, *ignored):
1631+ """Method called to complete an input line when no command-specific
1632+ complete_*() method is available.
1633+
1634+ By default, it returns an empty list.
1635+
1636+ """
1637+ return []
1638+
1639+ def completenames(self, text, *ignored):
1640+ dotext = 'do_'+text
1641+ return [a[3:] for a in self.get_names() if a.startswith(dotext)]
1642+
1643+ def complete(self, text, state):
1644+ """Return the next possible completion for 'text'.
1645+
1646+ If a command has not been entered, then complete against command list.
1647+ Otherwise try to call complete_<command> to get list of completions.
1648+ """
1649+ if state == 0:
1650+ import readline
1651+ origline = readline.get_line_buffer()
1652+ line = origline.lstrip()
1653+ stripped = len(origline) - len(line)
1654+ begidx = readline.get_begidx() - stripped
1655+ endidx = readline.get_endidx() - stripped
1656+ if begidx>0:
1657+ cmd, args, foo = self.parseline(line)
1658+ if cmd == '':
1659+ compfunc = self.completedefault
1660+ else:
1661+ try:
1662+ compfunc = getattr(self, 'complete_' + cmd)
1663+ except AttributeError:
1664+ compfunc = self.completedefault
1665+ else:
1666+ compfunc = self.completenames
1667+ self.completion_matches = compfunc(text, line, begidx, endidx)
1668+ try:
1669+ return self.completion_matches[state]
1670+ except IndexError:
1671+ return None
1672+
1673+ def get_names(self):
1674+ # Inheritance says we have to look in class and
1675+ # base classes; order is not important.
1676+ names = []
1677+ classes = [self.__class__]
1678+ while classes:
1679+ aclass = classes.pop(0)
1680+ if aclass.__bases__:
1681+ classes = classes + list(aclass.__bases__)
1682+ names = names + dir(aclass)
1683+ return names
1684+
1685+ def complete_help(self, *args):
1686+ return self.completenames(*args)
1687+
1688+ def do_help(self, arg):
1689+ if arg:
1690+ # XXX check arg syntax
1691+ try:
1692+ func = getattr(self, 'help_' + arg)
1693+ except AttributeError:
1694+ try:
1695+ doc=getattr(self, 'do_' + arg).__doc__
1696+ if doc:
1697+ self.stdout.write("%s\n"%str(doc))
1698+ return
1699+ except AttributeError:
1700+ pass
1701+ self.stdout.write("%s\n"%str(self.nohelp % (arg,)))
1702+ return
1703+ func()
1704+ else:
1705+ names = self.get_names()
1706+ cmds_doc = []
1707+ cmds_undoc = []
1708+ help = {}
1709+ for name in names:
1710+ if name[:5] == 'help_':
1711+ help[name[5:]]=1
1712+ names.sort()
1713+ # There can be duplicates if routines overridden
1714+ prevname = ''
1715+ for name in names:
1716+ if name[:3] == 'do_':
1717+ if name == prevname:
1718+ continue
1719+ prevname = name
1720+ cmd=name[3:]
1721+ if cmd in help:
1722+ cmds_doc.append(cmd)
1723+ del help[cmd]
1724+ elif getattr(self, name).__doc__:
1725+ cmds_doc.append(cmd)
1726+ else:
1727+ cmds_undoc.append(cmd)
1728+ self.stdout.write("%s\n"%str(self.doc_leader))
1729+ self.print_topics(self.doc_header, cmds_doc, 15,80)
1730+ self.print_topics(self.misc_header, help.keys(),15,80)
1731+ self.print_topics(self.undoc_header, cmds_undoc, 15,80)
1732+
1733+ def print_topics(self, header, cmds, cmdlen, maxcol):
1734+ if cmds:
1735+ self.stdout.write("%s\n"%str(header))
1736+ if self.ruler:
1737+ self.stdout.write("%s\n"%str(self.ruler * len(header)))
1738+ self.columnize(cmds, maxcol-1)
1739+ self.stdout.write("\n")
1740+
1741+ def columnize(self, list, displaywidth=80):
1742+ """Display a list of strings as a compact set of columns.
1743+
1744+ Each column is only as wide as necessary.
1745+ Columns are separated by two spaces (one was not legible enough).
1746+ """
1747+ if not list:
1748+ self.stdout.write("<empty>\n")
1749+ return
1750+ nonstrings = [i for i in range(len(list))
1751+ if not isinstance(list[i], str)]
1752+ if nonstrings:
1753+ raise TypeError, ("list[i] not a string for i in %s" %
1754+ ", ".join(map(str, nonstrings)))
1755+ size = len(list)
1756+ if size == 1:
1757+ self.stdout.write('%s\n'%str(list[0]))
1758+ return
1759+ # Try every row count from 1 upwards
1760+ for nrows in range(1, len(list)):
1761+ ncols = (size+nrows-1) // nrows
1762+ colwidths = []
1763+ totwidth = -2
1764+ for col in range(ncols):
1765+ colwidth = 0
1766+ for row in range(nrows):
1767+ i = row + nrows*col
1768+ if i >= size:
1769+ break
1770+ x = list[i]
1771+ colwidth = max(colwidth, len(x))
1772+ colwidths.append(colwidth)
1773+ totwidth += colwidth + 2
1774+ if totwidth > displaywidth:
1775+ break
1776+ if totwidth <= displaywidth:
1777+ break
1778+ else:
1779+ nrows = len(list)
1780+ ncols = 1
1781+ colwidths = [0]
1782+ for row in range(nrows):
1783+ texts = []
1784+ for col in range(ncols):
1785+ i = row + nrows*col
1786+ if i >= size:
1787+ x = ""
1788+ else:
1789+ x = list[i]
1790+ texts.append(x)
1791+ while texts and not texts[-1]:
1792+ del texts[-1]
1793+ for col in range(len(texts)):
1794+ texts[col] = texts[col].ljust(colwidths[col])
1795+ self.stdout.write("%s\n"%str(" ".join(texts)))
1796+
1797+
1798+
1799
1800 #===============================================================================
1801 # CmdExtended
1802 #===============================================================================
1803-class BasicCmd(cmd.Cmd):
1804+class BasicCmd(OriginalCmd):
1805 """Simple extension for the readline"""
1806
1807 def preloop(self):
1808 if readline and not 'libedit' in readline.__doc__:
1809 readline.set_completion_display_matches_hook(self.print_suggestions)
1810
1811- def deal_multiple_categories(self, dico, forceCategory=False):
1812+ def deal_multiple_categories(self, dico, formatting=True, forceCategory=False):
1813 """convert the multiple category in a formatted list understand by our
1814 specific readline parser"""
1815
1816+ if not formatting:
1817+ return dico
1818+
1819 if 'libedit' in readline.__doc__:
1820 # No parser in this case, just send all the valid options
1821 out = []
1822@@ -316,7 +679,7 @@
1823 prefix += os.path.sep
1824
1825 if only_dirs:
1826- completion = [prefix + f
1827+ completion = [prefix + f + os.path.sep
1828 for f in os.listdir(base_dir)
1829 if f.startswith(text) and \
1830 os.path.isdir(os.path.join(base_dir, f)) and \
1831@@ -493,7 +856,7 @@
1832 self.log = True
1833 self.history = []
1834 self.save_line = '' # for line splitting
1835- cmd.Cmd.__init__(self, *arg, **opt)
1836+ super(Cmd, self).__init__(*arg, **opt)
1837 self.__initpos = os.path.abspath(os.getcwd())
1838 self.child = None # sub CMD interface call from this one
1839 self.mother = None #This CMD interface was called from another one
1840@@ -657,7 +1020,7 @@
1841 else:
1842 path_msg = []
1843
1844- if timeout:
1845+ if timeout is True:
1846 try:
1847 timeout = self.options['timeout']
1848 except Exception:
1849@@ -709,7 +1072,10 @@
1850 if answer in alias:
1851 answer = alias[answer]
1852 if ask_class:
1853- answer = question_instance.default(answer)
1854+ line=answer
1855+ answer = question_instance.default(line)
1856+ question_instance.postcmd(answer, line)
1857+ return question_instance.answer
1858 if hasattr(question_instance, 'check_answer_consistency'):
1859 question_instance.check_answer_consistency()
1860 return answer
1861@@ -723,6 +1089,7 @@
1862 value = alias[value]
1863 except TypeError:
1864 pass
1865+
1866 if value == default and ask_class:
1867 value = question_instance.default(default)
1868 return value
1869@@ -771,7 +1138,7 @@
1870 logger.info('The answer to the previous question is not set in your input file', '$MG:color:BLACK')
1871 logger.info('Use %s value' % default, '$MG:color:BLACK')
1872 return str(default)
1873-
1874+
1875 line = line.replace('\n','').strip()
1876 if '#' in line:
1877 line = line.split('#')[0]
1878@@ -839,7 +1206,7 @@
1879 if os.path.exists(self.debug_output):
1880 os.remove(self.debug_output)
1881 try:
1882- cmd.Cmd.onecmd(self, 'history %s' % self.debug_output.replace(' ', '\ '))
1883+ super(Cmd,self).onecmd('history %s' % self.debug_output.replace(' ', '\ '))
1884 except Exception, error:
1885 logger.error(error)
1886
1887@@ -888,7 +1255,7 @@
1888 return self.child.nice_user_error(error, line)
1889 # Make sure that we are at the initial position
1890 os.chdir(self.__initpos)
1891- if line == self.history[-1]:
1892+ if not self.history or line == self.history[-1]:
1893 error_text = 'Command \"%s\" interrupted with error:\n' % line
1894 else:
1895 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
1896@@ -914,7 +1281,7 @@
1897 error_text = 'Error detected in sub-command %s\n' % self.history[-1]
1898 error_text += 'write debug file %s \n' % self.debug_output
1899 self.log = False
1900- cmd.Cmd.onecmd(self, 'history %s' % self.debug_output)
1901+ super(Cmd,self).onecmd('history %s' % self.debug_output)
1902 debug_file = open(self.debug_output, 'a')
1903 traceback.print_exc(file=debug_file)
1904 error_text += self.config_debug % {'debug' :self.debug_output}
1905@@ -1018,17 +1385,18 @@
1906 pass # dummy function
1907
1908 def exec_cmd(self, line, errorhandling=False, printcmd=True,
1909- precmd=False, postcmd=True, **opt):
1910+ precmd=False, postcmd=True,
1911+ child=True, **opt):
1912 """for third party call, call the line with pre and postfix treatment
1913 without global error handling """
1914
1915+
1916 if printcmd and not line.startswith('#'):
1917 logger.info(line)
1918- if self.child:
1919+ if self.child and child:
1920 current_interface = self.child
1921 else:
1922 current_interface = self
1923-
1924 if precmd:
1925 line = current_interface.precmd(line)
1926 if errorhandling:
1927@@ -1061,11 +1429,7 @@
1928
1929 if self.history and self.history[-1] == line:
1930 self.history.pop()
1931-
1932-
1933-
1934-
1935-
1936+
1937 # Write the list of command line use in this session
1938 def do_history(self, line):
1939 """write in a file the suite of command that was used"""
1940@@ -1258,7 +1622,7 @@
1941
1942 # if they are an argument use the default help
1943 if line:
1944- return cmd.Cmd.do_help(self, line)
1945+ return super(Cmd, self).do_help(line)
1946
1947
1948 names = self.get_names()
1949@@ -1526,12 +1890,16 @@
1950 class SmartQuestion(BasicCmd):
1951 """ a class for answering a question with the path autocompletion"""
1952
1953+ allowpath = False
1954 def preloop(self):
1955 """Initializing before starting the main loop"""
1956 self.prompt = '>'
1957 self.value = None
1958 BasicCmd.preloop(self)
1959
1960+ @property
1961+ def answer(self):
1962+ return self.value
1963
1964 def __init__(self, question, allow_arg=[], default=None,
1965 mother_interface=None, *arg, **opt):
1966@@ -1541,7 +1909,7 @@
1967 self.history_header = ''
1968 self.default_value = str(default)
1969 self.mother_interface = mother_interface
1970- cmd.Cmd.__init__(self, *arg, **opt)
1971+ super(SmartQuestion, self).__init__(*arg, **opt)
1972
1973 def __call__(self, question, reprint_opt=True, **opts):
1974
1975@@ -1604,6 +1972,8 @@
1976 return func(arg, **opt)
1977 except Exception as error:
1978 logger.warning(error)
1979+ if __debug__:
1980+ raise
1981
1982 def reask(self, reprint_opt=True):
1983 pat = re.compile('\[(\d*)s to answer\]')
1984@@ -1620,6 +1990,15 @@
1985 if not prev_timer:
1986 self.question = pat.sub('',self.question)
1987 print self.question
1988+
1989+ if self.mother_interface:
1990+ answer = self.mother_interface.check_answer_in_input_file(self, 'EOF',
1991+ path=self.allowpath)
1992+ if answer:
1993+ stop = self.default(answer)
1994+ self.postcmd(stop, answer)
1995+ return False
1996+
1997 return False
1998
1999 def default(self, line):
2000@@ -1665,8 +2044,8 @@
2001 return True
2002
2003 def cmdloop(self, intro=None):
2004- cmd.Cmd.cmdloop(self, intro)
2005- return self.value
2006+ super(SmartQuestion,self).cmdloop(intro)
2007+ return self.answer
2008
2009 # a function helper
2010 def smart_input(input_text, allow_arg=[], default=None):
2011@@ -1681,8 +2060,9 @@
2012 """ a class for answering a question with the path autocompletion"""
2013
2014 completion_prefix=''
2015+ allowpath=True
2016
2017- def completenames(self, text, line, begidx, endidx):
2018+ def completenames(self, text, line, begidx, endidx, formatting=True):
2019 prev_timer = signal.alarm(0) # avoid timer if any
2020 if prev_timer:
2021 nb_back = len(line)
2022@@ -1696,7 +2076,7 @@
2023 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False)
2024 out[' Recognized command'] = BasicCmd.completenames(self, text)
2025
2026- return self.deal_multiple_categories(out)
2027+ return self.deal_multiple_categories(out, formatting)
2028 except Exception, error:
2029 print error
2030
2031@@ -1748,8 +2128,9 @@
2032 % ','.join(self.allow_arg)
2033 print 'please retry'
2034 reprint_opt = False
2035-
2036- return self.reask(reprint_opt)
2037+
2038+ if line != 'EOF':
2039+ return self.reask(reprint_opt)
2040
2041
2042 # a function helper
2043
2044=== modified file 'madgraph/interface/loop_interface.py'
2045--- madgraph/interface/loop_interface.py 2016-05-26 00:13:49 +0000
2046+++ madgraph/interface/loop_interface.py 2016-08-18 22:31:39 +0000
2047@@ -25,6 +25,7 @@
2048 import madgraph
2049 from madgraph import MG4DIR, MG5DIR, MadGraph5Error
2050 import madgraph.interface.madgraph_interface as mg_interface
2051+import madgraph.interface.extended_cmd as cmd
2052 import madgraph.interface.launch_ext_program as launch_ext
2053 import madgraph.interface.extended_cmd as extended_cmd
2054 import madgraph.core.base_objects as base_objects
2055@@ -465,11 +466,11 @@
2056 noclean, output_type=output_type, group_subprocesses=False)
2057
2058 if self._export_format in ['standalone', 'matchbox']:
2059- self._curr_exporter.copy_v4template(modelname=self._curr_model.get('name'))
2060+ self._curr_exporter.copy_template(self._curr_model)
2061
2062 if self._export_format == "standalone_rw":
2063 self._export_format = "standalone"
2064- self._curr_exporter.copy_v4template(modelname=self._curr_model.get('name'))
2065+ self._curr_exporter.copy_template(self._curr_model)
2066 self._export_format = "standalone_rw"
2067
2068 # Reset _done_export, since we have new directory
2069@@ -490,11 +491,105 @@
2070 # Put aloha back in its original mode.
2071 aloha.mp_precision = aloha_original_quad_mode
2072
2073+
2074+ def install_reduction_library(self):
2075+ """Code to install the reduction library if needed"""
2076+
2077+ opt = self.options
2078+
2079+
2080+ # Check if first time:
2081+ if (opt['ninja'] is None) or (os.path.isfile(pjoin(opt['ninja'],'libninja.a'))):
2082+ return
2083+
2084+ logger.info("First output using loop matrix-elements has been detected. Now asking for loop reduction:", '$MG:color:BLACK')
2085+ to_install = self.ask('install', '0', ask_class=AskLoopInstaller, timeout=300,
2086+ path_msg=' ')
2087+
2088+
2089+ for key, value in to_install.items():
2090+ if key in ['cuttools', 'iregi']:
2091+ if os.path.sep not in value:
2092+ continue
2093+ import madgraph.iolibs.files as files
2094+ if key == 'cuttools':
2095+ if os.path.exists(pjoin(value, 'includects')):
2096+ path = pjoin(value, 'includects')
2097+ elif os.path.exists(pjoin(value, 'CutTools','includects')):
2098+ path = pjoin(value, 'CutTools', 'includects')
2099+ elif os.path.exists(pjoin(value, 'vendor','CutTools','includects')):
2100+ path = pjoin(value, 'vendor','CutTools', 'includects')
2101+ else:
2102+ logger.warning('invalid path for cuttools import')
2103+ continue
2104+
2105+ target = pjoin(MG5DIR,'vendor','CutTools','includects')
2106+ if not os.path.exists(target):
2107+ os.mkdir(target)
2108+ files.cp(pjoin(path,'libcts.a'), target)
2109+ files.cp(pjoin(path,'mpmodule.mod'), target, log=True)
2110+ if os.path.exists(pjoin(path,'compiler_version.log')):
2111+ files.cp(pjoin(path,'compiler_version.log'), target)
2112+
2113+ if key == 'iregi':
2114+ if os.path.exists(pjoin(value, 'src','IREGI4ML5_interface.f90')):
2115+ path = pjoin(value, 'src')
2116+ elif os.path.exists(pjoin(value, 'IREGI','src','IREGI4ML5_interface.f90')):
2117+ path = pjoin(value, 'IREGI', 'src')
2118+ elif os.path.exists(pjoin(value, 'vendor','IREGI','src','IREGI4ML5_interface.f90')):
2119+ path = pjoin(value, 'vendor', 'IREGI', 'src')
2120+ else:
2121+ logger.warning('invalid path for IREGI import')
2122+ continue
2123+
2124+ target = pjoin(MG5DIR,'vendor','IREGI','src')
2125+ files.cp(pjoin(path,'libiregi.a'), target, log=True)
2126+ elif value == 'local':
2127+ ## LOCAL INSTALLATION OF NINJA/COLLIER
2128+ logger.info(
2129+"""MG5aMC will now install the loop reduction tool '%(p)s' from the local offline installer.
2130+Use the command 'install $(p)s' if you want to update to the latest online version.
2131+This installation can take some time but only needs to be performed once.""" %{'p': key},'$MG:color:GREEN')
2132+ additional_options = ['--ninja_tarball=%s'%pjoin(MG5DIR,'vendor','%s.tar.gz' % key)]
2133+ if key == 'ninja':
2134+ additional_options.append('--oneloop_tarball=%s'%pjoin(MG5DIR,'vendor','oneloop.tar.gz'))
2135+
2136+ try:
2137+ self.do_install(key,paths={'HEPToolsInstaller':
2138+ pjoin(MG5DIR,'vendor','OfflineHEPToolsInstaller.tar.gz')},
2139+ additional_options=additional_options)
2140+ except self.InvalidCmd:
2141+ logger.warning(
2142+"""The offline installation of %(p)s was unsuccessful, and MG5aMC disabled it.
2143+In the future, if you want to reactivate Ninja, you can do so by re-attempting
2144+its online installation with the command 'install %(p)s' or install it on your
2145+own and set the path to its library in the MG5aMC option '%(p)s'.""" % {'p': key})
2146+ self.exec_cmd("set %s ''" % key)
2147+ self.exec_cmd('save options')
2148+
2149+ # ONLINE INSTALLATION
2150+ elif value == 'install':
2151+ prog = {'pjfry': 'PJFry', 'golem': 'Golem95'}
2152+ if key in prog:
2153+ self.exec_cmd('install %s' % prog[key])
2154+ else:
2155+ self.exec_cmd('install %s' % key)
2156+ # Not install
2157+ elif value == 'off':
2158+ self.exec_cmd("set %s ''" % key)
2159+ self.exec_cmd('save options %s' % key)
2160+ else:
2161+ self.exec_cmd("set %s %s" % (key,value))
2162+ self.exec_cmd('save options %s' % key)
2163+
2164+
2165+
2166 # Export a matrix element
2167-
2168 def ML5export(self, nojpeg = False, main_file_name = ""):
2169 """Export a generated amplitude to file"""
2170
2171+ if not self._curr_helas_model:
2172+ self._curr_helas_model = helas_call_writers.FortranUFOHelasCallWriter(self._curr_model)
2173 def generate_matrix_elements(self):
2174 """Helper function to generate the matrix elements before exporting"""
2175
2176@@ -540,9 +635,8 @@
2177 if self._export_format in self.supported_ML_format:
2178 for unique_id, me in enumerate(matrix_elements):
2179 calls = calls + \
2180- self._curr_exporter.generate_subprocess_directory_v4(\
2181- me, self._curr_fortran_model, (unique_id+1))
2182- self._curr_exporter.write_global_specs(matrix_elements)
2183+ self._curr_exporter.generate_subprocess_directory(\
2184+ me, self._curr_helas_model)
2185 # If all ME's do not share the same maximum loop vertex rank and the
2186 # same loop maximum wavefunction size, we need to set the maximum
2187 # in coef_specs.inc of the HELAS Source. The SubProcesses/P* directory
2188@@ -555,7 +649,6 @@
2189 if len(set(max_lwfspins))>1 or len(set(max_loop_vert_ranks))>1:
2190 self._curr_exporter.fix_coef_specs(max(max_lwfspins),\
2191 max(max_loop_vert_ranks))
2192- self._curr_exporter.write_global_specs(matrix_elements)
2193
2194 # Just the matrix.f files
2195 if self._export_format == 'matrix':
2196@@ -568,7 +661,7 @@
2197 logger.info("Creating new file %s" % filename)
2198 calls = calls + self._curr_exporter.write_matrix_element_v4(\
2199 writers.FortranWriter(filename),\
2200- me, self._curr_fortran_model)
2201+ me, self._curr_helas_model)
2202
2203 cpu_time2 = time.time() - cpu_time1
2204
2205@@ -611,21 +704,22 @@
2206 del self.previous_lorentz
2207 del self.previous_couplings
2208
2209- self._curr_exporter.convert_model_to_mg4(self._curr_model,
2210+ self._curr_exporter.convert_model(self._curr_model,
2211 wanted_lorentz,
2212 wanted_couplings)
2213-
2214- compiler = {'fortran': self.options['fortran_compiler'],
2215- 'f2py': self.options['f2py_compiler'],
2216- 'cpp': self.options['cpp_compiler']}
2217
2218 if self._export_format in self.supported_ML_format:
2219- self._curr_exporter.finalize_v4_directory( \
2220+ flags = []
2221+ if nojpeg:
2222+ flags.append('nojpeg')
2223+ if online:
2224+ flags.append('online')
2225+
2226+ self._curr_exporter.finalize( \
2227 self._curr_matrix_elements,
2228 self.history,
2229- not nojpeg,
2230- online,
2231- compiler)
2232+ self.options,
2233+ flags)
2234
2235 if self._export_format in self.supported_ML_format:
2236 logger.info('Output to directory ' + self._export_dir + ' done.')
2237@@ -791,3 +885,207 @@
2238 class LoopInterfaceWeb(mg_interface.CheckValidForCmdWeb, LoopInterface):
2239 pass
2240
2241+
2242+class AskLoopInstaller(cmd.OneLinePathCompletion):
2243+
2244+ local_installer = ['ninja', 'collier']
2245+ required = ['cuttools', 'iregi']
2246+ order = ['cuttools', 'iregi', 'ninja', 'collier', 'golem', 'pjfry']
2247+
2248+ @property
2249+ def answer(self):
2250+ return self.code
2251+
2252+
2253+ def __init__(self, question, *args, **opts):
2254+
2255+ import urllib2
2256+ try:
2257+ response=urllib2.urlopen('http://madgraph.phys.ucl.ac.be/F1.html', timeout=3)
2258+ self.online=True
2259+ except urllib2.URLError as err:
2260+ self.online=False
2261+
2262+ self.code = {'ninja': 'install',
2263+ 'collier': 'install',
2264+ 'golem': 'off',
2265+ 'pjfry':'off',
2266+ 'cuttools': 'required',
2267+ 'iregi': 'required'}
2268+ if not self.online:
2269+ self.code['ninja'] = 'local'
2270+ self.code['collier'] = 'local'
2271+ self.code['pjfry'] = 'fail'
2272+ self.code['golem'] = 'fail'
2273+ if not misc.which('cmake'):
2274+ self.code['collier'] = 'off'
2275+
2276+
2277+
2278+
2279+ # 1. create the question
2280+ question, allowed_answer = self.create_question(first=True)
2281+
2282+ opts['allow_arg'] = allowed_answer
2283+
2284+ cmd.OneLinePathCompletion.__init__(self, question, *args, **opts)
2285+
2286+
2287+ def create_question(self, first = False):
2288+ """ """
2289+
2290+ question = "For loop computations, MadLoop requires dedicated tools to"+\
2291+ " perform the reduction of loop Feynman diagrams using OPP-based and/or TIR approaches.\n"+\
2292+ "\nWhich one do you want to install? (this needs to be done only once)\n"
2293+
2294+ allowed_answer = set(['0','done'])
2295+
2296+ descript = {'cuttools': ['cuttools','(OPP)','[0711.3596]'],
2297+ 'iregi': ['iregi','(TIR)','[1405.0301]'],
2298+ 'ninja': ['ninja','(OPP)','[1403.1229]'],
2299+ 'pjfry': ['pjfry','(TIR)','[1112.0500]'],
2300+ 'golem': ['golem','(TIR)','[0807.0605]'],
2301+ 'collier': ['collier','(TIR)','[1604.06792]']}
2302+
2303+
2304+ status = {'off': '%(start_red)sdo not install%(stop)s',
2305+ 'install': '%(start_green)swill be installed %(stop)s',
2306+ 'local': '%(start_green)swill be installed %(stop)s(offline installation from local repository)',
2307+ 'fail': 'not available without internet connection',
2308+ 'required': 'will be installed (required)'}
2309+
2310+ for i,key in enumerate(self.order,1):
2311+ if os.path.sep not in self.code[key]:
2312+ question += '%s. %%(start_blue)s%-9s %-5s %-13s%%(stop)s : %s%s\n' % \
2313+ tuple([i,]+descript[key]+[status[self.code[key]],]+\
2314+ ['(recommended)' if key in ['ninja','collier'] and self.code[key] in ['install'] else ''])
2315+ else:
2316+ question += '%s. %%(start_blue)s%-9s %-5s %-13s%%(stop)s : %s\n' % tuple([i,]+descript[key]+[self.code[key],])
2317+ if key in self.required:
2318+ continue
2319+ allowed_answer.update([str(i), key])
2320+ if key in self.local_installer:
2321+ allowed_answer.update(['key=local','key=off'])
2322+ if self.online:
2323+ allowed_answer.update(['key=on','key=install', 'key=off'])
2324+
2325+ question += "You can:\n -> hit 'enter' to proceed\n -> type a number to cycle its options\n -> enter the following command:\n"+\
2326+ ' %(start_blue)s{tool_name}%(stop)s [%(start_blue)sinstall%(stop)s|%(start_blue)snoinstall%(stop)s|'+\
2327+ '%(start_blue)s{prefixed_installation_path}%(stop)s]\n'
2328+ if first:
2329+ question += '\n%(start_bold)s%(start_red)sIf you are unsure about what this question means, just type enter to proceed. %(stop)s'
2330+
2331+ question = question % {'start_green' : '\033[92m',
2332+ 'start_red' : '\033[91m',
2333+ 'start_blue' : '\033[34m',
2334+ 'stop': '\033[0m',
2335+ 'start_bold':'\033[1m',
2336+ }
2337+ return question, allowed_answer
2338+
2339+ def default(self, line):
2340+ """Default action if line is not recognized"""
2341+
2342+ line = line.strip()
2343+ args = line.split()
2344+
2345+ if line in ['0', 'done','','EOF']:
2346+ self.value = 'done'
2347+ return self.answer
2348+ self.value = 'repeat'
2349+ if args:
2350+ if len(args) ==1 and '=' in args[0]:
2351+ args = args[0].split('=')
2352+ args[0] = args[0].lower()
2353+ if len(args) == 1:
2354+ # loop over the possibility
2355+ if args[0].isdigit():
2356+ if len(self.order) < int(args[0]):
2357+ logger.warning('Invalid integer %s. Please Retry' % args[0])
2358+ return
2359+ args[0] = self.order[int(args[0])-1]
2360+ key = args[0]
2361+ if key in self.code:
2362+ if self.code[key] in ['off']:
2363+ if self.online:
2364+ self.code[key] = 'install'
2365+ elif key in self.local_installer:
2366+ self.code[key] = 'local'
2367+ elif self.code[key] == 'install':
2368+ if key in self.local_installer:
2369+ self.code[key] = 'local'
2370+ else:
2371+ self.code[key] = 'off'
2372+ elif self.code[key] == 'local':
2373+ self.code[key] = 'off'
2374+ else:
2375+ logger.warning('Unknown entry \'%s\'. Please retry' % key)
2376+ return
2377+ elif len(args) == 2:
2378+ key = args[0]
2379+ if key not in self.code:
2380+ logger.warning('unknown %s type of entry. Bypass command.')
2381+ return
2382+ if os.path.sep not in args[1]:
2383+ value = args[1].lower()
2384+ if value in ['off', 'not','noinstall']:
2385+ self.code[key] = 'off'
2386+ elif value in ['on', 'install']:
2387+ if self.online:
2388+ self.code[key] = 'install'
2389+ elif key in self.local_installer:
2390+ self.code[key] = 'local'
2391+ else:
2392+ logger.warning('offline installer not available for %s', key)
2393+ self.code[key] = 'off'
2394+ elif value in ['local']:
2395+ if key in self.local_installer:
2396+ self.code[key] = 'local'
2397+ else:
2398+ logger.warning('offline installer not available for %s', key)
2399+ self.code[key] = 'off'
2400+ else:
2401+ self.code[key] = args[1]
2402+ else:
2403+ self.value = 0
2404+ self.question,self.allow_arg = self.create_question()
2405+ return self.answer
2406+
2407+ def apply_name(self, name, line):
2408+
2409+ if line.startswith('='):
2410+ line = line[1:]
2411+ return self.default('%s %s' % (name,line))
2412+
2413+
2414+ do_ninja = lambda self,line : self.apply_name('ninja', line)
2415+ do_pjfry = lambda self,line : self.apply_name('pjfry', line)
2416+ do_collier = lambda self,line : self.apply_name('collier', line)
2417+ do_golem = lambda self,line : self.apply_name('golem', line)
2418+ do_cuttools = lambda self,line : self.apply_name('cuttools', line)
2419+ do_iregi = lambda self,line : self.apply_name('iregi', line)
2420+
2421+
2422+ def complete_prog(self, text, line, begidx, endidx, formatting=True):
2423+
2424+ if os.path.sep in line:
2425+ args = line[0:begidx].split()
2426+ if args[-1].endswith(os.path.sep):
2427+ return self.path_completion(text,
2428+ pjoin(*[a for a in args if a.endswith(os.path.sep)]),
2429+ only_dirs = True)
2430+ else:
2431+ return self.path_completion(text, '.', only_dirs = True)
2432+ else:
2433+ return self.list_completion(text, ['install', 'noinstall', 'local'], line)
2434+
2435+ complete_ninja = complete_prog
2436+ complete_pjfry = complete_prog
2437+ complete_collier = complete_prog
2438+ complete_golem = complete_prog
2439+ complete_cuttools = complete_prog
2440+ complete_iregi = complete_prog
2441+
2442+
2443+
2444+
2445
2446=== modified file 'madgraph/interface/madevent_interface.py'
2447--- madgraph/interface/madevent_interface.py 2016-08-14 00:17:23 +0000
2448+++ madgraph/interface/madevent_interface.py 2016-08-18 22:31:39 +0000
2449@@ -1293,7 +1293,7 @@
2450 else:
2451 return self.list_completion(text, ['--threshold='], line)
2452
2453- def complete_banner_run(self, text, line, begidx, endidx):
2454+ def complete_banner_run(self, text, line, begidx, endidx, formatting=True):
2455 "Complete the banner run command"
2456 try:
2457
2458@@ -1331,7 +1331,7 @@
2459 run_list = [n.rsplit('/',2)[1] for n in run_list]
2460 possibilites['RUN Name'] = self.list_completion(text, run_list)
2461
2462- return self.deal_multiple_categories(possibilites)
2463+ return self.deal_multiple_categories(possibilites, formatting)
2464
2465
2466 except Exception, error:
2467@@ -1511,7 +1511,7 @@
2468 else:
2469 return self.list_completion(text, self._plot_mode + self.results.keys())
2470
2471- def complete_syscalc(self, text, line, begidx, endidx):
2472+ def complete_syscalc(self, text, line, begidx, endidx, formatting=True):
2473 """ Complete the syscalc command """
2474
2475 output = {}
2476@@ -1527,7 +1527,7 @@
2477 tags = ['--tag=%s' % tag['tag'] for tag in self.results[run]]
2478 output['options'] += tags
2479
2480- return self.deal_multiple_categories(output)
2481+ return self.deal_multiple_categories(output, formatting)
2482
2483 def complete_remove(self, text, line, begidx, endidx):
2484 """Complete the remove command """
2485@@ -2035,7 +2035,9 @@
2486 #check if the param_card defines a scan.
2487 orig_name = self.run_name
2488 for card in param_card_iterator:
2489+ path = pjoin(self.me_dir,'Cards','param_card.dat')
2490 card.write(pjoin(self.me_dir,'Cards','param_card.dat'))
2491+ self.check_param_card(path, dependent=True)
2492 next_name = param_card_iterator.get_next_name(self.run_name)
2493 try:
2494 self.exec_cmd("generate_events -f %s" % next_name,
2495
2496=== modified file 'madgraph/interface/madgraph_interface.py'
2497--- madgraph/interface/madgraph_interface.py 2016-08-16 00:19:25 +0000
2498+++ madgraph/interface/madgraph_interface.py 2016-08-18 22:31:39 +0000
2499@@ -146,6 +146,33 @@
2500 # Define the Error Class # Define how error are handle
2501 InvalidCmd = madgraph.InvalidCmd
2502 ConfigurationError = MadGraph5Error
2503+
2504+ intro_banner = "************************************************************\n" + \
2505+ "* *\n" + \
2506+ "* W E L C O M E to *\n" + \
2507+ "* M A D G R A P H 5 _ a M C @ N L O *\n" + \
2508+ "* *\n" + \
2509+ "* *\n" + \
2510+ "* * * *\n" + \
2511+ "* * * * * *\n" + \
2512+ "* * * * * 5 * * * * *\n" + \
2513+ "* * * * * *\n" + \
2514+ "* * * *\n" + \
2515+ "* *\n" + \
2516+ "%s" + \
2517+ "* *\n" + \
2518+ "* The MadGraph5_aMC@NLO Development Team - Find us at *\n" + \
2519+ "* https://server06.fynu.ucl.ac.be/projects/madgraph *\n" + \
2520+ "* and *\n" + \
2521+ "* http://amcatnlo.web.cern.ch/amcatnlo/ *\n" + \
2522+ "* *\n" + \
2523+ "* Type 'help' for in-line help. *\n" + \
2524+ "* Type 'tutorial' to learn how MG5 works *\n" + \
2525+ "* Type 'tutorial aMCatNLO' to learn how aMC@NLO works *\n" + \
2526+ "* Type 'tutorial MadLoop' to learn how MadLoop works *\n" + \
2527+ "* *\n" + \
2528+ "************************************************************"
2529+
2530
2531 def __init__(self, *arg, **opt):
2532 """Init history and line continuation"""
2533@@ -187,32 +214,7 @@
2534
2535
2536
2537- logger.info(\
2538- "************************************************************\n" + \
2539- "* *\n" + \
2540- "* W E L C O M E to *\n" + \
2541- "* M A D G R A P H 5 _ a M C @ N L O *\n" + \
2542- "* *\n" + \
2543- "* *\n" + \
2544- "* * * *\n" + \
2545- "* * * * * *\n" + \
2546- "* * * * * 5 * * * * *\n" + \
2547- "* * * * * *\n" + \
2548- "* * * *\n" + \
2549- "* *\n" + \
2550- info_line + \
2551- "* *\n" + \
2552- "* The MadGraph5_aMC@NLO Development Team - Find us at *\n" + \
2553- "* https://server06.fynu.ucl.ac.be/projects/madgraph *\n" + \
2554- "* and *\n" + \
2555- "* http://amcatnlo.web.cern.ch/amcatnlo/ *\n" + \
2556- "* *\n" + \
2557- "* Type 'help' for in-line help. *\n" + \
2558- "* Type 'tutorial' to learn how MG5 works *\n" + \
2559- "* Type 'tutorial aMCatNLO' to learn how aMC@NLO works *\n" + \
2560- "* Type 'tutorial MadLoop' to learn how MadLoop works *\n" + \
2561- "* *\n" + \
2562- "************************************************************")
2563+ logger.info(self.intro_banner % info_line)
2564
2565 cmd.Cmd.__init__(self, *arg, **opt)
2566
2567@@ -1117,11 +1119,13 @@
2568 def check_install(self, args):
2569 """check that the install command is valid"""
2570
2571+ hidden_prog = ['Delphes2', 'pythia-pgs']
2572+
2573 if len(args) < 1:
2574 self.help_install()
2575 raise self.InvalidCmd('install command require at least one argument')
2576
2577- if args[0] not in self._install_opts:
2578+ if args[0] not in self._install_opts + hidden_prog:
2579 if not args[0].startswith('td'):
2580 self.help_install()
2581 raise self.InvalidCmd('Not recognize program %s ' % args[0])
2582@@ -1154,13 +1158,15 @@
2583 if not args:
2584 if self._done_export:
2585 mode = self.find_output_type(self._done_export[0])
2586-
2587- if not self._done_export[1].startswith(mode):
2588- print mode, self._done_export[1]
2589+ if (self._done_export[1] == 'plugin' and mode not in self._export_formats):
2590+ args.append(mode)
2591+ args.append(self._done_export[0])
2592+ elif self._done_export[1].startswith(mode):
2593+ args.append(self._done_export[1])
2594+ args.append(self._done_export[0])
2595+ else:
2596 raise self.InvalidCmd, \
2597 '%s not valid directory for launch' % self._done_export[0]
2598- args.append(self._done_export[1])
2599- args.append(self._done_export[0])
2600 return
2601 else:
2602 logger.warning('output command missing, run it automatically (with default argument)')
2603@@ -1306,7 +1312,7 @@
2604 if args[0] == 'options':
2605 has_path = None
2606 for arg in args[1:]:
2607- if arg in ['--auto', '--all']:
2608+ if arg in ['--auto', '--all'] or arg in self.options:
2609 continue
2610 elif arg.startswith('--'):
2611 raise self.InvalidCmd('unknow command for \'save options\'')
2612@@ -1460,6 +1466,28 @@
2613
2614 if args and args[0] in self._export_formats:
2615 self._export_format = args.pop(0)
2616+ elif args:
2617+ # check for PLUGIN format
2618+ for plug in os.listdir(pjoin(MG5DIR, 'PLUGIN')):
2619+ if os.path.exists(pjoin(MG5DIR, 'PLUGIN', plug, '__init__.py')):
2620+ try:
2621+ __import__('PLUGIN.%s' % plug)
2622+ except Exception, error:
2623+ logger.warning("error detected in plugin: %s.", plug)
2624+ logger.warning("%s", error)
2625+ continue
2626+ plugin = sys.modules['PLUGIN.%s' % plug]
2627+ if hasattr(plugin, 'new_output'):
2628+ if not misc.is_plugin_supported(plugin):
2629+ continue
2630+ if args[0] in plugin.new_output:
2631+ self._export_format = 'plugin'
2632+ self._export_plugin = plugin.new_output[args[0]]
2633+ logger.info('Output will be done with PLUGIN: %s' % plug ,'$MG:color:BLACK')
2634+ args.pop(0)
2635+ break
2636+ else:
2637+ self._export_format = default
2638 else:
2639 self._export_format = default
2640
2641@@ -1494,7 +1522,7 @@
2642 # Check for special directory treatment
2643 if path == 'auto' and self._export_format in \
2644 ['madevent', 'standalone', 'standalone_cpp', 'matchbox_cpp', 'madweight',
2645- 'matchbox']:
2646+ 'matchbox', 'plugin']:
2647 self.get_default_path()
2648 if '-noclean' not in args and os.path.exists(self._export_dir):
2649 args.append('-noclean')
2650@@ -1665,6 +1693,11 @@
2651 (self._curr_model['name'], i)
2652 auto_path = lambda i: pjoin(self.writing_dir,
2653 name_dir(i))
2654+ elif self._export_format in ['plugin']:
2655+ name_dir = lambda i: 'PROC_PLUGIN_%s_%s' % \
2656+ (self._curr_model['name'], i)
2657+ auto_path = lambda i: pjoin(self.writing_dir,
2658+ name_dir(i))
2659 elif self._export_format == 'pythia8':
2660 if self.options['pythia8_path']:
2661 self._export_dir = self.options['pythia8_path']
2662@@ -1849,7 +1882,8 @@
2663 return self.list_completion(text, possibilities)
2664
2665 def model_completion(self, text, process, line, categories = True, \
2666- allowed_loop_mode = None):
2667+ allowed_loop_mode = None,
2668+ formatting=True):
2669 """ complete the line with model information. If categories is True,
2670 it will use completion with categories. If allowed_loop_mode is
2671 specified, it will only complete with these loop modes."""
2672@@ -1926,9 +1960,9 @@
2673 if len(possibilities.keys())==1:
2674 return self.list_completion(text, possibilities.values()[0])
2675 else:
2676- return self.deal_multiple_categories(possibilities)
2677+ return self.deal_multiple_categories(possibilities, formatting)
2678
2679- def complete_generate(self, text, line, begidx, endidx):
2680+ def complete_generate(self, text, line, begidx, endidx, formatting=True):
2681 "Complete the generate command"
2682
2683 # Return list of particle names and multiparticle names, as well as
2684@@ -1936,25 +1970,25 @@
2685 args = self.split_arg(line[0:begidx])
2686
2687 valid_sqso_operators=['==','<=','>']
2688+
2689 if any(line.endswith('^2 %s '%op) for op in valid_sqso_operators):
2690 return
2691 if args[-1].endswith('^2'):
2692 return self.list_completion(text,valid_sqso_operators)
2693 match_op = [o for o in valid_sqso_operators if o.startswith(args[-1])]
2694- if args[-2].endswith('^2') and len(match_op)>0:
2695+ if len(args)>2 and args[-2].endswith('^2') and len(match_op)>0:
2696 if args[-1] in valid_sqso_operators:
2697 return self.list_completion(text,' ')
2698 if len(match_op)==1:
2699 return self.list_completion(text,[match_op[0][len(args[-1]):]])
2700 else:
2701 return self.list_completion(text,match_op)
2702-
2703 if len(args) > 2 and args[-1] == '@' or ( args[-1].endswith('=') and \
2704 (not '[' in line or ('[' in line and ']' in line))):
2705 return
2706
2707 try:
2708- return self.model_completion(text, ' '.join(args[1:]),line)
2709+ return self.model_completion(text, ' '.join(args[1:]),line, formatting)
2710 except Exception as error:
2711 print error
2712
2713@@ -1966,7 +2000,7 @@
2714 # self._multiparticles.keys() + couplings)
2715
2716
2717- def complete_compute_widths(self, text, line, begidx, endidx):
2718+ def complete_compute_widths(self, text, line, begidx, endidx,formatting=True):
2719 "Complete the compute_widths command"
2720
2721 args = self.split_arg(line[0:begidx])
2722@@ -1987,11 +2021,11 @@
2723 '--precision_channel=0.\$', '--body_decay=', '--nlo'])
2724 completion['particles'] = self.model_completion(text, '', line)
2725
2726- return self.deal_multiple_categories(completion)
2727+ return self.deal_multiple_categories(completion,formatting)
2728
2729 complete_decay_diagram = complete_compute_widths
2730
2731- def complete_add(self, text, line, begidx, endidx):
2732+ def complete_add(self, text, line, begidx, endidx, formatting):
2733 "Complete the add command"
2734
2735 args = self.split_arg(line[0:begidx])
2736@@ -2005,9 +2039,9 @@
2737
2738 elif args[1] == 'model':
2739 completion_categories = self.complete_import(text, line, begidx, endidx,
2740- allow_restrict=False, treat_completion=False)
2741+ allow_restrict=False, formatting=False)
2742 completion_categories['options'] = self.list_completion(text,['--modelname=','--recreate'])
2743- return self.deal_multiple_categories(completion_categories)
2744+ return self.deal_multiple_categories(completion_categories, formatting)
2745
2746 def complete_customize_model(self, text, line, begidx, endidx):
2747 "Complete the customize_model command"
2748@@ -2019,7 +2053,7 @@
2749 return self.list_completion(text, ['--save='])
2750
2751
2752- def complete_check(self, text, line, begidx, endidx):
2753+ def complete_check(self, text, line, begidx, endidx, formatting=True):
2754 "Complete the check command"
2755
2756 out = {}
2757@@ -2053,7 +2087,7 @@
2758 {'Process completion': self.model_completion(text, ' '.join(args[2:]),
2759 line, categories = False, allowed_loop_mode=['virt']),
2760 'Param_card.dat path completion:':self.path_completion(text),
2761- 'options': self.list_completion(text,options)})
2762+ 'options': self.list_completion(text,options)}, formatting)
2763
2764 #Special rules for check cms completion
2765 if cms_check_mode:
2766@@ -2085,7 +2119,7 @@
2767 return self.deal_multiple_categories(
2768 {"Examples of completion for option '%s'"%args[-1].split('=')[0]:
2769 # ['%d: %s'%(i+1,ex) for i, ex in enumerate(example)]},
2770- ['%s'%ex for i, ex in enumerate(example)]},
2771+ ['%s'%ex for i, ex in enumerate(example)]},formatting,
2772 forceCategory=True)
2773 if args[-1]=='--recompute_width=':
2774 return self.list_completion(text,
2775@@ -2104,17 +2138,20 @@
2776 line, categories = False, allowed_loop_mode=['virt']),
2777 'Param_card.dat path completion:': self.path_completion(text),
2778 'reanalyze result on disk / save output:':self.list_completion(
2779- text,['-reuse','--analyze='])})
2780+ text,['-reuse','--analyze='])},
2781+ formatting)
2782 elif not any(arg.startswith('--') for arg in args):
2783 if '>' in args:
2784 return self.deal_multiple_categories({'Process completion':
2785 self.model_completion(text, ' '.join(args[2:]),
2786 line, categories = False, allowed_loop_mode=['virt']),
2787- 'options': self.list_completion(text,options)})
2788+ 'options': self.list_completion(text,options)},
2789+ formatting)
2790 else:
2791 return self.deal_multiple_categories({'Process completion':
2792 self.model_completion(text, ' '.join(args[2:]),
2793- line, categories = False, allowed_loop_mode=['virt'])})
2794+ line, categories = False, allowed_loop_mode=['virt'])},
2795+ formatting)
2796 else:
2797 return self.list_completion(text,options)
2798
2799@@ -2177,7 +2214,7 @@
2800 'non_propagating', '--']
2801 return self.list_completion(text, opt)
2802
2803- def complete_launch(self, text, line, begidx, endidx):
2804+ def complete_launch(self, text, line, begidx, endidx,formatting=True):
2805 """ complete the launch command"""
2806 args = self.split_arg(line[0:begidx])
2807
2808@@ -2211,7 +2248,7 @@
2809 out['Options'] = self.list_completion(text, opt, line)
2810
2811
2812- return self.deal_multiple_categories(out)
2813+ return self.deal_multiple_categories(out,formatting)
2814
2815 def complete_load(self, text, line, begidx, endidx):
2816 "Complete the load command"
2817@@ -2333,7 +2370,7 @@
2818 content += possible_options_full
2819 return self.list_completion(text, content)
2820
2821- def aloha_complete_output(self, text, line, begidx, endidx):
2822+ def aloha_complete_output(self, text, line, begidx, endidx,formatting=True):
2823 "Complete the output aloha command"
2824 args = self.split_arg(line[0:begidx])
2825 completion_categories = {}
2826@@ -2372,7 +2409,7 @@
2827 completion_categories['Wavefunctions routines'] = self.list_completion(text, wf_opt)
2828 completion_categories['conjugate_routines'] = self.list_completion(text, opt_conjg)
2829
2830- return self.deal_multiple_categories(completion_categories)
2831+ return self.deal_multiple_categories(completion_categories,formatting)
2832
2833 def complete_set(self, text, line, begidx, endidx):
2834 "Complete the set command"
2835@@ -2426,7 +2463,7 @@
2836 only_dirs = True)
2837
2838 def complete_import(self, text, line, begidx, endidx, allow_restrict=True,
2839- treat_completion=True):
2840+ formatting=True):
2841 "Complete the import command"
2842
2843 args=self.split_arg(line[0:begidx])
2844@@ -2569,11 +2606,9 @@
2845 if len(args) >= 3 and mode.startswith('banner') and not '--no_launch' in line:
2846 completion_categories['options'] = self.list_completion(text, ['--no_launch'])
2847
2848- if treat_completion:
2849- return self.deal_multiple_categories(completion_categories)
2850- else:
2851- #this means this function is called as a subgroup of another completion
2852- return completion_categories
2853+ return self.deal_multiple_categories(completion_categories,formatting)
2854+
2855+
2856 def find_restrict_card(self, model_name, base_dir='./', no_restrict=True):
2857 """find the restriction file associate to a given model"""
2858
2859@@ -2637,9 +2672,8 @@
2860 _check_opts = ['full', 'timing', 'stability', 'profile', 'permutation',
2861 'gauge','lorentz', 'brs', 'cms']
2862 _import_formats = ['model_v4', 'model', 'proc_v4', 'command', 'banner']
2863- _install_opts = ['pythia-pgs', 'Delphes', 'MadAnalysis', 'ExRootAnalysis',
2864- 'update', 'Delphes2', 'SysCalc', 'Golem95', 'PJFry',
2865- 'QCDLoop']
2866+ _install_opts = ['Delphes', 'MadAnalysis', 'ExRootAnalysis',
2867+ 'update', 'SysCalc', 'Golem95', 'PJFry', 'QCDLoop']
2868 # The targets below are installed using the HEPToolsInstaller.py script
2869 _advanced_install_opts = ['ninja','collier']
2870
2871@@ -2732,8 +2766,7 @@
2872 _curr_model = None #base_objects.Model()
2873 _curr_amps = diagram_generation.AmplitudeList()
2874 _curr_matrix_elements = helas_objects.HelasMultiProcess()
2875- _curr_fortran_model = None
2876- _curr_cpp_model = None
2877+ _curr_helas_model = None
2878 _curr_exporter = None
2879 _done_export = False
2880 _curr_decaymodel = None
2881@@ -2837,6 +2870,11 @@
2882 warning_duplicate = False
2883 args.remove('--no_warning=duplicate')
2884
2885+ diagram_filter = False
2886+ if '--diagram_filter' in args:
2887+ diagram_filter = True
2888+ args.remove('--diagram_filter')
2889+
2890 # Check the validity of the arguments
2891 self.check_add(args)
2892
2893@@ -2927,7 +2965,7 @@
2894 myproc = diagram_generation.MultiProcess(myprocdef,
2895 collect_mirror_procs = collect_mirror_procs,
2896 ignore_six_quark_processes = ignore_six_quark_processes,
2897- optimize=optimize)
2898+ optimize=optimize, diagram_filter=diagram_filter)
2899
2900
2901 for amp in myproc.get('amplitudes'):
2902@@ -2958,6 +2996,7 @@
2903
2904 model_path = args[0]
2905 recreate = ('--recreate' in args)
2906+ keep_decay = ('--keep_decay' in args)
2907 output_dir = [a.split('=',1)[1] for a in args if a.startswith('--output')]
2908 if output_dir:
2909 output_dir = output_dir[0]
2910@@ -2998,6 +3037,10 @@
2911 base_model.add_model(path=model_path, identify_particles=identify)
2912 base_model.write(output_dir)
2913
2914+ if keep_decay and os.path.exists(pjoin(self._curr_model.get('modelpath'), 'decays.py')):
2915+ base_model.mod_file(pjoin(pjoin(self._curr_model.get('modelpath'), 'decays.py')),
2916+ pjoin(pjoin(output_dir, 'decays.py')))
2917+
2918 new_model_name = output_dir
2919 if restrict_name:
2920 new_model_name = '%s-%s' % (output_dir, restrict_name)
2921@@ -4904,9 +4947,6 @@
2922 if args[0].endswith('_v4'):
2923 self._curr_model, self._model_v4_path = \
2924 import_v4.import_model(args[1], self._mgme_dir)
2925- self._curr_fortran_model = \
2926- helas_call_writers.FortranHelasCallWriter(\
2927- self._curr_model)
2928 else:
2929 # avoid loading the qcd/qed model twice
2930 if (args[1].startswith('loop_qcd_qed_sm') or\
2931@@ -4960,13 +5000,6 @@
2932 self._curr_model = None
2933 self.do_set('gauge unitary', log= False)
2934 return
2935-
2936- self._curr_fortran_model = \
2937- helas_call_writers.FortranUFOHelasCallWriter(\
2938- self._curr_model)
2939- self._curr_cpp_model = \
2940- helas_call_writers.CPPUFOHelasCallWriter(\
2941- self._curr_model)
2942
2943 if '-modelname' not in args:
2944 self._curr_model.pass_particles_name_in_mg_default()
2945@@ -5077,10 +5110,6 @@
2946 """ import the UFO model """
2947
2948 self._curr_model = import_ufo.import_model(model_name)
2949- self._curr_fortran_model = \
2950- helas_call_writers.FortranUFOHelasCallWriter(self._curr_model)
2951- self._curr_cpp_model = \
2952- helas_call_writers.CPPUFOHelasCallWriter(self._curr_model)
2953
2954 def process_model(self):
2955 """Set variables _particle_names and _couplings for tab
2956@@ -5530,7 +5559,6 @@
2957 logger.info(" when using results produced with this tool.", '$MG:color:BLACK')
2958 logger.info("------------------------------------------------------", '$MG:color:GREEN')
2959
2960-
2961 # Load file with path of the different program:
2962 import urllib
2963 if paths:
2964@@ -6488,15 +6516,11 @@
2965 if self._curr_model.get('parameters'):
2966 # This is a UFO model
2967 self._model_v4_path = None
2968- self._curr_fortran_model = \
2969- helas_call_writers.FortranUFOHelasCallWriter(self._curr_model)
2970 else:
2971 # This is a v4 model
2972 self._model_v4_path = import_v4.find_model_path(\
2973 self._curr_model.get('name').replace("_v4", ""),
2974 self._mgme_dir)
2975- self._curr_fortran_model = \
2976- helas_call_writers.FortranHelasCallWriter(self._curr_model)
2977
2978 # Do post-processing of model
2979 self.process_model()
2980@@ -6522,14 +6546,8 @@
2981 self._model_v4_path = import_v4.find_model_path(\
2982 model.get('name').replace("_v4", ""),
2983 self._mgme_dir)
2984- self._curr_fortran_model = \
2985- helas_call_writers.FortranHelasCallWriter(\
2986- model)
2987 else:
2988 self._model_v4_path = None
2989- self._curr_fortran_model = \
2990- helas_call_writers.FortranUFOHelasCallWriter(\
2991- model)
2992 # If not exceptions from previous steps, set
2993 # _curr_amps and _curr_model
2994 self._curr_amps = amps
2995@@ -6649,37 +6667,53 @@
2996 raise self.InvalidCmd('No processes to save!')
2997
2998 elif args[0] == 'options':
2999- # First look at options which should be put in MG5DIR/input
3000+ partial_save = False
3001 to_define = {}
3002- for key, default in self.options_configuration.items():
3003- if self.options_configuration[key] != self.options[key] and not self.options_configuration[key] is None:
3004- to_define[key] = self.options[key]
3005-
3006- if not '--auto' in args:
3007- for key, default in self.options_madevent.items():
3008- if self.options_madevent[key] != self.options[key] != None:
3009- if '_path' in key and os.path.basename(self.options[key]) == 'None':
3010- continue
3011- to_define[key] = self.options[key]
3012- elif key == 'cluster_queue' and self.options[key] is None:
3013- to_define[key] = self.options[key]
3014-
3015- if '--all' in args:
3016- for key, default in self.options_madgraph.items():
3017- if self.options_madgraph[key] != self.options[key] != None and \
3018- key != 'stdout_level':
3019- to_define[key] = self.options[key]
3020- elif not '--auto' in args:
3021- for key, default in self.options_madgraph.items():
3022- if self.options_madgraph[key] != self.options[key] != None and key != 'stdout_level':
3023- logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \
3024- % (key,self.options_madgraph[key]) )
3025- logger.info('If you want to make this value the default for future session, you can run \'save options --all\'')
3026- if len(args) >1 and not args[1].startswith('--'):
3027+ if any(not arg.startswith('--') and arg in self.options
3028+ for arg in args):
3029+ # store in file only those ones
3030+ partial_save = True
3031+ all_arg = [arg for arg in args[1:] if not arg.startswith('--') and
3032+ arg in self.options]
3033+ for key in all_arg:
3034+ to_define[key] = self.options[key]
3035+ else:
3036+ # First look at options which should be put in MG5DIR/input
3037+ for key, default in self.options_configuration.items():
3038+ if self.options_configuration[key] != self.options[key] and not self.options_configuration[key] is None:
3039+ to_define[key] = self.options[key]
3040+
3041+ if not '--auto' in args:
3042+ for key, default in self.options_madevent.items():
3043+ if self.options_madevent[key] != self.options[key] != None:
3044+ if '_path' in key and os.path.basename(self.options[key]) == 'None':
3045+ continue
3046+ to_define[key] = self.options[key]
3047+ elif key == 'cluster_queue' and self.options[key] is None:
3048+ to_define[key] = self.options[key]
3049+
3050+ if '--all' in args:
3051+ for key, default in self.options_madgraph.items():
3052+ if self.options_madgraph[key] != self.options[key] != None and \
3053+ key != 'stdout_level':
3054+ to_define[key] = self.options[key]
3055+ elif not '--auto' in args:
3056+ for key, default in self.options_madgraph.items():
3057+ if self.options_madgraph[key] != self.options[key] != None and key != 'stdout_level':
3058+ logger.info('The option %s is modified [%s] but will not be written in the configuration files.' \
3059+ % (key,self.options_madgraph[key]) )
3060+ logger.info('If you want to make this value the default for future session, you can run \'save options --all\'')
3061+
3062+ if len(args) >1 and not args[1].startswith('--') and args[1] not in self.options:
3063 filepath = args[1]
3064 else:
3065 filepath = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
3066- basefile = pjoin(MG5DIR, 'input', '.mg5_configuration_default.txt')
3067+
3068+ if partial_save:
3069+ basefile = filepath
3070+ else:
3071+ basefile = pjoin(MG5DIR, 'input', '.mg5_configuration_default.txt')
3072+
3073 basedir = MG5DIR
3074
3075 if to_keep:
3076@@ -6813,8 +6847,7 @@
3077 self._curr_model = None
3078 self._curr_amps = diagram_generation.AmplitudeList()
3079 self._curr_matrix_elements = helas_objects.HelasMultiProcess()
3080- self._curr_fortran_model = None
3081- self._curr_cpp_model = None
3082+ self._curr_helas_model = None
3083 self._curr_exporter = None
3084 self._done_export = False
3085 import_ufo._import_once = []
3086@@ -7074,7 +7107,11 @@
3087 config['matchbox'] = {'check': True, 'exporter': 'v4', 'output': 'Template'}
3088 config['madweight'] = {'check': True, 'exporter': 'v4', 'output':'Template'}
3089
3090- options = config[self._export_format]
3091+ if self._export_format == 'plugin':
3092+ options = {'check': self._export_plugin.check, 'exporter':self._export_plugin.exporter, 'output':self._export_plugin.output}
3093+ else:
3094+ options = config[self._export_format]
3095+
3096 # check
3097 if os.path.realpath(self._export_dir) == os.getcwd():
3098 if len(args) == 0:
3099@@ -7137,12 +7174,14 @@
3100 if options['exporter'] == 'v4':
3101 self._curr_exporter = export_v4.ExportV4Factory(self, noclean,
3102 group_subprocesses=group_processes)
3103- if options['output'] == 'Template':
3104- self._curr_exporter.copy_v4template(modelname=self._curr_model.get('name'))
3105- if options['exporter'] == 'cpp' and options['output'] == 'Template':
3106- export_cpp.setup_cpp_standalone_dir(self._export_dir, self._curr_model)
3107-
3108- if options['output'] == 'dir' and not os.path.isdir(self._export_dir):
3109+ elif options['exporter'] == 'cpp':
3110+ self._curr_exporter = export_cpp.ExportCPPFactory(self, group_subprocesses=group_processes)
3111+
3112+ self._curr_exporter.pass_information_from_cmd(self)
3113+
3114+ if options['output'] == 'Template':
3115+ self._curr_exporter.copy_template(self._curr_model)
3116+ elif options['output'] == 'dir' and not os.path.isdir(self._export_dir):
3117 os.makedirs(self._export_dir)
3118
3119 # Reset _done_export, since we have new directory
3120@@ -7173,6 +7212,16 @@
3121 args=[]):
3122 """Export a generated amplitude to file."""
3123
3124+ # Define the helas call writer
3125+ if self._curr_exporter.exporter == 'cpp':
3126+ self._curr_helas_model = helas_call_writers.CPPUFOHelasCallWriter(self._curr_model)
3127+ elif self._model_v4_path:
3128+ assert self._curr_exporter.exporter == 'v4'
3129+ self._curr_helas_model = helas_call_writers.FortranHelasCallWriter(self._curr_model)
3130+ else:
3131+ assert self._curr_exporter.exporter == 'v4'
3132+ self._curr_helas_model = helas_call_writers.FortranUFOHelasCallWriter(self._curr_model)
3133+
3134 version = [arg[10:] for arg in args if arg.startswith('--version=')]
3135 if version:
3136 version = version[-1]
3137@@ -7212,16 +7261,18 @@
3138 subproc_groups = group_subprocs.SubProcessGroupList()
3139 matrix_elements_opts = {'optimized_output':
3140 self.options['loop_optimized_output']}
3141+
3142+ grouping_criteria = self._curr_exporter.grouped_mode
3143 if non_dc_amps:
3144 subproc_groups.extend(\
3145 group_subprocs.SubProcessGroup.group_amplitudes(\
3146- non_dc_amps, self._export_format,
3147+ non_dc_amps,grouping_criteria,
3148 matrix_elements_opts=matrix_elements_opts))
3149
3150 if dc_amps:
3151 dc_subproc_group = \
3152 group_subprocs.DecayChainSubProcessGroup.\
3153- group_amplitudes(dc_amps, self._export_format,
3154+ group_amplitudes(dc_amps, grouping_criteria,
3155 matrix_elements_opts=matrix_elements_opts)
3156 subproc_groups.extend(dc_subproc_group.\
3157 generate_helas_decay_chain_subproc_groups())
3158@@ -7276,11 +7327,7 @@
3159 calls = 0
3160
3161 path = self._export_dir
3162- if self._export_format in ['standalone_cpp', 'madevent', 'standalone',
3163- 'standalone_msP', 'standalone_msF', 'standalone_rw',
3164- 'matchbox_cpp', 'madweight', 'matchbox']:
3165- path = pjoin(path, 'SubProcesses')
3166-
3167+
3168 cpu_time1 = time.time()
3169
3170 # First treat madevent and pythia8 exports, where we need to
3171@@ -7288,10 +7335,10 @@
3172
3173 # MadEvent
3174 if self._export_format == 'madevent':
3175+ path = pjoin(path, 'SubProcesses')
3176 calls += self._curr_exporter.export_processes(self._curr_matrix_elements,
3177- self._curr_fortran_model)
3178- self._curr_exporter.write_global_specs(
3179- self._curr_matrix_elements.get_matrix_elements())
3180+ self._curr_helas_model)
3181+
3182
3183 # Write the procdef_mg5.dat file with process info
3184 card_path = pjoin(path, os.path.pardir, 'SubProcesses', \
3185@@ -7307,21 +7354,21 @@
3186 pass
3187
3188 # Pythia 8
3189- if self._export_format == 'pythia8':
3190+ elif self._export_format == 'pythia8':
3191 # Output the process files
3192 process_names = []
3193 if isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList):
3194 for (group_number, me_group) in enumerate(self._curr_matrix_elements):
3195- exporter = export_cpp.generate_process_files_pythia8(\
3196- me_group.get('matrix_elements'), self._curr_cpp_model,
3197+ exporter = self._curr_exporter.generate_process_directory(\
3198+ me_group.get('matrix_elements'), self._curr_helas_model,
3199 process_string = me_group.get('name'),
3200- process_number = group_number, path = path,
3201+ process_number = group_number,
3202 version = version)
3203 process_names.append(exporter.process_name)
3204 else:
3205- exporter = export_cpp.generate_process_files_pythia8(\
3206- self._curr_matrix_elements, self._curr_cpp_model,
3207- process_string = self._generate_info, path = path)
3208+ exporter = self._curr_exporter.generate_process_directory(\
3209+ self._curr_matrix_elements, self._curr_helas_model,
3210+ process_string = self._generate_info, version = version)
3211 process_names.append(exporter.process_file_name)
3212
3213 # Output the model parameter and ALOHA files
3214@@ -7330,44 +7377,14 @@
3215
3216 # Generate the main program file
3217 filename, make_filename = \
3218- export_cpp.generate_example_file_pythia8(path,
3219+ self._curr_exporter.generate_example_file_pythia8(path,
3220 model_path,
3221 process_names,
3222 exporter,
3223 main_file_name)
3224-
3225- # Pick out the matrix elements in a list
3226+
3227+
3228 matrix_elements = self._curr_matrix_elements.get_matrix_elements()
3229-
3230- # Fortran MadGraph MadWeight
3231- if self._export_format == 'madweight':
3232-
3233- if isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList):
3234- #remove the merging between electron and muon
3235- self._curr_matrix_elements = self._curr_matrix_elements.split_lepton_grouping()
3236-
3237- for (group_number, me_group) in enumerate(self._curr_matrix_elements):
3238- calls = calls + \
3239- self._curr_exporter.generate_subprocess_directory_v4(\
3240- me_group, self._curr_fortran_model,
3241- group_number)
3242- else:
3243- for me_number, me in \
3244- enumerate(self._curr_matrix_elements.get_matrix_elements()):
3245- calls = calls + \
3246- self._curr_exporter.generate_subprocess_directory_v4(\
3247- me, self._curr_fortran_model, me_number)
3248-
3249- # Fortran MadGraph5_aMC@NLO Standalone
3250- if self._export_format in ['standalone', 'standalone_msP',
3251- 'standalone_msF', 'standalone_rw', 'matchbox']:
3252- for me in matrix_elements[:]:
3253- new_calls = self._curr_exporter.generate_subprocess_directory_v4(\
3254- me, self._curr_fortran_model)
3255- if not new_calls:
3256- matrix_elements.remove(me)
3257- calls = calls + new_calls
3258-
3259 # Just the matrix.f files
3260 if self._export_format == 'matrix':
3261 for me in matrix_elements:
3262@@ -7379,15 +7396,31 @@
3263 logger.info("Creating new file %s" % filename)
3264 calls = calls + self._curr_exporter.write_matrix_element_v4(\
3265 writers.FortranWriter(filename),\
3266- me, self._curr_fortran_model)
3267+ me, self._curr_helas_model)
3268+ elif self._export_format in ['madevent', 'pythia8']:
3269+ pass
3270+ # grouping mode
3271+ elif isinstance(self._curr_matrix_elements, group_subprocs.SubProcessGroupList) and\
3272+ self._curr_exporter.grouped_mode:
3273+ modify, self._curr_matrix_elements = self._curr_exporter.modify_grouping(self._curr_matrix_elements)
3274+ if modify:
3275+ matrix_elements = self._curr_matrix_elements.get_matrix_elements()
3276
3277- # C++ standalone
3278- if self._export_format in ['standalone_cpp', 'matchbox_cpp']:
3279- for me in matrix_elements:
3280- export_cpp.generate_subprocess_directory_standalone_cpp(\
3281- me, self._curr_cpp_model,
3282- path = path,
3283- format=self._export_format)
3284+ for me_number, me in enumerate(self._curr_matrix_elements):
3285+ calls = calls + \
3286+ self._curr_exporter.generate_subprocess_directory(\
3287+ me, self._curr_helas_model, me_number)
3288+
3289+ # ungroup mode
3290+ else:
3291+ for nb,me in enumerate(matrix_elements[:]):
3292+ new_calls = self._curr_exporter.generate_subprocess_directory(\
3293+ me, self._curr_helas_model, nb)
3294+ if isinstance(new_calls, int):
3295+ if new_calls ==0:
3296+ matrix_elements.remove(me)
3297+ else:
3298+ calls = calls + new_calls
3299
3300 cpu_time2 = time.time() - cpu_time1
3301
3302@@ -7416,6 +7449,7 @@
3303 # Replace the amplitudes with the actual amplitudes from the
3304 # matrix elements, which allows proper diagram drawing also of
3305 # decay chain processes
3306+ matrix_elements = self._curr_matrix_elements.get_matrix_elements()
3307 self._curr_amps = diagram_generation.AmplitudeList(\
3308 [me.get('base_amplitude') for me in \
3309 matrix_elements])
3310@@ -7428,79 +7462,42 @@
3311 'cpp': self.options['cpp_compiler'],
3312 'f2py': self.options['f2py_compiler']}
3313
3314-
3315- if self._export_format in ['madevent', 'standalone', 'standalone_msP',
3316- 'standalone_msF', 'standalone_rw', 'NLO', 'madweight',
3317- 'matchbox']:
3318-
3319- # For v4 models, copy the model/HELAS information.
3320- if self._model_v4_path:
3321- logger.info('Copy %s model files to directory %s' % \
3322+ # Handling of the model.
3323+ if self._model_v4_path:
3324+ logger.info('Copy %s model files to directory %s' % \
3325 (os.path.basename(self._model_v4_path), self._export_dir))
3326- self._curr_exporter.export_model_files(self._model_v4_path)
3327- self._curr_exporter.export_helas(pjoin(self._mgme_dir,'HELAS'))
3328- else:
3329- logger.info('Export UFO model to MG4 format')
3330- # wanted_lorentz are the lorentz structures which are
3331- # actually used in the wavefunctions and amplitudes in
3332- # these processes
3333- wanted_lorentz = self._curr_matrix_elements.get_used_lorentz()
3334- wanted_couplings = self._curr_matrix_elements.get_used_couplings()
3335- # For a unique output of multiple type of exporter need to store this
3336- # information.
3337- if hasattr(self, 'previous_lorentz'):
3338- wanted_lorentz = list(set(self.previous_lorentz + wanted_lorentz))
3339- wanted_couplings = list(set(self.previous_couplings + wanted_couplings))
3340- del self.previous_lorentz
3341- del self.previous_couplings
3342- if 'store_model' in flaglist:
3343- self.previous_lorentz = wanted_lorentz
3344- self.previous_couplings = wanted_couplings
3345- else:
3346- self._curr_exporter.convert_model_to_mg4(self._curr_model,
3347- wanted_lorentz,
3348- wanted_couplings)
3349- if self._export_format in ['standalone_cpp', 'matchbox_cpp']:
3350- logger.info('Export UFO model to C++ format')
3351+ self._curr_exporter.export_model_files(self._model_v4_path)
3352+ self._curr_exporter.export_helas(pjoin(self._mgme_dir,'HELAS'))
3353+ else:
3354 # wanted_lorentz are the lorentz structures which are
3355 # actually used in the wavefunctions and amplitudes in
3356 # these processes
3357 wanted_lorentz = self._curr_matrix_elements.get_used_lorentz()
3358 wanted_couplings = self._curr_matrix_elements.get_used_couplings()
3359- export_cpp.convert_model_to_cpp(self._curr_model,
3360- pjoin(self._export_dir),
3361- wanted_lorentz,
3362- wanted_couplings)
3363- export_cpp.make_model_cpp(self._export_dir)
3364-
3365-
3366- elif self._export_format in ['NLO']:
3367- ## write fj_lhapdf_opts file
3368- devnull = os.open(os.devnull, os.O_RDWR)
3369- try:
3370- res = misc.call([self.options['lhapdf'], '--version'], \
3371- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
3372- except Exception:
3373- res = 1
3374- if res != 0:
3375- logger.info('The value for lhapdf in the current configuration does not ' + \
3376- 'correspond to a valid executable.\nPlease set it correctly either in ' + \
3377- 'input/mg5_configuration or with "set lhapdf /path/to/lhapdf-config" ' + \
3378- 'and regenrate the process. \nTo avoid regeneration, edit the ' + \
3379- ('%s/Cards/amcatnlo_configuration.txt file.\n' % self._export_dir ) + \
3380- 'Note that you can still compile and run aMC@NLO with the built-in PDFs\n')
3381-
3382-
3383-
3384- self._curr_exporter.finalize_fks_directory( \
3385- self._curr_matrix_elements,
3386- self.history,
3387- not nojpeg,
3388- online,
3389- compiler_dict,
3390- output_dependencies = self.options['output_dependencies'],
3391- MG5DIR = MG5DIR)
3392+ # For a unique output of multiple type of exporter need to store this
3393+ # information.
3394+ if hasattr(self, 'previous_lorentz'):
3395+ wanted_lorentz = list(set(self.previous_lorentz + wanted_lorentz))
3396+ wanted_couplings = list(set(self.previous_couplings + wanted_couplings))
3397+ del self.previous_lorentz
3398+ del self.previous_couplings
3399+ if 'store_model' in flaglist:
3400+ self.previous_lorentz = wanted_lorentz
3401+ self.previous_couplings = wanted_couplings
3402+ else:
3403+ self._curr_exporter.convert_model(self._curr_model,
3404+ wanted_lorentz,
3405+ wanted_couplings)
3406+
3407+ # move the old options to the flaglist system.
3408+ if nojpeg:
3409+ flaglist.append('nojpeg')
3410+ if online:
3411+ flaglist.append('online')
3412
3413+
3414+ if self._export_format in ['NLO']:
3415+ ## write fj_lhapdf_opts file
3416 # Create configuration file [path to executable] for amcatnlo
3417 filename = os.path.join(self._export_dir, 'Cards', 'amcatnlo_configuration.txt')
3418 opts_to_keep = ['lhapdf', 'fastjet', 'pythia8_path', 'hwpp_path', 'thepeg_path',
3419@@ -7518,15 +7515,12 @@
3420 self.do_save('options %s' % filename.replace(' ', '\ '), check=False,
3421 to_keep={'mg5_path':MG5DIR})
3422
3423- if self._export_format in ['madevent', 'standalone', 'standalone_msP', 'standalone_msF',
3424- 'standalone_rw', 'madweight', 'matchbox']:
3425+ # Dedicated finalize function.
3426+ self._curr_exporter.finalize(self._curr_matrix_elements,
3427+ self.history,
3428+ self.options,
3429+ flaglist)
3430
3431- self._curr_exporter.finalize_v4_directory( \
3432- self._curr_matrix_elements,
3433- self.history,
3434- not nojpeg,
3435- online,
3436- compiler_dict)
3437
3438 if self._export_format in ['madevent', 'standalone', 'standalone_cpp','madweight', 'matchbox']:
3439 logger.info('Output to directory ' + self._export_dir + ' done.')
3440@@ -7593,8 +7587,6 @@
3441 model = import_ufo.import_model(modelname, decay=True)
3442 else:
3443 self._curr_model = model
3444- self._curr_fortran_model = \
3445- helas_call_writers.FortranUFOHelasCallWriter(self._curr_model)
3446 if not isinstance(model, model_reader.ModelReader):
3447 model = model_reader.ModelReader(model)
3448
3449@@ -7663,7 +7655,7 @@
3450 elif value < 0:
3451 raise Exception, 'Partial width for %s > %s negative: %s' % \
3452 (particle.get('name'), ' '.join([p.get('name') for p in mode]), value)
3453- elif value < 0.1 and particle['color'] !=1:
3454+ elif 0 < value < 0.1 and particle['color'] !=1:
3455 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \
3456 % (particle.get('name'), value, decay_to))
3457 value = 0
3458@@ -7701,7 +7693,7 @@
3459 decay_dir = pjoin(path,'temp_decay')
3460 logger_mg.info('More info in temporary files:\n %s/index.html' % (decay_dir))
3461 with misc.MuteLogger(['madgraph','ALOHA','cmdprint','madevent'], [40,40,40,40]):
3462- self.exec_cmd('output %s -f' % decay_dir)
3463+ self.exec_cmd('output %s -f' % decay_dir,child=False)
3464 # Need to write the correct param_card in the correct place !!!
3465 if os.path.exists(opts['output']):
3466 files.cp(opts['output'], pjoin(decay_dir, 'Cards', 'param_card.dat'))
3467@@ -7746,7 +7738,7 @@
3468 for BR in param['decay'].decay_table[pid]:
3469 if len(BR.lhacode) == 3 and skip_2body:
3470 continue
3471- if BR.value * width <0.1 and particle['color'] !=1:
3472+ if 0 < BR.value * width <0.1 and particle['color'] !=1:
3473 logger.warning("partial width of particle %s lower than QCD scale:%s. Set it to zero. (%s)" \
3474 % (particle.get('name'), BR.value * width, BR.lhacode[1:]))
3475
3476
3477=== modified file 'madgraph/interface/master_interface.py'
3478--- madgraph/interface/master_interface.py 2016-07-20 22:43:24 +0000
3479+++ madgraph/interface/master_interface.py 2016-08-18 22:31:39 +0000
3480@@ -80,6 +80,9 @@
3481 def debug_link_to_command(self):
3482 """redefine all the command to call directly the appropriate child"""
3483
3484+ if hasattr(self, 'plugin') and self.plugin:
3485+ return True
3486+
3487 correct = True
3488 # function which should be self.cmd dependent but which doesn't start
3489 # by do_xxxx, help_xxx, check_xxxx or complete_xxx
3490@@ -114,7 +117,7 @@
3491 # in the Switcher or in one of the MasterClass
3492 define = {}
3493 for mother in MasterCmd.__mro__:
3494- if mother.__name__ in ['Cmd', 'BasicCmd', 'ExtendedCmd']:
3495+ if mother.__name__ in ['OriginalCmd', 'BasicCmd', 'CmdExtended', 'Cmd']:
3496 continue
3497
3498
3499@@ -134,9 +137,8 @@
3500 # Do the same for the WEb MasterClass
3501 define = {}
3502 for mother in MasterCmdWeb.__mro__:
3503- if mother.__name__ in ['Cmd', 'BasicCmd', 'ExtendedCmd']:
3504+ if mother.__name__ in ['OriginalCmd', 'BasicCmd', 'CmdExtended', 'Cmd']:
3505 continue
3506-
3507 for data in mother.__dict__:
3508 #check if define in Switcher
3509 if data in Switcher.__dict__ or data.startswith('__'):
3510
3511=== modified file 'madgraph/interface/reweight_interface.py'
3512--- madgraph/interface/reweight_interface.py 2016-07-29 15:27:30 +0000
3513+++ madgraph/interface/reweight_interface.py 2016-08-18 22:31:39 +0000
3514@@ -853,6 +853,9 @@
3515
3516 return 0
3517
3518+ def do_compute_widths(self, line):
3519+ return self.mother.do_compute_widths(line)
3520+
3521 def calculate_weight(self, event, space=None):
3522 """space defines where to find the calculator (in multicore)"""
3523
3524
3525=== modified file 'madgraph/iolibs/export_cpp.py'
3526--- madgraph/iolibs/export_cpp.py 2016-04-15 11:14:25 +0000
3527+++ madgraph/iolibs/export_cpp.py 2016-08-18 22:31:39 +0000
3528@@ -35,9 +35,11 @@
3529 import madgraph.iolibs.file_writers as writers
3530 import madgraph.iolibs.template_files as template_files
3531 import madgraph.iolibs.ufo_expression_parsers as parsers
3532+import madgraph.various.banner as banner_mod
3533 from madgraph import MadGraph5Error, InvalidCmd, MG5DIR
3534 from madgraph.iolibs.files import cp, ln, mv
3535
3536+from madgraph.iolibs.export_v4 import VirtualExporter
3537 import madgraph.various.misc as misc
3538
3539 import aloha.create_aloha as create_aloha
3540@@ -48,132 +50,6 @@
3541 pjoin = os.path.join
3542
3543
3544-
3545-#===============================================================================
3546-# setup_cpp_standalone_dir
3547-#===============================================================================
3548-def setup_cpp_standalone_dir(dirpath, model):
3549- """Prepare export_dir as standalone_cpp directory, including:
3550- src (for RAMBO, model and ALOHA files + makefile)
3551- lib (with compiled libraries from src)
3552- SubProcesses (with check_sa.cpp + makefile and Pxxxxx directories)
3553- """
3554-
3555- cwd = os.getcwd()
3556-
3557- try:
3558- os.mkdir(dirpath)
3559- except os.error as error:
3560- logger.warning(error.strerror + " " + dirpath)
3561-
3562- try:
3563- os.chdir(dirpath)
3564- except os.error:
3565- logger.error('Could not cd to directory %s' % dirpath)
3566- return 0
3567-
3568- logger.info('Creating subdirectories in directory %s' % dirpath)
3569-
3570- try:
3571- os.mkdir('src')
3572- except os.error as error:
3573- logger.warning(error.strerror + " " + dirpath)
3574-
3575- try:
3576- os.mkdir('lib')
3577- except os.error as error:
3578- logger.warning(error.strerror + " " + dirpath)
3579-
3580- try:
3581- os.mkdir('Cards')
3582- except os.error as error:
3583- logger.warning(error.strerror + " " + dirpath)
3584-
3585- try:
3586- os.mkdir('SubProcesses')
3587- except os.error as error:
3588- logger.warning(error.strerror + " " + dirpath)
3589-
3590- # Write param_card
3591- open(os.path.join("Cards","param_card.dat"), 'w').write(\
3592- model.write_param_card())
3593-
3594- src_files = ['rambo.h', 'rambo.cc', 'read_slha.h', 'read_slha.cc']
3595-
3596- # Copy the needed src files
3597- for f in src_files:
3598- cp(_file_path + 'iolibs/template_files/' + f, 'src')
3599-
3600- # Copy src Makefile
3601- makefile = read_template_file('Makefile_sa_cpp_src') % \
3602- {'model': ProcessExporterCPP.get_model_name(model.get('name'))}
3603- open(os.path.join('src', 'Makefile'), 'w').write(makefile)
3604-
3605- # Copy SubProcesses files
3606- cp(_file_path + 'iolibs/template_files/check_sa.cpp', 'SubProcesses')
3607-
3608- # Copy SubProcesses Makefile
3609- makefile = read_template_file('Makefile_sa_cpp_sp') % \
3610- {'model': ProcessExporterCPP.get_model_name(model.get('name'))}
3611- open(os.path.join('SubProcesses', 'Makefile'), 'w').write(makefile)
3612-
3613- # Return to original PWD
3614- os.chdir(cwd)
3615-
3616-#===============================================================================
3617-# generate_subprocess_directory_standalone_cpp
3618-#===============================================================================
3619-def generate_subprocess_directory_standalone_cpp(matrix_element,
3620- cpp_helas_call_writer,
3621- path = os.getcwd(),
3622- format='standalone_cpp'):
3623-
3624- """Generate the Pxxxxx directory for a subprocess in C++ standalone,
3625- including the necessary .h and .cc files"""
3626-
3627- cwd = os.getcwd()
3628- # Create the process_exporter
3629- if format == 'standalone_cpp':
3630- process_exporter_cpp = ProcessExporterCPP(matrix_element,
3631- cpp_helas_call_writer)
3632- elif format == 'matchbox_cpp':
3633- process_exporter_cpp = ProcessExporterMatchbox(matrix_element,
3634- cpp_helas_call_writer)
3635- else:
3636- raise Exception, 'Unrecognized format %s' % format
3637-
3638- # Create the directory PN_xx_xxxxx in the specified path
3639- dirpath = os.path.join(path, \
3640- "P%d_%s" % (process_exporter_cpp.process_number,
3641- process_exporter_cpp.process_name))
3642- try:
3643- os.mkdir(dirpath)
3644- except os.error as error:
3645- logger.warning(error.strerror + " " + dirpath)
3646-
3647- try:
3648- os.chdir(dirpath)
3649- except os.error:
3650- logger.error('Could not cd to directory %s' % dirpath)
3651- return 0
3652-
3653- logger.info('Creating files in directory %s' % dirpath)
3654-
3655- process_exporter_cpp.path = dirpath
3656- # Create the process .h and .cc files
3657- process_exporter_cpp.generate_process_files()
3658-
3659- linkfiles = ['check_sa.cpp', 'Makefile']
3660-
3661-
3662- for file in linkfiles:
3663- ln('../%s' % file)
3664-
3665- # Return to original PWD
3666- os.chdir(cwd)
3667-
3668- return
3669-
3670 def make_model_cpp(dir_path):
3671 """Make the model library in a C++ standalone directory"""
3672
3673@@ -182,16 +58,16 @@
3674 logger.info("Running make for src")
3675 misc.compile(cwd=source_dir)
3676
3677-#===============================================================================
3678-# ProcessExporterCPP
3679-#===============================================================================
3680-class ProcessExporterCPP(object):
3681+
3682+class OneProcessExporterCPP(object):
3683 """Class to take care of exporting a set of matrix elements to
3684 C++ format."""
3685
3686 # Static variables (for inheritance)
3687 process_dir = '.'
3688 include_dir = '.'
3689+ template_path = os.path.join(_file_path, 'iolibs', 'template_files')
3690+ __template_path = os.path.join(_file_path, 'iolibs', 'template_files')
3691 process_template_h = 'cpp_process_h.inc'
3692 process_template_cc = 'cpp_process_cc.inc'
3693 process_class_template = 'cpp_process_class.inc'
3694@@ -217,7 +93,7 @@
3695 self.matrix_elements = matrix_elements
3696 else:
3697 raise base_objects.PhysicsObject.PhysicsObjectError,\
3698- "Wrong object type for matrix_elements"
3699+ "Wrong object type for matrix_elements: %s" % type(matrix_elements)
3700
3701 if not self.matrix_elements:
3702 raise MadGraph5Error("No matrix elements to export")
3703@@ -305,8 +181,32 @@
3704 self.amplitudes = helas_objects.HelasMatrixElement({\
3705 'diagrams': helas_objects.HelasDiagramList([diagram])})
3706
3707+ #===============================================================================
3708+ # Global helper methods
3709+ #===============================================================================
3710+ @classmethod
3711+ def read_template_file(cls, filename, classpath=False):
3712+ """Open a template file and return the contents."""
3713+
3714+ if isinstance(filename, tuple):
3715+ file_path = filename[0]
3716+ filename = filename[1]
3717+ elif isinstance(filename, str):
3718+ if classpath:
3719+ file_path = cls.__template_path
3720+ else:
3721+ file_path = cls.template_path
3722+ else:
3723+ raise MadGraph5Error('Argument should be string or tuple.')
3724+
3725+ return open(os.path.join(file_path, filename)).read()
3726+
3727+
3728+
3729+
3730+
3731+
3732 # Methods for generation of process files for C++
3733-
3734 def generate_process_files(self):
3735 """Generate the .h and .cc files needed for C++, for the
3736 processes described by multi_matrix_element"""
3737@@ -335,13 +235,14 @@
3738
3739
3740 return replace_dict
3741+
3742 #===========================================================================
3743 # write_process_h_file
3744 #===========================================================================
3745 def write_process_h_file(self, writer):
3746 """Write the class definition (.h) file for the process"""
3747
3748- if not isinstance(writer, writers.CPPWriter):
3749+ if writer and not isinstance(writer, writers.CPPWriter):
3750 raise writers.CPPWriter.CPPWriterError(\
3751 "writer not CPPWriter")
3752
3753@@ -362,11 +263,12 @@
3754 process_class_definitions = self.get_process_class_definitions()
3755 replace_dict['process_class_definitions'] = process_class_definitions
3756
3757- file = read_template_file(self.process_template_h) % replace_dict
3758-
3759- # Write the file
3760- writer.writelines(file)
3761-
3762+ if writer:
3763+ file = self.read_template_file(self.process_template_h) % replace_dict
3764+ # Write the file
3765+ writer.writelines(file)
3766+ else:
3767+ return replace_dict
3768 #===========================================================================
3769 # write_process_cc_file
3770 #===========================================================================
3771@@ -374,8 +276,9 @@
3772 """Write the class member definition (.cc) file for the process
3773 described by matrix_element"""
3774
3775- if not isinstance(writer, writers.CPPWriter):
3776- raise writers.CPPWriter.CPPWriterError(\
3777+ if writer:
3778+ if not isinstance(writer, writers.CPPWriter):
3779+ raise writers.CPPWriter.CPPWriterError(\
3780 "writer not CPPWriter")
3781
3782 replace_dict = self.get_default_converter()
3783@@ -397,15 +300,17 @@
3784 replace_dict['process_function_definitions'] = \
3785 process_function_definitions
3786
3787- file = read_template_file(self.process_template_cc) % replace_dict
3788-
3789- # Write the file
3790- writer.writelines(file)
3791-
3792+ if writer:
3793+ file = self.read_template_file(self.process_template_cc) % replace_dict
3794+ # Write the file
3795+ writer.writelines(file)
3796+ else:
3797+ return replace_dict
3798+
3799 #===========================================================================
3800 # Process export helper functions
3801 #===========================================================================
3802- def get_process_class_definitions(self):
3803+ def get_process_class_definitions(self, write=True):
3804 """The complete class definition for the process"""
3805
3806 replace_dict = {}
3807@@ -472,11 +377,12 @@
3808 replace("0_", "") \
3809 for me in self.matrix_elements])
3810
3811-
3812- file = read_template_file(self.process_class_template) % replace_dict
3813-
3814- return file
3815-
3816+ if write:
3817+ file = self.read_template_file(self.process_class_template) % replace_dict
3818+ return file
3819+ else:
3820+ return replace_dict
3821+
3822 def get_process_function_definitions(self):
3823 """The complete Pythia 8 class definition for the process"""
3824
3825@@ -510,7 +416,7 @@
3826 self.get_all_sigmaKin_lines(color_amplitudes,
3827 'CPPProcess')
3828
3829- file = read_template_file(self.process_definition_template) %\
3830+ file = self.read_template_file(self.process_definition_template) %\
3831 replace_dict
3832
3833 return file
3834@@ -584,7 +490,7 @@
3835 return ret_lines
3836
3837
3838- def get_calculate_wavefunctions(self, wavefunctions, amplitudes):
3839+ def get_calculate_wavefunctions(self, wavefunctions, amplitudes, write=True):
3840 """Return the lines for optimized calculation of the
3841 wavefunctions for all subprocesses"""
3842
3843@@ -603,13 +509,15 @@
3844 replace_dict['amplitude_calls'] = "\n".join(\
3845 self.helas_call_writer.get_amplitude_calls(amplitudes))
3846
3847- file = read_template_file(self.process_wavefunction_template) % \
3848+ if write:
3849+ file = self.read_template_file(self.process_wavefunction_template) % \
3850 replace_dict
3851-
3852- return file
3853+ return file
3854+ else:
3855+ return replace_dict
3856
3857
3858- def get_sigmaKin_lines(self, color_amplitudes):
3859+ def get_sigmaKin_lines(self, color_amplitudes, write=True):
3860 """Get sigmaKin_lines for function definition for Pythia 8 .cc file"""
3861
3862
3863@@ -667,22 +575,27 @@
3864
3865 replace_dict['get_mirror_matrix_lines'] = mirror_matrix_lines
3866
3867-
3868- file = \
3869- read_template_file(\
3870+ if write:
3871+ file = \
3872+ self.read_template_file(\
3873 self.process_sigmaKin_function_template) %\
3874 replace_dict
3875-
3876- return file
3877-
3878+ return file
3879+ else:
3880+ return replace_dict
3881 else:
3882 ret_lines = "// Call the individual sigmaKin for each process\n"
3883- return ret_lines + \
3884+ ret_lines = ret_lines + \
3885 "\n".join(["sigmaKin_%s();" % \
3886 me.get('processes')[0].shell_string().\
3887 replace("0_", "") for \
3888 me in self.matrix_elements])
3889-
3890+ if write:
3891+ return ret_lines
3892+ else:
3893+ replace_dict['get_mirror_matrix_lines'] = ret_lines
3894+ return replace_dict
3895+
3896 def get_all_sigmaKin_lines(self, color_amplitudes, class_name):
3897 """Get sigmaKin_process for all subprocesses for Pythia 8 .cc file"""
3898
3899@@ -705,7 +618,7 @@
3900 return "\n".join(ret_lines)
3901
3902
3903- def get_sigmaKin_single_process(self, i, matrix_element):
3904+ def get_sigmaKin_single_process(self, i, matrix_element, write=True):
3905 """Write sigmaKin for each process"""
3906
3907 # Write sigmaKin for the process
3908@@ -731,14 +644,16 @@
3909 # Extract denominator
3910 replace_dict['den_factor'] = matrix_element.get_denominator_factor()
3911
3912- file = \
3913- read_template_file('cpp_process_sigmaKin_subproc_function.inc') %\
3914- replace_dict
3915-
3916- return file
3917-
3918+ if write:
3919+ file = \
3920+ self.read_template_file('cpp_process_sigmaKin_subproc_function.inc') %\
3921+ replace_dict
3922+ return file
3923+ else:
3924+ return replace_dict
3925+
3926 def get_matrix_single_process(self, i, matrix_element, color_amplitudes,
3927- class_name):
3928+ class_name, write=True):
3929 """Write matrix() for each process"""
3930
3931 # Write matrix() for the process
3932@@ -785,11 +700,13 @@
3933 #specific exporter hack
3934 replace_dict = self.get_class_specific_definition_matrix(replace_dict, matrix_element)
3935
3936- file = read_template_file(self.single_process_template) % \
3937+ if write:
3938+ file = self.read_template_file(self.single_process_template) % \
3939 replace_dict
3940-
3941- return file
3942-
3943+ return file
3944+ else:
3945+ return replace_dict
3946+
3947 def get_class_specific_definition_matrix(self, converter, matrix_element):
3948 """place to add some specific hack to a given exporter.
3949 Please always use Super in that case"""
3950@@ -945,45 +862,9 @@
3951 res_list.append(res)
3952
3953 return "\n".join(res_list)
3954-
3955- @staticmethod
3956- def get_model_name(name):
3957- """Replace - with _, + with _plus_ in a model name."""
3958-
3959- name = name.replace('-', '_')
3960- name = name.replace('+', '_plus_')
3961- return name
3962-
3963-#===============================================================================
3964-# generate_process_files_pythia8
3965-#===============================================================================
3966-def generate_process_files_pythia8(multi_matrix_element, cpp_helas_call_writer,
3967- process_string = "",
3968- process_number = 0, path = os.getcwd(),
3969- version='8.2'):
3970-
3971- """Generate the .h and .cc files needed for Pythia 8, for the
3972- processes described by multi_matrix_element"""
3973-
3974- process_exporter_pythia8 = ProcessExporterPythia8(multi_matrix_element,
3975- cpp_helas_call_writer,
3976- process_string,
3977- process_number,
3978- path,
3979- version=version)
3980-
3981- # Set process directory
3982- model = process_exporter_pythia8.model
3983- model_name = process_exporter_pythia8.model_name
3984- process_exporter_pythia8.process_dir = \
3985- 'Processes_%(model)s' % {'model': \
3986- model_name}
3987- process_exporter_pythia8.include_dir = process_exporter_pythia8.process_dir
3988- process_exporter_pythia8.generate_process_files()
3989- return process_exporter_pythia8
3990-
3991-
3992-class ProcessExporterMatchbox(ProcessExporterCPP):
3993+
3994+
3995+class OneProcessExporterMatchbox(OneProcessExporterCPP):
3996 """Class to take care of exporting a set of matrix elements to
3997 Matchbox format."""
3998
3999@@ -1007,7 +888,7 @@
4000 def get_class_specific_definition_matrix(self, converter, matrix_element):
4001 """ """
4002
4003- converter = super(ProcessExporterMatchbox, self).get_class_specific_definition_matrix(converter, matrix_element)
4004+ converter = super(OneProcessExporterMatchbox, self).get_class_specific_definition_matrix(converter, matrix_element)
4005
4006 # T(....)
4007 converter['color_sting_lines'] = \
4008@@ -1085,7 +966,7 @@
4009 #===============================================================================
4010 # ProcessExporterPythia8
4011 #===============================================================================
4012-class ProcessExporterPythia8(ProcessExporterCPP):
4013+class OneProcessExporterPythia8(OneProcessExporterCPP):
4014 """Class to take care of exporting a set of matrix elements to
4015 Pythia 8 format."""
4016
4017@@ -1096,6 +977,8 @@
4018 process_definition_template = 'pythia8_process_function_definitions.inc'
4019 process_wavefunction_template = 'pythia8_process_wavefunctions.inc'
4020 process_sigmaKin_function_template = 'pythia8_process_sigmaKin_function.inc'
4021+ template_path = os.path.join(_file_path, 'iolibs', 'template_files', 'pythia8')
4022+
4023
4024 def __init__(self, *args, **opts):
4025 """Set process class name"""
4026@@ -1105,7 +988,7 @@
4027 del opts['version']
4028 else:
4029 self.version='8.2'
4030- super(ProcessExporterPythia8, self).__init__(*args, **opts)
4031+ super(OneProcessExporterPythia8, self).__init__(*args, **opts)
4032
4033 # Check if any processes are not 2->1,2,3
4034 for me in self.matrix_elements:
4035@@ -1135,7 +1018,7 @@
4036 #===========================================================================
4037 # Process export helper functions
4038 #===========================================================================
4039- def get_process_class_definitions(self):
4040+ def get_process_class_definitions(self, write=True):
4041 """The complete Pythia 8 class definition for the process"""
4042
4043 replace_dict = self.get_default_converter()
4044@@ -1199,12 +1082,13 @@
4045 replace("0_", "") \
4046 for me in self.matrix_elements])
4047
4048-
4049- file = read_template_file('pythia8_process_class.inc') % replace_dict
4050-
4051- return file
4052-
4053- def get_process_function_definitions(self):
4054+ if write:
4055+ file = self.read_template_file('pythia8_process_class.inc') % replace_dict
4056+ return file
4057+ else:
4058+ return replace_dict
4059+
4060+ def get_process_function_definitions(self, write=True):
4061 """The complete Pythia 8 class definition for the process"""
4062
4063
4064@@ -1239,11 +1123,12 @@
4065 replace_dict['all_sigmaKin'] = \
4066 self.get_all_sigmaKin_lines(color_amplitudes,
4067 self.process_name)
4068-
4069- file = read_template_file('pythia8_process_function_definitions.inc') %\
4070+ if write:
4071+ file = self.read_template_file('pythia8_process_function_definitions.inc') %\
4072 replace_dict
4073-
4074- return file
4075+ return file
4076+ else:
4077+ return replace_dict
4078
4079 def get_process_influx(self):
4080 """Return process file name for the process in matrix_element"""
4081@@ -1292,6 +1177,19 @@
4082
4083 return
4084
4085+ #===============================================================================
4086+ # Global helper methods
4087+ #===============================================================================
4088+ @classmethod
4089+ def read_template_file(cls, filename):
4090+ """Open a template file and return the contents."""
4091+
4092+ try:
4093+ return super(OneProcessExporterPythia8, cls).read_template_file(filename)
4094+ except:
4095+ return super(OneProcessExporterPythia8, cls).read_template_file(filename, classpath=True)
4096+
4097+
4098 def get_id_masses(self, process):
4099 """Return the lines which define the ids for the final state particles,
4100 for the Pythia phase space"""
4101@@ -1693,19 +1591,295 @@
4102
4103
4104 #===============================================================================
4105-# Global helper methods
4106+# ProcessExporterCPP
4107 #===============================================================================
4108-def read_template_file(filename):
4109- """Open a template file and return the contents."""
4110- try:
4111- return open(os.path.join(_file_path, \
4112- 'iolibs', 'template_files', 'pythia8',
4113- filename)).read()
4114- except:
4115- return open(os.path.join(_file_path, \
4116- 'iolibs', 'template_files',
4117- filename)).read()
4118-
4119+class ProcessExporterCPP(VirtualExporter):
4120+ """Class to take care of exporting a set of matrix elements to
4121+ Fortran (v4) format."""
4122+
4123+ grouped_mode = False
4124+ exporter = 'cpp'
4125+
4126+ default_opt = {'clean': False, 'complex_mass':False,
4127+ 'export_format':'madevent', 'mp': False,
4128+ 'v5_model': True
4129+ }
4130+
4131+ oneprocessclass = OneProcessExporterCPP
4132+ s= _file_path + 'iolibs/template_files/'
4133+ from_template = {'src': [s+'rambo.h', s+'rambo.cc', s+'read_slha.h', s+'read_slha.cc'],
4134+ 'SubProcesses': [s+'check_sa.cpp']}
4135+ to_link_in_P = ['check_sa.cpp', 'Makefile']
4136+ template_src_make = pjoin(_file_path, 'iolibs', 'template_files','Makefile_sa_cpp_src')
4137+ template_Sub_make = template_src_make
4138+
4139+
4140+
4141+ def __init__(self, dir_path = "", opt=None):
4142+ """Initiate the ProcessExporterFortran with directory information"""
4143+ self.mgme_dir = MG5DIR
4144+ self.dir_path = dir_path
4145+ self.model = None
4146+
4147+ self.opt = dict(self.default_opt)
4148+ if opt:
4149+ self.opt.update(opt)
4150+
4151+ #place holder to pass information to the run_interface
4152+ self.proc_characteristic = banner_mod.ProcCharacteristic()
4153+
4154+ def copy_template(self, model):
4155+ """Prepare export_dir as standalone_cpp directory, including:
4156+ src (for RAMBO, model and ALOHA files + makefile)
4157+ lib (with compiled libraries from src)
4158+ SubProcesses (with check_sa.cpp + makefile and Pxxxxx directories)
4159+ """
4160+
4161+ try:
4162+ os.mkdir(self.dir_path)
4163+ except os.error as error:
4164+ logger.warning(error.strerror + " " + self.dir_path)
4165+
4166+ with misc.chdir(self.dir_path):
4167+ logger.info('Creating subdirectories in directory %s' % self.dir_path)
4168+
4169+ for d in ['src', 'lib', 'Cards', 'SubProcesses']:
4170+ try:
4171+ os.mkdir(d)
4172+ except os.error as error:
4173+ logger.warning(error.strerror + " " + self.dir_path)
4174+
4175+ # Write param_card
4176+ open(os.path.join("Cards","param_card.dat"), 'w').write(\
4177+ model.write_param_card())
4178+
4179+
4180+ # Copy the needed src files
4181+ for key in self.from_template:
4182+ for f in self.from_template[key]:
4183+ cp(f, key)
4184+
4185+ # Copy src Makefile
4186+ makefile = self.read_template_file('Makefile_sa_cpp_src') % \
4187+ {'model': self.get_model_name(model.get('name'))}
4188+ open(os.path.join('src', 'Makefile'), 'w').write(makefile)
4189+
4190+ # Copy SubProcesses Makefile
4191+ makefile = self.read_template_file('Makefile_sa_cpp_sp') % \
4192+ {'model': self.get_model_name(model.get('name'))}
4193+ open(os.path.join('SubProcesses', 'Makefile'), 'w').write(makefile)
4194+
4195+ #===========================================================================
4196+ # Helper functions
4197+ #===========================================================================
4198+ def modify_grouping(self, matrix_element):
4199+ """allow to modify the grouping (if grouping is in place)
4200+ return two value:
4201+ - True/False if the matrix_element was modified
4202+ - the new(or old) matrix element"""
4203+
4204+ return False, matrix_element
4205+
4206+
4207+
4208+ def convert_model(self, model, wanted_lorentz = [],
4209+ wanted_couplings = []):
4210+ # create the model parameter files
4211+ model_builder = UFOModelConverterCPP(model,
4212+ os.path.join(self.dir_path, 'src'),
4213+ wanted_lorentz,
4214+ wanted_couplings)
4215+ model_builder.write_files()
4216+
4217+ def compile_model(self):
4218+ make_model_cpp(self.dir_path)
4219+
4220+ @classmethod
4221+ def read_template_file(cls, *args, **opts):
4222+ """Open a template file and return the contents."""
4223+
4224+ return cls.oneprocessclass.read_template_file(*args, **opts)
4225+
4226+ #===============================================================================
4227+ # generate_subprocess_directory
4228+ #===============================================================================
4229+ def generate_subprocess_directory(self, matrix_element, cpp_helas_call_writer,
4230+ proc_number=None):
4231+ """Generate the Pxxxxx directory for a subprocess in C++ standalone,
4232+ including the necessary .h and .cc files"""
4233+
4234+
4235+ process_exporter_cpp = self.oneprocessclass(matrix_element,cpp_helas_call_writer)
4236+
4237+
4238+ # Create the directory PN_xx_xxxxx in the specified path
4239+ dirpath = pjoin(self.dir_path, 'SubProcesses', "P%d_%s" % (process_exporter_cpp.process_number,
4240+ process_exporter_cpp.process_name))
4241+ try:
4242+ os.mkdir(dirpath)
4243+ except os.error as error:
4244+ logger.warning(error.strerror + " " + dirpath)
4245+
4246+ with misc.chdir(dirpath):
4247+ logger.info('Creating files in directory %s' % dirpath)
4248+ process_exporter_cpp.path = dirpath
4249+ # Create the process .h and .cc files
4250+ process_exporter_cpp.generate_process_files()
4251+ for file in self.to_link_in_P:
4252+ ln('../%s' % file)
4253+ return
4254+
4255+ @staticmethod
4256+ def get_model_name(name):
4257+ """Replace - with _, + with _plus_ in a model name."""
4258+
4259+ name = name.replace('-', '_')
4260+ name = name.replace('+', '_plus_')
4261+ return name
4262+
4263+ def finalize(self, *args, **opts):
4264+ """ """
4265+ self.compile_model()
4266+ pass
4267+
4268+class ProcessExporterMatchbox(ProcessExporterCPP):
4269+ oneprocessclass = OneProcessExporterMatchbox
4270+
4271+class ProcessExporterPythia8(ProcessExporterCPP):
4272+ oneprocessclass = OneProcessExporterPythia8
4273+ grouped_mode = 'madevent'
4274+
4275+ #===============================================================================
4276+ # generate_process_files_pythia8
4277+ #===============================================================================
4278+ def generate_process_directory(self, multi_matrix_element, cpp_helas_call_writer,
4279+ process_string = "",
4280+ process_number = 0,
4281+ version='8.2'):
4282+
4283+ """Generate the .h and .cc files needed for Pythia 8, for the
4284+ processes described by multi_matrix_element"""
4285+
4286+ process_exporter_pythia8 = OneProcessExporterPythia8(multi_matrix_element,
4287+ cpp_helas_call_writer,
4288+ process_string,
4289+ process_number,
4290+ self.dir_path,
4291+ version=version)
4292+
4293+ # Set process directory
4294+ model = process_exporter_pythia8.model
4295+ model_name = process_exporter_pythia8.model_name
4296+ process_exporter_pythia8.process_dir = \
4297+ 'Processes_%(model)s' % {'model': \
4298+ model_name}
4299+ process_exporter_pythia8.include_dir = process_exporter_pythia8.process_dir
4300+ process_exporter_pythia8.generate_process_files()
4301+ return process_exporter_pythia8
4302+
4303+ #===============================================================================
4304+ # generate_example_file_pythia8
4305+ #===============================================================================
4306+ @staticmethod
4307+ def generate_example_file_pythia8(path,
4308+ model_path,
4309+ process_names,
4310+ exporter,
4311+ main_file_name = "",
4312+ example_dir = "examples",
4313+ version="8.2"):
4314+ """Generate the main_model_name.cc file and Makefile in the examples dir"""
4315+
4316+ filepath = os.path.join(path, example_dir)
4317+ if not os.path.isdir(filepath):
4318+ os.makedirs(filepath)
4319+
4320+ replace_dict = {}
4321+
4322+ # Extract version number and date from VERSION file
4323+ info_lines = get_mg5_info_lines()
4324+ replace_dict['info_lines'] = info_lines
4325+
4326+ # Extract model name
4327+ replace_dict['model_name'] = exporter.model_name
4328+
4329+ # Extract include line
4330+ replace_dict['include_lines'] = \
4331+ "\n".join(["#include \"%s.h\"" % proc_name \
4332+ for proc_name in process_names])
4333+
4334+ # Extract setSigmaPtr line
4335+ replace_dict['sigma_pointer_lines'] = \
4336+ "\n".join(["pythia.setSigmaPtr(new %s());" % proc_name \
4337+ for proc_name in process_names])
4338+
4339+ # Extract param_card path
4340+ replace_dict['param_card'] = os.path.join(os.path.pardir,model_path,
4341+ "param_card_%s.dat" % \
4342+ exporter.model_name)
4343+
4344+ # Create the example main file
4345+ if version =="8.2":
4346+ template_path = 'pythia8.2_main_example_cc.inc'
4347+ makefile_path = 'pythia8.2_main_makefile.inc'
4348+ replace_dict['include_prefix'] = 'Pythia8/'
4349+ else:
4350+ template_path = 'pythia8_main_example_cc.inc'
4351+ makefile_path = 'pythia8_main_makefile.inc'
4352+ replace_dict['include_prefix'] = ''
4353+
4354+
4355+ file = ProcessExporterPythia8.read_template_file(template_path) % \
4356+ replace_dict
4357+
4358+ if not main_file_name:
4359+ num = 1
4360+ while os.path.exists(os.path.join(filepath,
4361+ 'main_%s_%i.cc' % (exporter.model_name, num))) or \
4362+ os.path.exists(os.path.join(filepath,
4363+ 'main_%s_%i' % (exporter.model_name, num))):
4364+ num += 1
4365+ main_file_name = str(num)
4366+
4367+ main_file = 'main_%s_%s' % (exporter.model_name,
4368+ main_file_name)
4369+
4370+ main_filename = os.path.join(filepath, main_file + '.cc')
4371+
4372+ # Write the file
4373+ writers.CPPWriter(main_filename).writelines(file)
4374+
4375+ replace_dict = {}
4376+
4377+ # Extract version number and date from VERSION file
4378+ replace_dict['info_lines'] = get_mg5_info_lines()
4379+
4380+ replace_dict['main_file'] = main_file
4381+
4382+ replace_dict['process_dir'] = model_path
4383+
4384+ replace_dict['include_dir'] = exporter.include_dir
4385+
4386+ # Create the makefile
4387+ file = ProcessExporterPythia8.read_template_file(makefile_path) % replace_dict
4388+
4389+ make_filename = os.path.join(filepath, 'Makefile_%s_%s' % \
4390+ (exporter.model_name, main_file_name))
4391+
4392+ # Write the file
4393+ open(make_filename, 'w').write(file)
4394+
4395+ logger.info("Created files %s and %s in directory %s" \
4396+ % (os.path.split(main_filename)[-1],
4397+ os.path.split(make_filename)[-1],
4398+ os.path.split(make_filename)[0]))
4399+ return main_file, make_filename
4400+
4401+ def convert_model(self,*args,**opts):
4402+ pass
4403+ def finalize(self, *args, **opts):
4404+ pass
4405+
4406 def get_mg5_info_lines():
4407 """Return info lines for MG5, suitable to place at beginning of
4408 Fortran files"""
4409@@ -1753,21 +1927,6 @@
4410 return res_str + '*'
4411
4412 #===============================================================================
4413-# Routines to export/output UFO models in C++ format
4414-#===============================================================================
4415-
4416-def convert_model_to_cpp(model, output_dir, wanted_lorentz = [],
4417- wanted_couplings = []):
4418- """Create a full valid Pythia 8 model from an MG5 model (coming from UFO)"""
4419-
4420- # create the model parameter files
4421- model_builder = UFOModelConverterCPP(model,
4422- os.path.join(output_dir, 'src'),
4423- wanted_lorentz,
4424- wanted_couplings)
4425- model_builder.write_files()
4426-
4427-#===============================================================================
4428 # UFOModelConverterCPP
4429 #===============================================================================
4430
4431@@ -1998,9 +2157,9 @@
4432 replace_dict['include_prefix'] = ''
4433
4434
4435- file_h = read_template_file(self.param_template_h) % \
4436+ file_h = self.read_template_file(self.param_template_h) % \
4437 replace_dict
4438- file_cc = read_template_file(self.param_template_cc) % \
4439+ file_cc = self.read_template_file(self.param_template_cc) % \
4440 replace_dict
4441
4442 return file_h, file_cc
4443@@ -2109,8 +2268,8 @@
4444 replace_dict['function_declarations'] = '\n'.join(template_h_files)
4445 replace_dict['function_definitions'] = '\n'.join(template_cc_files)
4446
4447- file_h = read_template_file(self.aloha_template_h) % replace_dict
4448- file_cc = read_template_file(self.aloha_template_cc) % replace_dict
4449+ file_h = self.read_template_file(self.aloha_template_h) % replace_dict
4450+ file_cc = self.read_template_file(self.aloha_template_cc) % replace_dict
4451
4452 # Write the files
4453 writers.CPPWriter(model_h_file).writelines(file_h)
4454@@ -2173,105 +2332,14 @@
4455
4456 return line
4457
4458-#===============================================================================
4459-# generate_example_file_pythia8
4460-#===============================================================================
4461-def generate_example_file_pythia8(path,
4462- model_path,
4463- process_names,
4464- exporter,
4465- main_file_name = "",
4466- example_dir = "examples",
4467- version="8.2"):
4468- """Generate the main_model_name.cc file and Makefile in the examples dir"""
4469-
4470- filepath = os.path.join(path, example_dir)
4471- if not os.path.isdir(filepath):
4472- os.makedirs(filepath)
4473-
4474- replace_dict = {}
4475-
4476- # Extract version number and date from VERSION file
4477- info_lines = get_mg5_info_lines()
4478- replace_dict['info_lines'] = info_lines
4479-
4480- # Extract model name
4481- replace_dict['model_name'] = exporter.model_name
4482-
4483- # Extract include line
4484- replace_dict['include_lines'] = \
4485- "\n".join(["#include \"%s.h\"" % proc_name \
4486- for proc_name in process_names])
4487-
4488- # Extract setSigmaPtr line
4489- replace_dict['sigma_pointer_lines'] = \
4490- "\n".join(["pythia.setSigmaPtr(new %s());" % proc_name \
4491- for proc_name in process_names])
4492-
4493- # Extract param_card path
4494- replace_dict['param_card'] = os.path.join(os.path.pardir,model_path,
4495- "param_card_%s.dat" % \
4496- exporter.model_name)
4497-
4498- # Create the example main file
4499- if version =="8.2":
4500- template_path = 'pythia8.2_main_example_cc.inc'
4501- makefile_path = 'pythia8.2_main_makefile.inc'
4502- replace_dict['include_prefix'] = 'Pythia8/'
4503- else:
4504- template_path = 'pythia8_main_example_cc.inc'
4505- makefile_path = 'pythia8_main_makefile.inc'
4506- replace_dict['include_prefix'] = ''
4507-
4508-
4509- file = read_template_file(template_path) % \
4510- replace_dict
4511-
4512- if not main_file_name:
4513- num = 1
4514- while os.path.exists(os.path.join(filepath,
4515- 'main_%s_%i.cc' % (exporter.model_name, num))) or \
4516- os.path.exists(os.path.join(filepath,
4517- 'main_%s_%i' % (exporter.model_name, num))):
4518- num += 1
4519- main_file_name = str(num)
4520-
4521- main_file = 'main_%s_%s' % (exporter.model_name,
4522- main_file_name)
4523-
4524- main_filename = os.path.join(filepath, main_file + '.cc')
4525-
4526- # Write the file
4527- writers.CPPWriter(main_filename).writelines(file)
4528-
4529- replace_dict = {}
4530-
4531- # Extract version number and date from VERSION file
4532- replace_dict['info_lines'] = get_mg5_info_lines()
4533-
4534- replace_dict['main_file'] = main_file
4535-
4536- replace_dict['process_dir'] = model_path
4537-
4538- replace_dict['include_dir'] = exporter.include_dir
4539-
4540- # Create the makefile
4541- file = read_template_file(makefile_path) % replace_dict
4542-
4543- make_filename = os.path.join(filepath, 'Makefile_%s_%s' % \
4544- (exporter.model_name, main_file_name))
4545-
4546- # Write the file
4547- open(make_filename, 'w').write(file)
4548-
4549- logger.info("Created files %s and %s in directory %s" \
4550- % (os.path.split(main_filename)[-1],
4551- os.path.split(make_filename)[-1],
4552- os.path.split(make_filename)[0]))
4553- return main_file, make_filename
4554-
4555-
4556-
4557+ #===============================================================================
4558+ # Global helper methods
4559+ #===============================================================================
4560+ @classmethod
4561+ def read_template_file(cls, filename, classpath=False):
4562+ """Open a template file and return the contents."""
4563+
4564+ return OneProcessExporterCPP.read_template_file(filename, classpath)
4565
4566
4567 #===============================================================================
4568@@ -2286,8 +2354,8 @@
4569 namespace = 'Pythia8'
4570
4571 # Dictionaries for expression of MG5 SM parameters into Pythia 8
4572- slha_to_expr = {('SMINPUTS', (1,)): '1./csm->alphaEM(pow(pd->m0(23),2))',
4573- ('SMINPUTS', (2,)): 'M_PI*csm->alphaEM(pow(pd->m0(23),2))*pow(pd->m0(23),2)/(sqrt(2.)*pow(pd->m0(24),2)*(pow(pd->m0(23),2)-pow(pd->m0(24),2)))',
4574+ slha_to_expr = {('SMINPUTS', (1,)): '1./csm->alphaEM(((pd->m0(23))*(pd->m0(23))))',
4575+ ('SMINPUTS', (2,)): 'M_PI*csm->alphaEM(((pd->m0(23))*(pd->m0(23))))*((pd->m0(23))*(pd->m0(23)))/(sqrt(2.)*((pd->m0(24))*(pd->m0(24)))*(((pd->m0(23))*(pd->m0(23)))-((pd->m0(24))*(pd->m0(24)))))',
4576 ('SMINPUTS', (3,)): 'alpS',
4577 ('CKMBLOCK', (1,)): 'csm->VCKMgen(1,2)',
4578 }
4579@@ -2295,6 +2363,7 @@
4580 # Template files to use
4581 param_template_h = 'pythia8_model_parameters_h.inc'
4582 param_template_cc = 'pythia8_model_parameters_cc.inc'
4583+ template_paths = os.path.join(_file_path, 'iolibs', 'template_files', 'pythia8')
4584
4585 def prepare_parameters(self):
4586 """Extract the model parameters from Pythia 8, and store them in
4587@@ -2412,7 +2481,7 @@
4588 path = 'pythia8.2_makefile.inc'
4589 else:
4590 path = 'pythia8_makefile.inc'
4591- makefile = read_template_file(path) % replace_dict
4592+ makefile = self.read_template_file(path) % replace_dict
4593
4594 # Write the files
4595 open(makefilename, 'w').write(makefile)
4596@@ -2433,3 +2502,32 @@
4597 logger.info("Created %s in directory %s" \
4598 % (os.path.split(paramcardname)[-1],
4599 os.path.split(paramcardname)[0]))
4600+
4601+ #===============================================================================
4602+ # Global helper methods
4603+ #===============================================================================
4604+ @classmethod
4605+ def read_template_file(cls, *args, **opts):
4606+ """Open a template file and return the contents."""
4607+
4608+ return OneProcessExporterPythia8.read_template_file(*args, **opts)
4609+
4610+def ExportCPPFactory(cmd, group_subprocesses=False):
4611+ """ Determine which Export class is required. cmd is the command
4612+ interface containing all potential usefull information.
4613+ """
4614+
4615+ opt = cmd.options
4616+ cformat = cmd._export_format
4617+
4618+ if cformat == 'pythia8':
4619+ return ProcessExporterPythia8(cmd._export_dir, opt)
4620+ elif cformat == 'standalone_cpp':
4621+ return ProcessExporterCPP(cmd._export_dir, opt)
4622+ elif cformat == 'matchbox_cpp':
4623+ return ProcessExporterMatchbox(cmd._export_dir, opt)
4624+ elif cformat == 'plugin':
4625+ return cmd._export_plugin(cmd._export_dir, opt)
4626+
4627+
4628+
4629
4630=== modified file 'madgraph/iolibs/export_fks.py'
4631--- madgraph/iolibs/export_fks.py 2016-06-24 01:32:34 +0000
4632+++ madgraph/iolibs/export_fks.py 2016-08-18 22:31:39 +0000
4633@@ -285,10 +285,10 @@
4634 cp(pjoin(_file_path,cp_file),
4635 pjoin(self.dir_path,'bin','internal',os.path.basename(cp_file)))
4636
4637- def convert_model_to_mg4(self, model, wanted_lorentz = [],
4638+ def convert_model(self, model, wanted_lorentz = [],
4639 wanted_couplings = []):
4640
4641- super(ProcessExporterFortranFKS,self).convert_model_to_mg4(model,
4642+ super(ProcessExporterFortranFKS,self).convert_model(model,
4643 wanted_lorentz, wanted_couplings)
4644
4645 IGNORE_PATTERNS = ('*.pyc','*.dat','*.py~')
4646@@ -705,12 +705,39 @@
4647 run_card.write(pjoin(self.dir_path, 'Cards', 'run_card.dat'))
4648
4649
4650- def finalize_fks_directory(self, matrix_elements, history, makejpg = False,
4651- online = False,
4652- compiler_dict={'fortran': 'gfortran', 'cpp': 'g++'},
4653- output_dependencies = 'external', MG5DIR = None):
4654+
4655+ def finalize(self, matrix_elements, history, mg5options, flaglist):
4656 """Finalize FKS directory by creating jpeg diagrams, html
4657 pages,proc_card_mg5.dat and madevent.tar.gz."""
4658+
4659+ devnull = os.open(os.devnull, os.O_RDWR)
4660+ try:
4661+ res = misc.call([self.options['lhapdf'], '--version'], \
4662+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
4663+ except Exception:
4664+ res = 1
4665+ if res != 0:
4666+ logger.info('The value for lhapdf in the current configuration does not ' + \
4667+ 'correspond to a valid executable.\nPlease set it correctly either in ' + \
4668+ 'input/mg5_configuration or with "set lhapdf /path/to/lhapdf-config" ' + \
4669+ 'and regenrate the process. \nTo avoid regeneration, edit the ' + \
4670+ ('%s/Cards/amcatnlo_configuration.txt file.\n' % self.dir_path ) + \
4671+ 'Note that you can still compile and run aMC@NLO with the built-in PDFs\n')
4672+
4673+ compiler_dict = {'fortran': mg5options['fortran_compiler'],
4674+ 'cpp': mg5options['cpp_compiler'],
4675+ 'f2py': mg5options['f2py_compiler']}
4676+
4677+ if 'nojpeg' in flaglist:
4678+ makejpg = False
4679+ else:
4680+ makejpg = True
4681+ if 'online' in flaglist:
4682+ online = True
4683+ else:
4684+ online = False
4685+ output_dependencies = mg5options['output_dependencies']
4686+
4687
4688 self.proc_characteristic['grouped_matrix'] = False
4689 self.create_proc_charac()
4690@@ -3033,6 +3060,11 @@
4691 """Class to take care of exporting a set of matrix elements to
4692 Fortran (v4) format."""
4693
4694+
4695+ def finalize(self, *args, **opts):
4696+ ProcessExporterFortranFKS.finalize(self, *args, **opts)
4697+ #export_v4.ProcessExporterFortranSA.finalize(self, *args, **opts)
4698+
4699 #===============================================================================
4700 # copy the Template in a new directory.
4701 #===============================================================================
4702
4703=== modified file 'madgraph/iolibs/export_v4.py'
4704--- madgraph/iolibs/export_v4.py 2016-08-14 00:17:23 +0000
4705+++ madgraph/iolibs/export_v4.py 2016-08-18 22:31:39 +0000
4706@@ -68,10 +68,71 @@
4707 'f2py': 'f2py',
4708 'cpp':'g++'}
4709
4710+
4711+class VirtualExporter(object):
4712+
4713+ #exporter variable who modified the way madgraph interacts with this class
4714+
4715+ grouped_mode = 'madevent'
4716+ # This variable changes the type of object called within 'generate_subprocess_directory'
4717+ #functions.
4718+ # False to avoid grouping (only identical matrix element are merged)
4719+ # 'madevent' group the massless quark and massless lepton
4720+ # 'madweight' group the gluon with the massless quark
4721+ sa_symmetry = False
4722+ # If no grouped_mode=False, uu~ and u~u will be called independently.
4723+ #Putting sa_symmetry generates only one of the two matrix-element.
4724+ check = True
4725+ # Ask madgraph to check if the directory already exists and propose to the user to
4726+ #remove it first if this is the case
4727+ output = 'Template'
4728+ # [Template, None, dir]
4729+ # - Template, madgraph will call copy_template
4730+ # - dir, madgraph will just create an empty directory for initialisation
4731+ # - None, madgraph do nothing for initialisation
4732+ exporter = 'v4'
4733+ # language of the output 'v4' for Fortran output
4734+ # 'cpp' for C++ output
4735+
4736+
4737+ def __init__(self, dir_path = "", opt=None):
4738+ return
4739+
4740+ def copy_template(self, model):
4741+ return
4742+
4743+ def generate_subprocess_directory(self, subproc_group, helicity_model, me=None):
4744+ # generate_subprocess_directory(self, matrix_element, helicity_model, me_number) [for ungrouped]
4745+ return 0 # return an integer stating the number of call to helicity routine
4746+
4747+ def convert_model(self, model, wanted_lorentz=[], wanted_couplings=[]):
4748+ return
4749+
4750+ def finalize(self,matrix_element, cmdhistory, MG5options, outputflag):
4751+ return
4752+
4753+
4754+ def pass_information_from_cmd(self, cmd):
4755+ """pass information from the command interface to the exporter.
4756+ Please do not modify any object of the interface from the exporter.
4757+ """
4758+ return
4759+
4760+ def modify_grouping(self, matrix_element):
4761+ return False, matrix_element
4762+
4763+ def export_model_files(self, model_v4_path):
4764+ raise Exception, "V4 model not supported by this type of exporter. Please use UFO model"
4765+ return
4766+
4767+ def export_helas(self, HELAS_PATH):
4768+ raise Exception, "V4 model not supported by this type of exporter. Please use UFO model"
4769+ return
4770+
4771 #===============================================================================
4772 # ProcessExporterFortran
4773 #===============================================================================
4774-class ProcessExporterFortran(object):
4775+class ProcessExporterFortran(VirtualExporter):
4776 """Class to take care of exporting a set of matrix elements to
4777 Fortran (v4) format."""
4778
4779@@ -79,10 +140,11 @@
4780 'export_format':'madevent', 'mp': False,
4781 'v5_model': True
4782 }
4783+ grouped_mode = False
4784
4785- def __init__(self, mgme_dir = "", dir_path = "", opt=None):
4786+ def __init__(self, dir_path = "", opt=None):
4787 """Initiate the ProcessExporterFortran with directory information"""
4788- self.mgme_dir = mgme_dir
4789+ self.mgme_dir = MG5DIR
4790 self.dir_path = dir_path
4791 self.model = None
4792
4793@@ -102,35 +164,29 @@
4794
4795 calls = 0
4796 if isinstance(matrix_elements, group_subprocs.SubProcessGroupList):
4797- unique_id=1
4798 for (group_number, me_group) in enumerate(matrix_elements):
4799- calls = calls + self.generate_subprocess_directory_v4(\
4800- me_group, fortran_model, group_number, unique_id=unique_id)
4801- unique_id += len(me_group.get('matrix_elements'))
4802+ calls = calls + self.generate_subprocess_directory(\
4803+ me_group, fortran_model, group_number)
4804 else:
4805 for me_number, me in enumerate(matrix_elements.get_matrix_elements()):
4806- calls = calls + self.generate_subprocess_directory_v4(\
4807+ calls = calls + self.generate_subprocess_directory(\
4808 me, fortran_model, me_number)
4809
4810 return calls
4811
4812- #===========================================================================
4813- # Generate an include file with global quantities about all ME's output.
4814- #===========================================================================
4815- def write_global_specs(self, matrix_elements):
4816- """ Writes the file global_specs.inc which contains general information
4817- about *all* the ME's output in this directory."""
4818-
4819- # Do nothing here, but daughter classes such as LoopOptimizedExporterFortran
4820- # overwrites this.
4821- pass
4822
4823 #===========================================================================
4824 # create the run_card
4825 #===========================================================================
4826 def create_run_card(self, matrix_elements, history):
4827 """ """
4828-
4829+
4830+
4831+ # bypass this for the loop-check
4832+ import madgraph.loop.loop_helas_objects as loop_helas_objects
4833+ if isinstance(matrix_elements, loop_helas_objects.LoopHelasMatrixElement):
4834+ matrix_elements = None
4835+
4836 run_card = banner_mod.RunCard()
4837
4838
4839@@ -157,7 +213,7 @@
4840 #===========================================================================
4841 # copy the Template in a new directory.
4842 #===========================================================================
4843- def copy_v4template(self, modelname):
4844+ def copy_template(self, model):
4845 """create the directory run_name as a copy of the MadEvent
4846 Template, and clean the directory
4847 """
4848@@ -284,27 +340,30 @@
4849 process_str = ' '.join(new_process_content)
4850
4851 #format the SubProcess
4852- process_text += process_template.substitute({'process': process_str, \
4853- 'coupling': coupling})
4854-
4855- text = proc_card_template.substitute({'process': process_text,
4856+ replace_dict = {'process': process_str,
4857+ 'coupling': coupling}
4858+ process_text += process_template.substitute(replace_dict)
4859+
4860+ replace_dict = {'process': process_text,
4861 'model': modelname,
4862- 'multiparticle':''})
4863- ff = open(file_pos, 'w')
4864- ff.write(text)
4865- ff.close()
4866-
4867+ 'multiparticle':''}
4868+ text = proc_card_template.substitute(replace_dict)
4869+
4870+ if file_pos:
4871+ ff = open(file_pos, 'w')
4872+ ff.write(text)
4873+ ff.close()
4874+ else:
4875+ return replace_dict
4876+
4877 #===========================================================================
4878 # Create jpeg diagrams, html pages,proc_card_mg5.dat and madevent.tar.gz
4879 #===========================================================================
4880- def finalize_v4_directory(self, matrix_elements, history = "", makejpg = False,
4881- online = False, compiler=default_compiler):
4882- """Function to finalize v4 directory, for inheritance.
4883- """
4884-
4885- self.create_run_card(matrix_elements, history)
4886-
4887- pass
4888+ def finalize(self, matrix_elements, history='', mg5options={}, flaglist=[]):
4889+ """Function to finalize v4 directory, for inheritance."""
4890+
4891+ self.create_run_card(matrix_elements, history)
4892+
4893
4894 #===========================================================================
4895 # Create the proc_characteristic file passing information to the run_interface
4896@@ -471,9 +530,9 @@
4897 #
4898
4899 #===========================================================================
4900- # generate_subprocess_directory_v4
4901+ # generate_subprocess_directory
4902 #===========================================================================
4903- def generate_subprocess_directory_v4(self, matrix_element,
4904+ def generate_subprocess_directory(self, matrix_element,
4905 fortran_model,
4906 me_number):
4907 """Routine to generate a subprocess directory (for inheritance)"""
4908@@ -531,9 +590,11 @@
4909 parameter (nincoming_prod=%(ninitial)d)""" % replace_dict
4910
4911 # Write the file
4912- writer.writelines(file)
4913-
4914- return True
4915+ if writer:
4916+ writer.writelines(file)
4917+ return True
4918+ else:
4919+ return replace_dict
4920
4921 #===========================================================================
4922 # write_helamp_madspin
4923@@ -552,9 +613,12 @@
4924 common /to_helamp/helamp """ % replace_dict
4925
4926 # Write the file
4927- writer.writelines(file)
4928+ if writer:
4929+ writer.writelines(file)
4930+ return True
4931+ else:
4932+ return replace_dict
4933
4934- return True
4935
4936
4937 #===========================================================================
4938@@ -575,10 +639,11 @@
4939 parameter (nincoming=%(ninitial)d)""" % replace_dict
4940
4941 # Write the file
4942- writer.writelines(file)
4943-
4944- return True
4945-
4946+ if writer:
4947+ writer.writelines(file)
4948+ return True
4949+ else:
4950+ return replace_dict
4951 #===========================================================================
4952 # write_pmass_file
4953 #===========================================================================
4954@@ -701,62 +766,12 @@
4955
4956 return True
4957
4958- #===========================================================================
4959- # write_props_file
4960- #===========================================================================
4961- def write_props_file(self, writer, matrix_element, s_and_t_channels):
4962- """Write the props.inc file for MadEvent. Needs input from
4963- write_configs_file."""
4964-
4965- lines = []
4966-
4967- particle_dict = matrix_element.get('processes')[0].get('model').\
4968- get('particle_dict')
4969-
4970- for iconf, configs in enumerate(s_and_t_channels):
4971- for vertex in configs[0] + configs[1][:-1]:
4972- leg = vertex.get('legs')[-1]
4973- if leg.get('id') not in particle_dict:
4974- # Fake propagator used in multiparticle vertices
4975- mass = 'zero'
4976- width = 'zero'
4977- pow_part = 0
4978- else:
4979- particle = particle_dict[leg.get('id')]
4980- # Get mass
4981- if particle.get('mass').lower() == 'zero':
4982- mass = particle.get('mass')
4983- else:
4984- mass = "abs(%s)" % particle.get('mass')
4985- # Get width
4986- if particle.get('width').lower() == 'zero':
4987- width = particle.get('width')
4988- else:
4989- width = "abs(%s)" % particle.get('width')
4990-
4991- pow_part = 1 + int(particle.is_boson())
4992-
4993- lines.append("prmass(%d,%d) = %s" % \
4994- (leg.get('number'), iconf + 1, mass))
4995- lines.append("prwidth(%d,%d) = %s" % \
4996- (leg.get('number'), iconf + 1, width))
4997- lines.append("pow(%d,%d) = %d" % \
4998- (leg.get('number'), iconf + 1, pow_part))
4999-
5000- # Write the file
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches