cepgen is hosted by Hepforge, IPPP Durham
CepGen 1.2.5
Central exclusive processes event generator
Loading...
Searching...
No Matches
MadGraphInterface.cpp
Go to the documentation of this file.
1/*
2 * CepGen: a central exclusive processes event generator
3 * Copyright (C) 2020-2024 Laurent Forthomme
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef MADGRAPH_BIN
20#error "*** MADGRAPH_BIN variable not set! ***"
21#endif
22#ifndef MADGRAPH_PROC_TMPL
23#error "*** MADGRAPH_PROC_TMPL variable not set! ***"
24#endif
25#ifndef CC_CFLAGS
26#error "*** CC_CFLAGS variable not set! ***"
27#endif
28
29#include <array>
30#include <fstream>
31
33#include "CepGen/Physics/PDG.h"
34#include "CepGen/Utils/Caller.h"
35#include "CepGen/Utils/String.h"
40
41namespace cepgen {
42 std::unordered_map<std::string, spdgid_t> MadGraphInterface::mg5_parts_ = {
43 {"d", 1}, {"d~", -1}, {"u", 2}, {"u~", -2}, {"s", 3}, {"s~", -3}, {"c", 4}, {"c~", -4},
44 {"b", 5}, {"b~", -5}, {"t", 6}, {"t~", -6}, {"e+", -11}, {"e-", 11}, {"ve", 12}, {"ve~", -12},
45 {"mu+", -13}, {"mu-", 13}, {"vm", 14}, {"vm~", -14}, {"tau+", -15}, {"tau-", 15}, {"vt", 16}, {"vt~", -16},
46 {"g", 21}, {"a", 22}, {"z", 23}, {"w+", -24}, {"w-", 24}, {"h", 25},
47 };
48
50 : SteeredObject(params),
51 proc_(steer<std::string>("process")),
52 model_(steer<std::string>("model")),
53 tmp_dir_(steerAs<std::string, fs::path>("tmpDir")),
54 card_path_(steerAs<std::string, fs::path>("cardPath")),
55 log_filename_(steer<std::string>("logFile")),
56 standalone_cpp_path_(steerAs<std::string, fs::path>("standaloneCppPath")),
57 extra_particles_(steer<ParametersList>("extraParticles")),
58 model_parameters_(steer<ParametersList>("modelParameters")) {
59 if (proc_.empty() && standalone_cpp_path_.empty())
60 throw CG_FATAL("MadGraphInterface") << "Neither a 'process' keyword nor a path to a MadGraph process interface "
61 "already generated ('standaloneCppPath') was set to the parameters!\n"
62 << params;
63 std::ofstream log(log_filename_, std::ios::trunc); // clearing the log
64 parseExtraParticles();
65 }
66
67 void MadGraphInterface::parseExtraParticles() {
68 for (const auto& extra_part : extra_particles_.keysOf<ParticleProperties>()) {
69 if (mg5_parts_.count(extra_part) > 0)
70 throw CG_FATAL("MadGraphInterface")
71 << "Particle with name '" << extra_part << "' is already defined in internal LUT.";
72 const auto& extra_part_prop = extra_particles_.get<ParticleProperties>(extra_part);
73 // find the equivalent MadGraph particle to alias
74 std::string found_mg_equiv;
75 for (const auto& part : mg5_parts_)
76 if ((pdgid_t)std::labs(part.second) == extra_part_prop.pdgid)
77 found_mg_equiv = part.first;
78 if (found_mg_equiv.empty())
79 throw CG_FATAL("MadGraphInterface")
80 << "No equivalent for particle with PDG id=" << extra_part_prop.pdgid << " in MadGraph LUT.";
81 if (found_mg_equiv.at(found_mg_equiv.size() - 1) == '+' || found_mg_equiv.at(found_mg_equiv.size() - 1) == '-')
82 found_mg_equiv.pop_back();
83 if (!extra_part_prop.charges.empty()) {
84 extra_part_definitions_ += "\ndefine " + extra_part + "+ = " + found_mg_equiv + "+";
85 extra_part_definitions_ += "\ndefine " + extra_part + "- = " + found_mg_equiv + "-";
86 mg5_parts_[extra_part + "+"] = mg5_parts_.at(found_mg_equiv + "+");
87 mg5_parts_[extra_part + "-"] = mg5_parts_.at(found_mg_equiv + "-");
88 } else {
89 extra_part_definitions_ += "\ndefine " + extra_part + " = " + found_mg_equiv;
90 mg5_parts_[extra_part] = mg5_parts_.at(found_mg_equiv);
91 }
92 //FIXME add extra particles properties (masses, ...)
93 CG_DEBUG("MadGraphInterface") << "Defined '" << extra_part
94 << "' as MadGraph alias for CepGen particle with properties: " << extra_part_prop
95 << ".";
96 }
97 }
98
99 std::string MadGraphInterface::run() const {
100 std::ofstream log(log_filename_, std::ios::app); // appending at the end of the log
101
102 fs::path cpp_path, cg_proc;
103 if (!standalone_cpp_path_.empty()) {
104 CG_INFO("MadGraphInterface:run") << "Running on a process already generated by mg5_aMC: " << standalone_cpp_path_;
105 cpp_path = standalone_cpp_path_;
106 cg_proc = tmp_dir_ / "cepgen_proc_interface.cpp";
107 } else {
108 CG_INFO("MadGraphInterface:run") << "Running the mg5_aMC process generation.";
109 std::vector<std::string> cmds;
110 if (!model_.empty()) {
111 cmds.emplace_back("set auto_convert_model T");
112 cmds.emplace_back("import model " + model_);
113 }
114 cmds.emplace_back(extra_part_definitions_);
115 cmds.emplace_back("generate " + proc_);
116 cmds.emplace_back("output standalone_cpp " + tmp_dir_.string());
117 cpp_path = tmp_dir_;
118 const auto num_removed_files = fs::remove_all(cpp_path);
119 CG_DEBUG("MadGraphInterface:run") << "Removed " << utils::s("file", num_removed_files, true)
120 << " from process directory " << cpp_path << ".";
121
122 std::ofstream log(log_filename_, std::ios::app); // appending at the end of the log
123 log << "\n\n*** mg5_aMC process generation ***\n\n";
124 log << utils::merge(mg5amc::runCommand(cmds, card_path_, true), "\n");
125
126 CG_INFO("MadGraphInterface:run") << "Preparing the mg5_aMC process library.";
127 log << "\n\n*** mg5_aMC process library compilation ***\n\n";
128 cg_proc = prepareMadGraphProcess();
129 }
130
131#ifdef _WIN32
132 fs::path lib_path = "CepGenMadGraphProcess.dll";
133#else
134 fs::path lib_path = "libCepGenMadGraphProcess.so";
135#endif
136
137 generateLibrary(cg_proc, cpp_path, lib_path);
138 linkCards();
139 return lib_path;
140 }
141
142 void MadGraphInterface::linkCards() const {
143 for (const auto& f : fs::directory_iterator(tmp_dir_ / "Cards"))
144 if (f.path().extension() == ".dat") {
145 fs::path link_path = f.path().filename();
146 if (!fs::exists(link_path))
147 fs::create_symlink(f, link_path);
148 }
149 CG_DEBUG("MadGraphInterface:run") << "Created links in current directory for all cards in '" +
150 std::string(tmp_dir_ / "Cards") + "'.";
151 }
152
153 std::string MadGraphInterface::prepareMadGraphProcess() const {
154 //--- open template file
155 std::ifstream tmpl_file(MADGRAPH_PROC_TMPL);
156 std::string tmpl = std::string(std::istreambuf_iterator<char>(tmpl_file), std::istreambuf_iterator<char>());
157 std::ofstream log(log_filename_, std::ios::app); // appending at the end of the log
158 log << "\n\n*** mg5_aMC process library compilation ***\n\n";
159
160 const auto& parts = mg5amc::unpackProcessParticles(proc_);
161 std::vector<int> in_parts, out_parts;
162 for (const auto& in_part : parts.first) {
163 if (mg5_parts_.count(in_part) == 0) {
164 const auto pprops = mg5amc::describeParticle(in_part, model_);
165 mg5_parts_[in_part] = pprops.pdgid;
166 PDG::get().define(pprops);
167 }
168 in_parts.emplace_back(mg5_parts_.at(in_part));
169 }
170 for (const auto& out_part : parts.second) {
171 if (mg5_parts_.count(out_part) == 0) {
172 const auto pprops = mg5amc::describeParticle(out_part, model_);
173 mg5_parts_[out_part] = pprops.pdgid;
174 PDG::get().define(pprops);
175 }
176 out_parts.emplace_back(mg5_parts_.at(out_part));
177 }
178 CG_INFO("MadGraphInterface.prepareMadGraphProcess") << "Unpacked process particles: "
179 << "incoming=" << in_parts << ", "
180 << "outgoing=" << out_parts << ".";
181
182 const std::string process_description = proc_ + (!model_.empty() ? " (model: " + model_ + ")" : "");
183
184 std::string src_filename = tmp_dir_ / "cepgen_proc_interface.cpp";
185 std::ofstream src_file(src_filename);
186 src_file << utils::replaceAll(tmpl,
187 {{"XXX_PART1_XXX", std::to_string(in_parts[0])},
188 {"XXX_PART2_XXX", std::to_string(in_parts[1])},
189 {"XXX_OUT_PART_XXX", utils::merge(out_parts, ", ")},
190 {"XXX_PROC_NAME_XXX", mg5amc::normalise(proc_)},
191 {"XXX_PROC_DESCRIPTION_XXX", process_description}});
192 src_file.close();
193 return src_filename;
194 }
195
196 void MadGraphInterface::generateLibrary(const fs::path& proc_path,
197 const fs::path& in_path,
198 const fs::path& out_lib) const {
199 std::vector<std::string> src_files;
200 src_files.emplace_back(proc_path.string());
201
202 //--- find all processes registered
203 std::vector<std::string> processes;
204 try {
205 for (const auto& p : fs::directory_iterator(in_path / "SubProcesses"))
206 if (p.path().filename().string()[0] == 'P') {
207 processes.emplace_back(p.path());
208 for (const auto& f : fs::directory_iterator(p))
209 if (f.path().extension() == ".cc")
210 src_files.emplace_back(f.path());
211 }
212 } catch (const fs::filesystem_error& err) {
213 throw CG_FATAL("MadGraphInterface:generateLibrary")
214 << "Failed to retrieve all subprocesses in path " << in_path << "!\n"
215 << err.what();
216 }
217
218 CG_DEBUG("MadGraphInterface:generateLibrary") << "Subprocess list: " << processes << ".";
219
220 if (processes.size() != 1)
221 throw CG_FATAL("MadGraphInterface:generateLibrary") << "Currently only single-process cases are supported!";
222
223 //--- find all model source files
224 for (const auto& f : fs::directory_iterator(in_path / "src"))
225 if (f.path().extension() == ".cc")
226 src_files.emplace_back(f.path());
227
228#ifdef _WIN32
229 throw CG_FATAL("MadGraphInterface:generateLibrary")
230 << "Library generation not yet implemented for Window$ systems!";
231#else
232 {
233 utils::Caller caller;
234 caller.call({CC_CFLAGS,
235 "-fPIC",
236 "-shared",
237 "-Wno-unused-variable",
238 "-Wno-int-in-bool-context",
239 "-I" + (in_path / "src").string(),
240 "-I" + processes.at(0),
241 utils::merge(src_files, " "),
242 "-o " + out_lib.string()});
243 }
244#endif
245 }
246
248 ParametersDescription output, block_params, decay_params("DECAY");
249 std::string block_name;
250 for (const auto& buf : utils::split(card_content, '\n', true)) {
251 if (buf[0] == '#')
252 continue;
253 const auto ln = utils::split(buf, '#', true); // info, comments
254 const auto vars = utils::split(ln.at(0), ' ', true);
255 if (utils::toLower(vars.at(0)) == "block") {
256 if (!block_params.empty())
257 output.add(block_name, block_params);
258 block_name = vars.at(1);
259 block_params = ParametersDescription(block_name);
260 if (ln.size() > 1)
261 block_params.setDescription(ln.at(1));
262 continue;
263 } else if (vars.size() == 3 && vars.at(0) == "DECAY") {
264 if (!block_params.empty())
265 output.add(block_name, block_params);
266 auto& par = decay_params.add<double>(vars.at(1), std::stod(vars.at(2)));
267 if (ln.size() > 1)
268 par.setDescription(ln.at(1));
269 continue;
270 }
271 if (vars.size() == 2) {
272 auto& par = block_params.add<double>(vars.at(0), std::stod(vars.at(1)));
273 if (ln.size() > 1)
274 par.setDescription(ln.at(1));
275 } else
276 throw CG_ERROR("MadGraphInterface:extractParamCardParameters")
277 << "Failed to unpack parameters line:\n\t" << buf;
278 }
279 if (!block_params.empty())
280 output.add(block_name, block_params);
281 output.add("DECAY", decay_params);
282 return output;
283 }
284
286 std::ostringstream output;
287 for (const auto& key : params.parameters().keysOf<ParametersList>()) {
288 const auto& block_params = params.parameters().get<ParametersList>(key);
289 if (key == "DECAY")
290 for (const auto& key2 : block_params.keys())
291 output << utils::format("\n%5s %3s %.6e # ", key.data(), key2.data(), block_params.get<double>(key2))
292 << params.get(key).get(key2).description();
293 else {
294 output << "\nBlock " << key;
295 for (const auto& key2 : block_params.keys())
296 output << utils::format("\n%5s %.6e # ", key2.data(), block_params.get<double>(key2))
297 << params.get(key).get(key2).description();
298 }
299 }
300 return output.str();
301 }
302
304 auto desc = ParametersDescription();
305 desc.add<std::string>("process", "").setDescription("MadGraph_aMC process definition");
306 desc.add<std::string>("model", "sm-full").setDescription("MadGraph_aMC model name");
307 desc.add<std::string>("cardPath", "/tmp/cepgen_mg5_input.dat")
308 .setDescription("Temporary file where to store the input card for MadGraph_aMC");
309 desc.add<std::string>("standaloneCppPath", "");
310 desc.add<std::string>("tmpDir", "/tmp/cepgen_mg5_aMC")
311 .setDescription("Temporary path where to store the MadGraph_aMC process definition files");
312 desc.add<std::string>("logFile", "/tmp/cepgen_mg5_aMC.log")
313 .setDescription("Temporary path where to store the log for this run");
314 desc.add<ParametersDescription>("extraParticles", ParametersDescription())
315 .setDescription("define internal MadGraph alias for a particle name");
316 desc.add<ParametersDescription>("modelParameters", ParametersDescription())
317 .setDescription("list of model parameters for the process generation");
318 return desc;
319 }
320} // namespace cepgen
#define CG_FATAL(mod)
Definition Exception.h:61
#define CG_ERROR(mod)
Definition Exception.h:60
#define CG_DEBUG(mod)
Definition Message.h:220
#define CG_INFO(mod)
Definition Message.h:216
MadGraphInterface(const ParametersList &)
static ParametersDescription extractParamCardParameters(const std::string &)
Retrieve a CepGen-compatible parameters list from a MadGraph parameters card.
static ParametersDescription description()
static std::string generateParamCard(const ParametersDescription &)
Generate a MadGraph parameters card from CepGen user-steered parameters.
void define(const ParticleProperties &)
Add a new particle definition to the library.
Definition PDG.cpp:60
static PDG & get()
Retrieve a unique instance of this particles info collection.
Definition PDG.cpp:41
A description object for parameters collection.
ParametersDescription & add(const std::string &name, const T &def)
Add the description to a new parameter.
ParametersList & parameters()
List of parameters associated to this description object.
ParametersDescription & setDescription(const std::string &descr)
Set the description of this parameter (or parameters collection)
bool empty() const
Does a description of this parameter (or parameters collection) exist?
const std::string & description() const
Description of this parameter (or parameters collection)
const ParametersDescription & get(const std::string &) const
Get the description of a sub-object.
T get(const std::string &key, const T &def=default_arg< T >::get()) const
Get a parameter value.
std::vector< std::string > keysOf() const
List of keys for one type in this list of parameters List of keys handled in this list of parameters.
Base user-steerable object.
ParticleProperties describeParticle(const std::string &part_name, const std::string &model)
Unpack all particle properties from MadGraph.
Definition Utils.cpp:68
ProcessParticles unpackProcessParticles(const std::string &proc)
Unpack the particles' content and role in the process from a string.
Definition Utils.cpp:38
std::string normalise(const std::string &proc_name, const std::string &model)
Normalise a process name to make it computer-readable.
Definition Utils.cpp:172
std::vector< std::string > runCommand(const std::vector< std::string > &cmds, const std::string &card_path, bool keep_output)
Run a mg5_aMC command and return its result.
Definition Utils.cpp:147
std::string format(const std::string &fmt, Args... args)
Format a string using a printf style format descriptor.
Definition String.h:61
std::string s(const std::string &word, float num, bool show_number)
Add a trailing "s" when needed.
Definition String.cpp:228
std::string toLower(const std::string &str)
Lowercase version of a string.
Definition String.cpp:304
size_t replaceAll(std::string &str, const std::string &from, const std::string &to)
Replace all occurrences of a text by another.
Definition String.cpp:118
std::string merge(const std::vector< T > &vec, const std::string &delim)
Merge a collection of a printable type in a single string.
Definition String.cpp:248
std::vector< std::string > split(const std::string &str, char delim, bool trim)
Split a string according to a separation character.
Definition String.cpp:233
Common namespace for this Monte Carlo generator.
unsigned long long pdgid_t
Alias for the integer-like particle PDG id.
A collection of physics constants associated to a single particle.