Multithreading with standalone_cpp output

Asked by Rob Verheyen

Dear Madgraph team,

I'm trying to use the standalone c++ output in a multithreaded program, but I'm running into issues. I managed to condense the problem down to some code that's very similar to the check_sa.cc that comes with the c++ output (compiled with -std=c++11):

#include <iostream>
#include <iomanip>
#include <thread>

#include "CPPProcess.h"
#include "rambo.h"

struct MEC
{
  MEC(){process.initProc("../../Cards/param_card.dat");}

  void run()
  {
    double energy = 1500;
    double weight;

    for (int i=0; i<3; i++)
    {
      // Get phase space point
      vector<double*> p = get_momenta(process.ninitial, energy,
             process.getMasses(), weight);

      // Set momenta for this event
      process.setMomenta(p);

      // Evaluate matrix element
      process.sigmaKin();
      cout << process.getMatrixElements()[0] << endl;
    }
  }

  CPPProcess process;
};

int main()
{
  thread t1(&MEC::run, MEC());
  thread t2(&MEC::run, MEC());
  t1.join();
  t2.join();
}

The code is supposed to generate 3 sets of rambo momenta and calculate the matrix element. However, the output is
0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00

If I remove one of the threads, the output is something like
3.624505e-15
2.599132e-13
2.264434e-14

as I would expect. I'm hoping anyone knows what's going on here, since as far as I know, this is how you're supposed to multithread this kind of c++ code.

Thanks,
Rob Verheyen

Question information

Language:
English Edit question
Status:
Answered
For:
MadGraph5_aMC@NLO Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
Olivier Mattelaer (olivier-mattelaer) said :
#1

Hi,

I have simply no idea on this....

Cheers,

Olivier

Revision history for this message
Rob Verheyen (robverheyen) said :
#2

Hey Olivier,

I guess that makes two of us :) Do you happen to have any idea if there's anyone I could ask about this?

Cheers

Revision history for this message
Valentin Hirschi (valentin-hirschi) said :
#3

The defaultMG5aMC C++ standalone tree matrix element output uses a "global" static pointer to store the model instance.
This is a rather bad programming style that is, among other problems, not thread-safe and I suspect that this could be the origin of the issue you are facing. This is however just a wild guess, so it could have nothing to do with this.

I have a private MG5aMC plugin for a more advanced and thread-safe C++ output for tree-level matrix elements that could play nicer for your application. Contact me by email directly (<email address hidden>) if you want to discuss more about that.

Revision history for this message
Valentin Hirschi (valentin-hirschi) said :
#4

Rob confirmed that the C++ output from my (still) private MG5aMC plugin is indeed thread-safe and could be used for his purpose (contact me if someone else needs it).
The thread-unsafety of the default C++ output is probably related to the global Model static pointer and the RAMBO C++ implementation (for which Rob has written an alternative implementation himself, again available upon request).

Revision history for this message
Rob Verheyen (robverheyen) said :
#5

For anyone that happens to encounter the same issue as I did, it turns out you can pretty easily modify the regular code to be thread-safe by doing the following:

- Remove every instance of the keyword 'static' from the CPPProcess.cc file
- Remove the static pointer functionality from the Parameter_sm class and change it in such a way that every instance of the CPPProcess object just has a copy of the Paramter_sm class.

Revision history for this message
Rob Verheyen (robverheyen) said :
#6

Actually only the first step is necessary as long as the CPPProcess objects are not created simultaneously. The singleton pattern design of the Parameter_sm class is thread-safe as long as the instance cannot be created by multiple threads.

Revision history for this message
Valentin Hirschi (valentin-hirschi) said :
#7

So in the end I decided to just publicly release the plugin I built for curated C++ matrix element outputs ( as I never wound up writing a short reference publication for this work).

It can be downloaded at:

lp:~py8team/+junk/PY8Kernels_plugin

And can be used as follows:

```
a) copy the plugin you obtained from the launchpad branch "as a" (and not "in a") folder named `PY8Kernels` in the "PLUGIN' directory of a v2.x version of MadGraph.
b) then:

./bin/mg5_aMC --mode=PY8Kernels
PY8Kernels > add process p p > d d~ j QED<=0
PY8Kernels > add process p p > z > d d~ QED<=2
PY8Kernels > output PY8MEs tmp_test
PY8Kernels > exit

cd tmp_test/Processes_sm/
make check
./check
```

yielding:

```
Opened slha file param_card_sm.dat for reading
sm model parameters independent of event kinematics:
mdl_WH = 0.006382339
mdl_WW = 2.0476
[...]
Testing the non-existence of a non-available process:
 -> Process '33 43 > 2 5 > 33 2 1 5' is not available.

Testing the evaluation of available processes:
 -> Process '21 21 > 1 -1 21' is available.
 | Momenta:
 | 1 7.50000000000000e+02 0.00000000000000e+00 0.00000000000000e+00 7.50000000000000e+02
 | 2 7.50000000000000e+02 0.00000000000000e+00 0.00000000000000e+00 -7.50000000000000e+02
 | 3 6.87868181828160e+02 2.54179830464520e+02 5.69480493117298e+02 -2.90253711975379e+02
 | 4 5.46099931105227e+02 -2.74948039397878e+01 -5.21556451979051e+02 1.59524411638062e+02
 | 5 2.66031887066613e+02 -2.26685026524732e+02 -4.79240411382473e+01 1.30729300337317e+02
 | Matrix element : 1.86539034007620204e-04 GeV^-2
[...]
 -> Process '3 -3 > 23 > 1 -1' is available.
 | Momenta:
 | 1 7.50000000000000e+02 0.00000000000000e+00 0.00000000000000e+00 7.50000000000000e+02
 | 2 7.50000000000000e+02 0.00000000000000e+00 0.00000000000000e+00 -7.50000000000000e+02
 | 3 7.50000000000015e+02 6.13712352994589e+02 -3.72213384149096e+02 2.17518607117062e+02
 | 4 7.49999999999997e+02 -6.13712352994571e+02 3.72213384149107e+02 -2.17518607117045e+02
 | Matrix element : 4.23176199133015046e-03 GeV^0
```

For now, the example driver file `check_sa.cpp` together with the function prototypes of the C++ headers should already help understand how the generated library `../lib/libPY8MEs_sm.a` is organised and intended to be linked+used.

In particular, I made it very easy to access a particular process simply by supplying the list of incoming and outgoing PDGs, and there is also facilities for easily accessing color-ordered Matrix elements and for specific helicities.
It can basically function as an API for accessing any ME.

I hope this can be of help to many projects relying on an easy to link library of many tree-level matrix elements.

Can you help with this problem?

Provide an answer of your own, or ask Rob Verheyen for more information if necessary.

To post a message you must log in.