cepgen is hosted by Hepforge, IPPP Durham
CepGen 1.2.3
A generic 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 std::ostringstream os;
317 if (type == "float" || type == "vfloat")
318 os << std::defaultfloat << std::showpoint;
319 os << utils::merge(val, ",");
320 return (wrap ? type + "(" : "") //+ (type == "bool" ? utils::yesno(std::stoi(os.str())) : os.str()) +
321 + os.str() + (wrap ? ")" : "");
322 };
323 // wrapper for the printout of a collection type (vector, array, ...)
324 auto wrap_coll = [&wrap_val](const auto& coll, const std::string& type) -> std::string {
325 return wrap_val(utils::merge(coll, ", "), type);
326 };
327 std::ostringstream os;
328 if (has<ParametersList>(key)) {
329 os << get<ParametersList>(key);
330 return os.str();
331 }
332 if (has<std::vector<double> >(key) || has<Limits>(key)) {
333 std::string sep;
334 if (has<std::vector<double> >(key)) {
335 os << wrap_coll(get<std::vector<double> >(key), "vfloat");
336 sep = "|";
337 }
338 if (has<Limits>(key))
339 os << sep << wrap_val(get<Limits>(key), "Limits");
340 return os.str();
341 }
342 if (has<bool>(key)) {
343 os << std::boolalpha << get<bool>(key);
344 return os.str();
345 }
346#define __TYPE_ENUM(type, map, name) \
347 if (has<type>(key)) \
348 return wrap_val(get<type>(key), name);
350#undef __TYPE_ENUM
351 if (key == MODULE_NAME)
352 return "";
353 throw CG_ERROR("ParametersList:getString")
354 << "Unrecognised type for key '" << key << "' from parameters list " << *this << ".";
355 } // namespace cepgen
356
357 ParametersList& ParametersList::rename(const std::string& old_key, const std::string& new_key) {
358#define __TYPE_ENUM(type, map, name) \
359 if (has<type>(old_key)) \
360 set(new_key, get<type>(old_key)).erase(old_key);
362#undef __TYPE_ENUM
363 return *this;
364 }
365
366 std::string ParametersList::serialise() const {
367 std::ostringstream out;
368 std::string sep;
369 for (const auto& key : keys(true)) {
370 out << sep << key;
371 if (has<ParametersList>(key)) {
372 const auto& plist = get<ParametersList>(key);
373 out << "/";
374 if (plist.keys().size() > 1)
375 out << "{";
376 out << plist.serialise();
377 if (plist.keys().size() > 1)
378 out << "}";
379 } else
380 out << ":" << getString(key, false);
381 sep = ",";
382 }
383 return out.str();
384 }
385
386 //------------------------------------------------------------------
387 // default template (place holders)
388 //------------------------------------------------------------------
389
390 template <typename T>
391 bool ParametersList::has(const std::string& key) const {
392 throw CG_FATAL("ParametersList") << "Invalid type for key '" << key << "'.";
393 }
394
395 template <typename T>
396 T ParametersList::get(const std::string& key, const T&) const {
397 throw CG_FATAL("ParametersList") << "Invalid type retrieved for key '" << key << "'.";
398 }
399
400 template <typename T>
401 T& ParametersList::operator[](const std::string& key) {
402 throw CG_FATAL("ParametersList") << "Invalid type retrieved for key '" << key << "'.";
403 }
404
405 template <typename T>
406 ParametersList& ParametersList::set(const std::string& key, const T&) {
407 throw CG_FATAL("ParametersList") << "Invalid type to be set for key '" << key << "'.";
408 }
409
410 //------------------------------------------------------------------
411 // sub-parameters-type attributes
412 //------------------------------------------------------------------
413
415 IMPL_TYPE_ALL(bool, bool_values_);
416 IMPL_TYPE_ALL(int, int_values_);
417 IMPL_TYPE_ALL(unsigned long long, ulong_values_);
418 IMPL_TYPE_ALL(double, dbl_values_);
419 IMPL_TYPE_ALL(std::string, str_values_);
420 IMPL_TYPE_ALL(std::vector<int>, vec_int_values_);
421 IMPL_TYPE_ALL(std::vector<double>, vec_dbl_values_);
422 IMPL_TYPE_ALL(std::vector<std::string>, vec_str_values_);
423 IMPL_TYPE_ALL(std::vector<Limits>, vec_lim_values_);
424 IMPL_TYPE_ALL(std::vector<ParametersList>, vec_param_values_);
425 IMPL_TYPE_ALL(std::vector<std::vector<double> >, vec_vec_dbl_values_);
426
427 //------------------------------------------------------------------
428 // limits-type attributes
429 //------------------------------------------------------------------
430
431 IMPL_TYPE_SET(Limits, lim_values_);
432
433 template <>
434 Limits ParametersList::get<Limits>(const std::string& key, const Limits& def) const {
435 // first try to find Limits object in collections
436 Limits out;
437 auto val = std::find_if(lim_values_.begin(), lim_values_.end(), [&key](const auto& kv) { return kv.first == key; });
438 if (val != lim_values_.end())
439 out = val->second;
440 else { // still trying to build it from (min/max) attributes
441 fill<double>(key + "min", out.min());
442 fill<double>(key + "max", out.max());
443 }
444 return out.validate();
445 // nothing found ; returning default
446 CG_DEBUG("ParametersList") << "Failed to retrieve limits parameter with key=" << key << ". "
447 << "Default value: " << def << ".";
448 return def;
449 }
450
451 template <>
452 const ParametersList& ParametersList::fill<Limits>(const std::string& key, Limits& value) const {
453 if (has<Limits>(key)) {
454 const auto& lim = get<Limits>(key);
455 if (lim.hasMin())
456 value.min() = lim.min();
457 if (lim.hasMax())
458 value.max() = lim.max();
459 return *this;
460 }
461 fill<double>(key + "min", value.min());
462 fill<double>(key + "max", value.max());
463 return *this;
464 }
465
466 //------------------------------------------------------------------
467 // particle properties-type attributes
468 // particular case for this container, as it can either be
469 // represented by a ParametersList (collection of parameters) or
470 // an integer PDG identifier
471 //------------------------------------------------------------------
472
474 template <>
475 bool ParametersList::has<ParticleProperties>(const std::string& key) const {
476 return has<ParametersList>(key) || has<int>(key);
477 }
478
480 template <>
481 ParticleProperties ParametersList::get<ParticleProperties>(const std::string& key,
482 const ParticleProperties& def) const {
483 if (has<ParametersList>(key)) { // try to steer as a dictionary of particle properties
484 const auto& plist = get<ParametersList>(key);
485 if (plist.keys() == std::vector<std::string>{"pdgid"})
486 return PDG::get()(plist.get<int>("pdgid"));
487 return ParticleProperties(plist);
488 } else if (has<pdgid_t>(key)) { // if not a dictionary of properties, retrieve from PDG runtime database
489 CG_DEBUG("ParametersList") << "Retrieved physical properties for particle with PDG identifier '"
490 << get<pdgid_t>(key) << "' from PDG database.";
491 return PDG::get()(get<pdgid_t>(key));
492 } else if (has<int>(key)) { // if not a dictionary of properties, retrieve from PDG runtime database
493 CG_DEBUG("ParametersList") << "Retrieved physical properties for particle with PDG identifier '" << get<int>(key)
494 << "' from PDG database.";
495 return PDG::get()(get<int>(key));
496 }
497 CG_DEBUG("ParametersList") << "Failed to retrieve particle properties parameter with key=" << key << ".";
498 return def;
499 }
500
502 template <>
503 ParametersList& ParametersList::set<ParticleProperties>(const std::string& key, const ParticleProperties& value) {
504 PDG::get().define(value);
505 return set<ParametersList>(key, value.parameters());
506 }
507
508 template <>
509 std::vector<std::string> ParametersList::keysOf<ParticleProperties>() const {
510 std::vector<std::string> pdesc_keys;
511 for (const auto& key : keys())
513 pdesc_keys.emplace_back(key);
514 return pdesc_keys;
515 }
516} // namespace cepgen
517
518#undef IMPL_TYPE_SET
519#undef IMPL_TYPE_GET
520#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
Limits & validate()
Ensure the limit object is valid by correcting it if necessary.
Definition Limits.cpp:91
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:219
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:342
std::string toLower(const std::string &str)
Lowercase version of a string.
Definition String.cpp:295
bool endsWith(const std::string &str, const std::string &end)
Check if a string ends with a given token.
Definition String.cpp:358
bool isFloat(const std::string &str)
Check if a string is also a floating point number.
Definition String.cpp:286
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:239
std::vector< std::string > split(const std::string &str, char delim, bool trim)
Split a string according to a separation character.
Definition String.cpp:224
bool isInt(const std::string &str)
Check if a string is also an integer.
Definition String.cpp:281
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.