cepgen is hosted by Hepforge, IPPP Durham
CepGen 1.2.5
Central exclusive processes event generator
Loading...
Searching...
No Matches
ParametersList.cpp
Go to the documentation of this file.
1/*
2 * CepGen: a central exclusive processes event generator
3 * Copyright (C) 2018-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#include <iomanip>
20#include <limits>
21#include <regex>
22
25#include "CepGen/Physics/PDG.h"
26#include "CepGen/Utils/String.h"
27
28#define IMPL_TYPE_GET(type, coll) \
29 template <> \
30 type ParametersList::get<type>(const std::string& key, const type& def) const { \
31 if (coll.count(key) > 0) \
32 return coll.at(key); \
33 CG_DEBUG("ParametersList") << "Failed to retrieve " << utils::demangle(typeid(type).name()) \
34 << " parameter with key=" << key << ". Default value: " << def << "."; \
35 return def; \
36 } \
37 static_assert(true, "")
38
39#define IMPL_TYPE_SET(type, coll) \
40 template <> \
41 bool ParametersList::has<type>(const std::string& key) const { \
42 return coll.count(key) != 0; \
43 } \
44 template <> \
45 ParametersList& ParametersList::set<type>(const std::string& key, const type& value) { \
46 coll[key] = static_cast<type>(value); \
47 return *this; \
48 } \
49 template <> \
50 type& ParametersList::operator[]<type>(const std::string& key) { \
51 return coll[key]; \
52 } \
53 template <> \
54 std::vector<std::string> ParametersList::keysOf<type>() const { \
55 std::vector<std::string> out; \
56 std::transform(coll.begin(), coll.end(), std::back_inserter(out), [](const auto& pair) { return pair.first; }); \
57 return out; \
58 } \
59 template <> \
60 size_t ParametersList::erase<type>(const std::string& key) { \
61 return coll.erase(key); \
62 } \
63 static_assert(true, "")
64
65#define IMPL_TYPE_ALL(type, coll) \
66 IMPL_TYPE_GET(type, coll); \
67 IMPL_TYPE_SET(type, coll); \
68 static_assert(true, "")
69
70namespace cepgen {
72
74#define __TYPE_ENUM(type, map, name) \
75 if (map != oth.map) \
76 return false;
78#undef __TYPE_ENUM
79 return true;
80 }
81
84 ParametersList &mine = diff.operator[]<ParametersList>("mine"), &theirs = diff.operator[]<ParametersList>("theirs");
85 if (*this == oth)
86 return diff;
87 for (const auto& key : keys()) {
88 if (has<ParametersList>(key)) {
89 const auto& my_plist = get<ParametersList>(key);
90 if (!has<ParametersList>(key))
91 mine.set(key, my_plist);
92 else if (const auto their_plist = oth.get<ParametersList>(key); my_plist != their_plist) {
93 mine.set(key, my_plist);
94 theirs.set(key, their_plist);
95 }
96 continue;
97 }
98#define __TYPE_ENUM(type, map, name) \
99 if (const auto my_param = get<type>(key), their_param = oth.get<type>(key); my_param != their_param) { \
100 mine.set(key, my_param); \
101 if (!oth.empty()) \
102 theirs.set(key, their_param); \
103 continue; \
104 }
106#undef __TYPE_ENUM
107 }
108 return diff;
109 }
110
112 if (empty()) {
113 *this = oth_orig;
114 return *this;
115 }
116 if (oth_orig.empty() || *this == oth_orig) // ensure the two collections are not identical or empty
117 return *this;
118 auto oth = oth_orig;
119 std::vector<std::string> keys_erased;
120 for (const auto& oth_key : oth.keys()) { // check if any key of the other collection is already present in the list
121 if (has<ParametersList>(oth_key)) {
122 // do not remove a duplicate parameters collection if they are not strictly identical ;
123 // will concatenate its values with the other object's
124 if (get<ParametersList>(oth_key) == oth.get<ParametersList>(oth_key) && oth.erase(oth_key) > 0)
125 keys_erased.emplace_back(oth_key);
126 } else if (oth.has<double>(oth_key) && (utils::endsWith(oth_key, "max") || utils::endsWith(oth_key, "min"))) {
127 // hacky path to drop 'xxxmin'/'xxxmax' keys if 'xxx' limits were found
128 auto& lim = operator[]<Limits>(oth_key.substr(0, oth_key.size() - 3));
129 if (utils::endsWith(oth_key, "max"))
130 lim.max() = oth.get<double>(oth_key);
131 else if (utils::endsWith(oth_key, "min"))
132 lim.min() = oth.get<double>(oth_key);
133 if (erase(oth_key) > 0 && oth.erase(oth_key) > 0)
134 keys_erased.emplace_back(oth_key);
135 } else if (erase(oth_key) > 0) // any other duplicate key is just replaced
136 keys_erased.emplace_back(oth_key);
137 }
138 if (!keys_erased.empty())
139 CG_DEBUG_LOOP("ParametersList") << utils::s("key", keys_erased.size(), true) << " erased: " << keys_erased << ".";
140 //--- concatenate all typed lists
141#define __TYPE_ENUM(type, map, name) map.insert(oth.map.begin(), oth.map.end());
143#undef __TYPE_ENUM
144 // special case for parameters collection: concatenate values instead of full containers
145 for (const auto& par : oth.param_values_)
146 // if the two parameters list are modules, and do not have the same name,
147 // simply replace the old one with the new parameters list
148 if (param_values_[par.first].getNameString() == par.second.getNameString())
149 param_values_[par.first] += par.second;
150 else
151 param_values_[par.first] = par.second;
152 return *this;
153 }
154
156 auto out = *this;
157 out += oth;
158 return out;
159 }
160
161 ParametersList& ParametersList::feed(const std::string& raw_args) {
162 auto raw_list = raw_args;
163 const auto raw_list_stripped = utils::between(raw_list, "{", "}");
164 if (raw_list_stripped.size() == 1 && raw_list == "{" + raw_list_stripped[0] + "}")
165 raw_list = raw_list_stripped[0];
166 // first pre-process the arguments list to isolate all comma-separated arguments
167 std::vector<std::string> list;
168 std::vector<std::string> buf;
169 short num_open_braces = 0;
170 for (const auto& item : utils::split(raw_list, ',')) {
171 buf.emplace_back(item);
172 num_open_braces += std::count(item.begin(), item.end(), '{') - std::count(item.begin(), item.end(), '}');
173 if (num_open_braces <= 0) {
174 list.emplace_back(utils::merge(buf, ","));
175 buf.clear();
176 }
177 }
178 CG_DEBUG("ParametersList:feed") << "Parsed arguments: " << list << ", raw list: " << raw_list
179 << " (split: " << utils::split(raw_list, ',') << "), "
180 << "{-} imbalance: " << num_open_braces << ".";
181 if (num_open_braces != 0)
182 throw CG_ERROR("ParametersList:feed") << "Invalid string to be parsed as a parameters list!\n\t"
183 << "Open-closed braces imbalance: " << num_open_braces << "\n\t"
184 << "Raw list: " << raw_list << "\n\t"
185 << "Resulting list: " << list << ", buffer: " << buf << ".";
186 for (const auto& arg : list) { // loop through all unpacked arguments
187 auto cmd = utils::split(arg, '/'); // browse through the parameters hierarchy
188 if (arg[arg.size() - 1] != '\'' && arg[arg.size() - 1] != '"' && cmd.size() > 1) { // sub-parameters word found
189 operator[]<ParametersList>(cmd.at(0)).feed(
190 utils::merge(std::vector<std::string>(cmd.begin() + 1, cmd.end()), "/"));
191 continue;
192 }
193 // from this point, a "key:value" or "key(:true)" was found
194 const auto& subplist = utils::between(arg, "{", "}");
195 if (!subplist.empty()) {
196 for (const auto& subp : subplist)
197 feed(subp);
198 return *this;
199 }
200 const auto& word = cmd.at(0);
201 const auto words = utils::split(arg, ':');
202 auto key = words.at(0);
203 if (erase(key) > 0)
204 CG_DEBUG("ParametersList:feed") << "Replacing key '" << key << "' with a new value.";
205 if (key == "name") // replace any "name" key encountered by the canonical module name key
206 key = MODULE_NAME;
207 if (words.size() == 1) // basic key:true
208 set<bool>(key, true);
209 else if (words.size() == 2) { // basic key:value
210 const auto& value = words.at(1);
211 if (utils::isInt(value))
212 set<int>(key, std::stoi(value));
213 else if (utils::isFloat(value))
214 set<double>(key, std::stod(value));
215 else if (value[0] == value[value.size() - 1] && (value[0] == '\'' || value[0] == '"')) // string parameter
216 set(key, value.substr(1, value.size() - 2));
217 else {
218 const auto value_lc = utils::toLower(value);
219 if (value_lc == "off" || value_lc == "no" || value_lc == "false")
220 set<bool>(key, false);
221 else if (value_lc == "on" || value_lc == "yes" || value_lc == "true")
222 set<bool>(key, true);
223 else if (value.find('>') != std::string::npos) {
224 const auto limits = utils::split(value, '>');
225 if (limits.size() != 2)
226 throw CG_FATAL("ParametersList:feed") << "Failed to parse limits value '" << value << "'.";
227 set<Limits>(key, Limits{std::stod(limits.at(0)), std::stod(limits.at(1))});
228 } else {
229 auto parsed_value = value;
230 if (value.size() > 2 && value[0] == value[value.size() - 1] && (value[0] == '"' || value[0] == '\''))
231 parsed_value = parsed_value.substr(1, value.size() - 2);
232 set<std::string>(key, parsed_value);
233 }
234 }
235 } else
236 throw CG_FATAL("ParametersList:feed") << "Invalid key:value unpacking: " << word << "!";
237 }
238 return *this;
239 }
240
241 size_t ParametersList::erase(const std::string& key) {
242 size_t num_keys_erased = 0;
243#define __TYPE_ENUM(type, map, name) num_keys_erased += erase<type>(key);
245#undef __TYPE_ENUM
246 return num_keys_erased;
247 }
248
249 bool ParametersList::empty() const { return keys(true).empty(); }
250
251 std::ostream& operator<<(std::ostream& os, const ParametersList& params) {
252 params.print(os);
253 return os;
254 }
255
256 const ParametersList& ParametersList::print(std::ostream& os) const {
257 const auto& keys_list = keys(true);
258 if (keys_list.empty()) {
259 os << "{}";
260 return *this;
261 }
262 std::string sep;
263 if (std::find(keys_list.begin(), keys_list.end(), MODULE_NAME) != keys_list.end()) {
264 const auto plist_name = getNameString();
265 auto mod_name = hasName() ? "\"" + plist_name + "\"" : plist_name;
266 os << "Module(" << mod_name, sep = ", ";
267 } else
268 os << "Parameters(";
269 for (const auto& key : keys_list)
270 if (key != MODULE_NAME)
271 os << sep << key << "=" << getString(key, true), sep = ", ";
272 os << ")";
273 return *this;
274 }
275
276 std::string ParametersList::print(bool compact) const {
277 std::ostringstream os;
278 if (compact) {
280 if (const auto& keys_list = keys(false); !keys_list.empty()) {
281 std::string sep = "{";
282 for (const auto& key : keys_list)
283 os << sep << key << "=" << getString(key), sep = ", ";
284 os << "}";
285 }
286 return os.str();
287 }
288 print(os);
289 return os.str();
290 }
291
292 bool ParametersList::hasName() const { return has<std::string>(MODULE_NAME); }
293
294 std::string ParametersList::name(const std::string& def) const { return get<std::string>(MODULE_NAME, def); }
295
296 ParametersList& ParametersList::setName(const std::string& value) { return set<std::string>(MODULE_NAME, value); }
297
298 std::vector<std::string> ParametersList::keys(bool name_key) const {
299 std::vector<std::string> out{};
300 const auto key = [](const auto& p) { return p.first; };
301#define __TYPE_ENUM(type, map, name) std::transform(map.begin(), map.end(), std::back_inserter(out), key);
303#undef __TYPE_ENUM
304 if (!name_key) {
305 if (const auto it_name = std::find(out.begin(), out.end(), MODULE_NAME); it_name != out.end())
306 out.erase(it_name);
307 }
308 std::sort(out.begin(), out.end());
309 out.erase(std::unique(out.begin(), out.end()), out.end()); // at most 1 duplicate
310 return out;
311 }
312
313 std::string ParametersList::getString(const std::string& key, bool wrap) const {
314 // wrapper for the printout of a general variable
315 auto wrap_val = [&wrap](const auto& val, const std::string& type) -> std::string {
316 return (wrap ? type + "(" : "") + utils::merge(val, ",") + (wrap ? ")" : "");
317 };
318 // wrapper for the printout of a collection type (vector, array, ...)
319 auto wrap_coll = [&wrap_val](const auto& coll, const std::string& type) -> std::string {
320 return wrap_val(utils::merge(coll, ", "), type);
321 };
322 std::ostringstream os;
323 if (has<ParametersList>(key)) {
324 os << get<ParametersList>(key);
325 return os.str();
326 }
327 if (has<std::vector<double> >(key) || has<Limits>(key)) {
328 std::string sep;
329 if (has<std::vector<double> >(key)) {
330 os << wrap_coll(get<std::vector<double> >(key), "vfloat");
331 sep = "|";
332 }
333 if (has<Limits>(key))
334 os << sep << wrap_val(get<Limits>(key), "Limits");
335 return os.str();
336 }
337 if (has<bool>(key)) {
338 os << std::boolalpha << get<bool>(key);
339 return os.str();
340 }
341#define __TYPE_ENUM(type, map, name) \
342 if (has<type>(key)) \
343 return wrap_val(get<type>(key), name);
345#undef __TYPE_ENUM
346 if (key == MODULE_NAME)
347 return "";
348 throw CG_ERROR("ParametersList:getString")
349 << "Unrecognised type for key '" << key << "' from parameters list " << *this << ".";
350 }
351
352 ParametersList& ParametersList::rename(const std::string& old_key, const std::string& new_key) {
353#define __TYPE_ENUM(type, map, name) \
354 if (has<type>(old_key)) \
355 set(new_key, get<type>(old_key)).erase(old_key);
357#undef __TYPE_ENUM
358 return *this;
359 }
360
361 std::string ParametersList::serialise() const {
362 std::ostringstream out;
363 std::string sep;
364 for (const auto& key : keys(true)) {
365 out << sep << key;
366 if (has<ParametersList>(key)) {
367 const auto& plist = get<ParametersList>(key);
368 out << "/";
369 if (plist.keys().size() > 1)
370 out << "{";
371 out << plist.serialise();
372 if (plist.keys().size() > 1)
373 out << "}";
374 } else
375 out << ":" << getString(key, false);
376 sep = ",";
377 }
378 return out.str();
379 }
380
381 //------------------------------------------------------------------
382 // default template (place holders)
383 //------------------------------------------------------------------
384
385 template <typename T>
386 bool ParametersList::has(const std::string& key) const {
387 throw CG_FATAL("ParametersList") << "Invalid type for key '" << key << "'.";
388 }
389
390 template <typename T>
391 T ParametersList::get(const std::string& key, const T&) const {
392 throw CG_FATAL("ParametersList") << "Invalid type retrieved for key '" << key << "'.";
393 }
394
395 template <typename T>
396 T& ParametersList::operator[](const std::string& key) {
397 throw CG_FATAL("ParametersList") << "Invalid type retrieved for key '" << key << "'.";
398 }
399
400 template <typename T>
401 ParametersList& ParametersList::set(const std::string& key, const T&) {
402 throw CG_FATAL("ParametersList") << "Invalid type to be set for key '" << key << "'.";
403 }
404
405 //------------------------------------------------------------------
406 // sub-parameters-type attributes
407 //------------------------------------------------------------------
408
410 IMPL_TYPE_ALL(bool, bool_values_);
411 IMPL_TYPE_ALL(int, int_values_);
412 IMPL_TYPE_ALL(unsigned long long, ulong_values_);
413 IMPL_TYPE_ALL(double, dbl_values_);
414 IMPL_TYPE_ALL(std::string, str_values_);
415 IMPL_TYPE_ALL(std::vector<int>, vec_int_values_);
416 IMPL_TYPE_ALL(std::vector<double>, vec_dbl_values_);
417 IMPL_TYPE_ALL(std::vector<std::string>, vec_str_values_);
418 IMPL_TYPE_ALL(std::vector<Limits>, vec_lim_values_);
419 IMPL_TYPE_ALL(std::vector<ParametersList>, vec_param_values_);
420 IMPL_TYPE_ALL(std::vector<std::vector<double> >, vec_vec_dbl_values_);
421
422 //------------------------------------------------------------------
423 // limits-type attributes
424 //------------------------------------------------------------------
425
426 IMPL_TYPE_SET(Limits, lim_values_);
427
428 template <>
429 Limits ParametersList::get<Limits>(const std::string& key, const Limits& def) const {
430 // first try to find Limits object in collections
431 auto out = def;
432 if (auto val =
433 std::find_if(lim_values_.begin(), lim_values_.end(), [&key](const auto& kv) { return kv.first == key; });
434 val != lim_values_.end())
435 out = val->second;
436 else { // still trying to build it from (min/max) attributes
437 fill<double>(key + "min", out.min());
438 fill<double>(key + "max", out.max());
439 }
440 return out.validate();
441 }
442
443 template <>
444 const ParametersList& ParametersList::fill<Limits>(const std::string& key, Limits& value) const {
445 if (has<Limits>(key)) {
446 const auto& lim = get<Limits>(key);
447 if (lim.hasMin())
448 value.min() = lim.min();
449 if (lim.hasMax())
450 value.max() = lim.max();
451 return *this;
452 }
453 fill<double>(key + "min", value.min());
454 fill<double>(key + "max", value.max());
455 return *this;
456 }
457
458 //------------------------------------------------------------------
459 // particle properties-type attributes
460 // particular case for this container, as it can either be
461 // represented by a ParametersList (collection of parameters) or
462 // an integer PDG identifier
463 //------------------------------------------------------------------
464
466 template <>
467 bool ParametersList::has<ParticleProperties>(const std::string& key) const {
468 return has<ParametersList>(key) || has<int>(key);
469 }
470
472 template <>
473 ParticleProperties ParametersList::get<ParticleProperties>(const std::string& key,
474 const ParticleProperties& def) const {
475 if (has<ParametersList>(key)) { // try to steer as a dictionary of particle properties
476 const auto& plist = get<ParametersList>(key);
477 if (plist.keys() == std::vector<std::string>{"pdgid"})
478 return PDG::get()(plist.get<int>("pdgid"));
479 return ParticleProperties(plist);
480 } else if (has<pdgid_t>(key)) { // if not a dictionary of properties, retrieve from PDG runtime database
481 CG_DEBUG("ParametersList") << "Retrieved physical properties for particle with PDG identifier '"
482 << get<pdgid_t>(key) << "' from PDG database.";
483 return PDG::get()(get<pdgid_t>(key));
484 } else if (has<int>(key)) { // if not a dictionary of properties, retrieve from PDG runtime database
485 CG_DEBUG("ParametersList") << "Retrieved physical properties for particle with PDG identifier '" << get<int>(key)
486 << "' from PDG database.";
487 return PDG::get()(get<int>(key));
488 }
489 CG_DEBUG("ParametersList") << "Failed to retrieve particle properties parameter with key=" << key << ".";
490 return def;
491 }
492
494 template <>
495 ParametersList& ParametersList::set<ParticleProperties>(const std::string& key, const ParticleProperties& value) {
496 PDG::get().define(value);
497 return set<ParametersList>(key, value.parameters());
498 }
499
500 template <>
501 std::vector<std::string> ParametersList::keysOf<ParticleProperties>() const {
502 std::vector<std::string> pdesc_keys;
503 for (const auto& key : keys())
505 pdesc_keys.emplace_back(key);
506 return pdesc_keys;
507 }
508} // namespace cepgen
509
510#undef IMPL_TYPE_SET
511#undef IMPL_TYPE_GET
512#undef IMPL_TYPE_ALL
#define CG_FATAL(mod)
Definition Exception.h:61
#define CG_ERROR(mod)
Definition Exception.h:60
#define CG_DEBUG_LOOP(mod)
Definition Message.h:224
#define CG_DEBUG(mod)
Definition Message.h:220
#define IMPL_TYPE_ALL(type, coll)
#define IMPL_TYPE_SET(type, coll)
#define REGISTER_CONTENT_TYPE
Looper over the list of parameters containers handled by the ParametersList object.
Validity interval for a variable.
Definition Limits.h:28
double min() const
Lower limit to apply on the variable.
Definition Limits.h:52
double max() const
Upper limit to apply on the variable.
Definition Limits.h:54
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
bool has(const std::string &key) const
Check if a given parameter is handled in this list.
std::string serialise() const
Serialise a parameters collection into a parseable string.
bool hasName() const
Does the parameters list have a name key?
bool operator==(const ParametersList &) const
Equality operator.
std::string name(const std::string &def="") const
Retrieve the module name if any.
ParametersList & operator+=(const ParametersList &oth)
Concatenate two parameters containers.
const ParametersList & print(std::ostream &) const
Debugging-like printout of a parameters container.
ParametersList & feed(const std::string &)
Feed a control string to the list of parameters.
ParametersList & setName(const std::string &)
Set the module name.
ParametersList diff(const ParametersList &) const
Diff with another parameters list ('mine' + 'theirs' keys)
std::vector< std::string > keys(bool name_key=true) const
bool empty() const
Is the list empty?
size_t erase(const std::string &)
Erase a parameter with key.
T get(const std::string &key, const T &def=default_arg< T >::get()) const
Get a parameter value.
std::string getNameString(bool wrap=false) const
Get a string-converted version of the module name if any.
ParametersList & set(const std::string &, const T &)
Set a parameter value Set a recast parameter value.
T & operator[](const std::string &key)
Reference to a parameter value.
ParametersList & rename(const std::string &, const std::string &)
Rename the key to a parameter value.
ParametersList operator+(const ParametersList &oth) const
Concatenation of two parameters containers.
std::string getString(const std::string &key, bool wrap=false) const
Get a string-converted version of a value.
const ParametersList & parameters() const override
Module user-defined parameters.
std::string s(const std::string &word, float num, bool show_number)
Add a trailing "s" when needed.
Definition String.cpp:228
std::vector< std::string > between(const std::string &str, const std::string &beg, const std::string &end)
Get a (list of) substring(s) between two characters chains.
Definition String.cpp:351
std::string toLower(const std::string &str)
Lowercase version of a string.
Definition String.cpp:304
bool endsWith(const std::string &str, const std::string &end)
Check if a string ends with a given token.
Definition String.cpp:367
bool isFloat(const std::string &str)
Check if a string is also a floating point number.
Definition String.cpp:295
std::string colourise(const std::string &str, const Colour &col, const Modifier &mod)
Colourise a string for TTY-type output streams.
Definition String.cpp:70
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
bool isInt(const std::string &str)
Check if a string is also an integer.
Definition String.cpp:290
Common namespace for this Monte Carlo generator.
std::ostream & operator<<(std::ostream &os, const Exception::Type &type)
Definition Exception.cpp:59
const char *const MODULE_NAME
Indexing key for the module name Parameters container.
A collection of physics constants associated to a single particle.