File parameterparser.h
File List > code_source > templat > include > TempLat > parameters > parameterparser.h
Go to the documentation of this file
#ifndef TEMPLAT_PARAMETERS_PARAMETERS_H
#define TEMPLAT_PARAMETERS_PARAMETERS_H
/* This file is part of TempLat, available at https://cosmolattice.github.io/templat .
Copyright 2021-2026 The TempLat authors, see AUTHORS.md.
Released under the MIT license, see LICENSE.md. */
// File info: Main contributor(s): Adrien Florio, Year: 2019
#include "TempLat/parameters/pairmaker.h"
#include <unordered_map>
#include "TempLat/parameters/stringconverter.h"
#include "TempLat/parameters/filereader.h"
#include "TempLat/util/rangeiteration/tagliteral.h"
#include "TempLat/util/log/log.h"
#include <random>
#include <iomanip>
#ifdef HAVE_MPI
#include <mpi.h> //This is to make getSeed MPI safe.
#endif
namespace TempLat
{
enum ParameterImportance { Important, Normal };
MakeException(ParameterParserMissingMandatory);
MakeException(ParameterParserMismatchSizes);
MakeException(ParameterParserMismatchDefaultSizes);
MakeException(ParameterParserDoesNotExist);
MakeException(ParameterParserIsEmpty);
class ParameterParser
{
public:
// Put public methods here. These should change very little over time.
ParameterParser(int argc, char *argv[], bool pVerbose = false)
: params(), pairMaker(), mVerbose(pVerbose), mOverride(false)
{
for (int i = 1; i < argc; ++i) {
insert(argv[i]);
}
if (params.count("input") > 0) {
FileReader fr;
fr(params["input"]);
for (size_t i = 0; i < fr.size(); ++i) {
insert(fr[i]);
}
assignImportance("input", Normal);
}
}
void addFromVector(const std::vector<std::string> &vec)
{
for (auto x : vec) {
insert(x);
}
}
template <class S> ParameterGetter<S> get(const std::string &name, ParameterImportance importance = Normal)
{
return this->get<S>(name, true, {S()}, false, Tag<1>(), importance)[0];
}
template <class S> ParameterGetter<S> get(const std::string &name, S def, ParameterImportance importance = Normal)
{
return this->get<S>(name, false, {def}, false, Tag<1>(), importance)[0];
}
template <class S, int N>
MultipleParameterGetter<S> get(const std::string &name, ParameterImportance importance = Normal)
{
return this->get<S>(name, true, {}, false, Tag<N>(), importance);
}
template <class S, int N>
MultipleParameterGetter<S> get(const std::string &name, std::vector<S> def, ParameterImportance importance = Normal)
{
return this->get<S>(name, false, def, false, Tag<N>(), importance);
}
template <class S, int N>
MultipleParameterGetter<S> get(const std::string &name, S def, ParameterImportance importance = Normal)
{
return this->get<S>(name, false, {def}, false, Tag<N>(), importance);
}
template <class S> ParameterGetter<S> getOverride(const std::string &name, ParameterImportance importance = Normal)
{
return this->get<S>(name, true, {S()}, mOverride, Tag<1>(), importance)[0];
}
template <class S>
ParameterGetter<S> getOverride(const std::string &name, S def, ParameterImportance importance = Normal)
{
return this->get<S>(name, false, {def}, mOverride, Tag<1>(), importance)[0];
}
template <class S, int N>
MultipleParameterGetter<S> getOverride(const std::string &name, ParameterImportance importance = Normal)
{
return this->get<S>(name, true, {}, mOverride, Tag<N>(), importance);
}
template <class S, int N>
MultipleParameterGetter<S> getOverride(const std::string &name, std::vector<S> def,
ParameterImportance importance = Normal)
{
return this->get<S>(name, false, def, mOverride, Tag<N>(), importance);
}
std::string getSeed(const std::string &name)
{
std::string tmp = this->get<std::string>(name, "0")();
if (tmp == "0") {
std::random_device r;
unsigned int res = r();
#ifdef HAVE_MPI
MPI_Bcast(&res, 1, MPI_INT, 0, MPI_COMM_WORLD);
#endif
tmp = std::to_string(res);
}
params[name] = tmp;
return tmp;
}
const auto &getParams() const { return params; }
void activateOverride() { mOverride = true; }
void insert(const std::string &str)
{ // Insert value of the current PairMaker in the unordered_map. If already exist, skip it.
pairMaker(str);
if (params.count(pairMaker.getKey()) == 0) {
params[pairMaker.getKey()] = pairMaker.getValue();
if (params[pairMaker.getKey()] == "")
throw(
ParameterParserIsEmpty("Parameter " + pairMaker.getKey() +
" is empty. Abort. If it is an optional parameter, remove it or comment it out."));
} else {
if (mVerbose)
say << "Parameter " + pairMaker.getKey() +
" already assigned, skipped. The last value of this parameter which is skipped will be cached to "
"have the potential of overriding it.";
paramsOverride[pairMaker.getKey()] = pairMaker.getValue(); // Store last of the extra value here.
}
}
void erase(const std::string &key) { params.erase(key); }
friend std::ostream &operator<<(std::ostream &os, const ParameterParser &par)
{
std::stringstream importantParams;
importantParams << "Important parameters:" << std::endl << std::endl;
std::stringstream otherParams;
otherParams << "Other parameters:" << std::endl << std::endl;
std::string second;
for (const auto &i : par.params) {
if (par.paramsImportance.count(i.first) > 0) {
second = par.paramsOverriden.count(i.first) > 0 ? par.paramsOverriden.at(i.first) : i.second;
if (par.paramsImportance.at(i.first) == Important)
importantParams << std::right << std::setw(20) << i.first << " " << std::setw(20) << std::left
<< second << std::endl;
if (par.paramsImportance.at(i.first) == Normal)
otherParams << std::right << std::setw(20) << i.first << " " << std::setw(20) << std::left << second
<< std::endl;
}
}
os << importantParams.str() << std::endl << std::endl << otherParams.str();
return os;
}
private:
/* Put all member variables and private methods here. These may change arbitrarily. */
std::unordered_map<std::string, std::string> params;
std::unordered_map<std::string, std::string> paramsOverride;
std::unordered_map<std::string, std::string>
paramsOverriden; // This is the list of parameters which have actually been overriden
std::unordered_map<std::string, int> paramsImportance; // just for printing purposes
PairMaker pairMaker;
const bool mVerbose;
bool mOverride;
template <class S, int N>
MultipleParameterGetter<S> get(const std::string &name, const bool &mandatory, std::vector<S> def, bool override,
Tag<N>, ParameterImportance importance = Normal)
{ // give the templated integer as a tag so we can specialise for N=0.
MultipleParameterGetter<S> ret;
StringConverter<S> conv;
if ((!override || paramsOverride.count(name) == 0) && params.count(name) > 0) {
conv(params[name], ret, name);
if (N > 0 && mandatory && ret.size() != N)
throw(ParameterParserMismatchSizes("Parameter " + name +
" was provided with an unexpected number of arguments. Abort."));
if (N > 0 && !mandatory && ret.size() > N)
throw(ParameterParserMismatchSizes("Parameter " + name + " was provided with too many arguments. Abort."));
} else if (override && paramsOverride.count(name) > 0) {
conv(paramsOverride[name], ret, name);
paramsOverriden[name] = paramsOverride[name];
if (N > 0 && ret.size() != N)
throw(ParameterParserMismatchSizes("Parameter " + name +
" was provided with an unexpected number of arguments. Abort."));
} else if (mandatory)
throw(ParameterParserMissingMandatory("Mandatory parameter " + name + " was not specified. Abort."));
else if ((N > 0 && (def.size() != 1 && def.size() != N)) || def.empty())
throw(ParameterParserMismatchDefaultSizes(
"Optional parameter " + name + " was not provided with the correct number of default values. Abort."));
// else{
if (ret.size() != N) {
std::ostringstream oss;
bool toInsert(ret.size() == 0);
oss << name << "=";
if (def.size() == 1) {
for (int i = 0; i < N - 1; ++i) {
def.emplace_back(def[0]);
}
}
if constexpr (N > 0)
for (size_t i = ret.size(); i < (size_t)N; ++i) {
ret.push_back(ParameterGetter<S>(def[i], name));
oss << std::boolalpha << def[i] << " ";
}
// if(mVerbose) say << oss.str();
if (toInsert)
insert(oss.str()); // useful to insert the optionnal params so we can retrieve them later, for saving purposes
// for example.
}
assignImportance(name, importance);
if (mVerbose) say << "Parameter initialisation: " << ret;
return ret;
}
void assignImportance(std::string name, ParameterImportance importance)
{
if (paramsImportance.count(name) == 0) {
paramsImportance[name] = importance;
}
}
template <class S>
MultipleParameterGetter<S> get(const std::string &name, const bool &mandatory, std::vector<S> def, bool override,
Tag<0>)
{
MultipleParameterGetter<S> ret;
return ret;
}
};
} // namespace TempLat
#endif