32#ifndef OPM_PARAMETER_SYSTEM_HH
33#define OPM_PARAMETER_SYSTEM_HH
36#include <opm/material/common/quad.hpp>
39#include <dune/common/classname.hh>
40#include <dune/common/parametertree.hh>
62template <
typename,
class =
void>
66struct has_name<T, std::void_t<decltype(std::declval<T>().name)>>
67:
public std::true_type {};
70template<
class Parameter>
74 return Parameter::name;
76 std::string paramName = Dune::className<Parameter>();
77 paramName.replace(0, std::strlen(
"Opm::Parameters::"),
"");
78 const auto pos = paramName.find_first_of(
'<');
79 if (pos != std::string::npos) {
121template <
class Param>
122auto Get(
bool errorIfNotRegistered =
true);
138template <
class Param>
139auto SetDefault(
decltype(Param::value) new_value);
149template <
class Param>
157 std::ignore = Get<Param>(
true);
163 using type = Dune::ParameterTree;
165 static Dune::ParameterTree&
tree()
166 {
return *storage_().tree; }
169 {
return storage_().registry; }
171 static const std::map<std::string, ParamInfo>&
registry()
172 {
return storage_().registry; }
175 {
return storage_().finalizers; }
178 {
return storage_().registrationOpen; }
182 storage_().tree = std::make_unique<Dune::ParameterTree>();
183 storage_().finalizers.clear();
184 storage_().registrationOpen =
true;
185 storage_().registry.clear();
197 tree = std::make_unique<Dune::ParameterTree>();
201 std::unique_ptr<Dune::ParameterTree>
tree;
202 std::map<std::string, ParamInfo>
registry;
203 std::list<std::unique_ptr<ParamRegFinalizerBase_>> finalizers;
207 static Storage_& storage_()
217 const Dune::ParameterTree& tree,
218 const std::string& prefix =
"");
227 int lastBreakPos = 0;
229 for (; inPos < int(msg.size()); ++ inPos, ++ ttyPos) {
230 if (msg[inPos] ==
'\n') {
231 result += msg.substr(startInPos, inPos - startInPos + 1);
232 startInPos = inPos + 1;
233 lastBreakPos = startInPos + 1;
240 if (std::isspace(msg[inPos]))
241 lastBreakPos = inPos;
243 if (ttyPos >= maxWidth) {
244 if (lastBreakPos > startInPos) {
245 result += msg.substr(startInPos, lastBreakPos - startInPos);
246 startInPos = lastBreakPos + 1;
247 lastBreakPos = startInPos;
251 result += msg.substr(startInPos, inPos - startInPos);
253 lastBreakPos = startInPos;
258 for (
int i = 0; i < indentWidth; ++i)
260 ttyPos = indentWidth;
264 result += msg.substr(startInPos);
271 int ttyWidth = 10*1000;
272 if (isatty(STDOUT_FILENO)) {
273#if defined TIOCGWINSZ
275 struct winsize ttySize;
276 ioctl(STDOUT_FILENO, TIOCGWINSZ, &ttySize);
277 ttyWidth = std::max<int>(80, ttySize.ws_col);
289 std::string paramMessage, paramType, paramDescription;
294 std::string cmdLineName =
"-";
295 const std::string camelCaseName = paramInfo.
paramName;
296 for (
unsigned i = 0; i < camelCaseName.size(); ++i) {
297 if (isupper(camelCaseName[i]))
299 cmdLineName +=
static_cast<char>(std::tolower(camelCaseName[i]));
304 paramMessage += cmdLineName;
307 bool isString =
false;
308 if (paramInfo.
paramTypeName == Dune::className<std::string>()
311 paramMessage +=
"=STRING";
321 paramMessage +=
"=SCALAR";
323 || paramInfo.
paramTypeName == Dune::className<unsigned int>()
325 || paramInfo.
paramTypeName == Dune::className<unsigned short>())
326 paramMessage +=
"=INTEGER";
328 paramMessage +=
"=BOOLEAN";
334 paramMessage +=
"=VALUE";
339 while (paramMessage.size() < 50)
348 if (paramMessage.back() !=
'.')
350 paramMessage +=
" Default: ";
353 paramMessage +=
"false";
355 paramMessage +=
"true";
358 paramMessage +=
"\"";
360 paramMessage +=
"\"";
366 paramMessage =
breakLines_(paramMessage, 52, ttyWidth);
367 paramMessage +=
"\n";
374 const Dune::ParameterTree& tree,
375 const std::string& prefix)
378 for (
const auto& valueKey : tree.getValueKeys()) {
379 std::string newKey(prefix + valueKey);
380 dest.push_back(newKey);
384 for (
const auto& subKey : tree.getSubKeys()) {
385 std::string newPrefix(prefix + subKey +
'.');
392 const std::list<std::string>& keyList,
393 bool printDefaults =
false)
397 for (
const auto& key : keyList) {
399 const std::string& defaultValue = paramInfo.defaultValue;
400 std::string value = defaultValue;
401 if (tree.hasKey(key))
402 value = tree.get(key,
"");
403 os << key <<
"=\"" << value <<
"\"";
405 os <<
" # default: \"" << defaultValue <<
"\"";
422 const std::string& errorMsg =
"",
423 std::ostream& os = std::cerr,
424 const bool showAll =
false)
426 if (!errorMsg.empty()) {
427 os << errorMsg <<
"\n\n";
433 os <<
"Recognized options:\n";
435 if (!helpPreamble.empty()) {
438 pInfo.
usageString =
"Print this help message and exit";
441 pInfo.
usageString =
"Print all parameters, including obsolete, hidden and deprecated ones.";
446 if (showAll || !param.second.isHidden)
452inline int noPositionalParameters_(std::set<std::string>&,
453 std::string& errorMsg,
459 errorMsg = std::string(
"Illegal parameter \"")+argv[paramIdx]+
"\".";
469 for (i = 0; i < s.size(); ++ i)
470 if (!std::isspace(s[i]))
476 bool capitalizeFirstLetter =
true,
477 const std::string& errorPrefix =
"")
482 throw std::runtime_error(errorPrefix+
"Empty parameter names are invalid");
484 if (!std::isalpha(s[0]))
485 throw std::runtime_error(errorPrefix+
"Parameter name '" + s +
"' is invalid: First character must be a letter");
487 if (capitalizeFirstLetter)
488 result +=
static_cast<char>(std::toupper(s[0]));
492 for (
unsigned i = 1; i < s.size(); ++i) {
495 if (s.size() <= i || !std::isalpha(s[i]))
496 throw std::runtime_error(errorPrefix+
"Invalid parameter name '" + s +
"'");
497 result +=
static_cast<char>(std::toupper(s[i]));
499 else if (!std::isalnum(s[i]))
500 throw std::runtime_error(errorPrefix+
"Invalid parameter name '" + s +
"'");
511 for (i = 0; i < s.size(); ++ i)
512 if (std::isspace(s[i]) || s[i] ==
'=')
515 std::string ret = s.substr(0, i);
523 if (s.empty() || s[0] !=
'"')
524 throw std::runtime_error(errorPrefix+
"Expected quoted string");
528 for (; i < s.size(); ++i) {
533 throw std::runtime_error(errorPrefix+
"Unexpected end of quoted string");
537 else if (s[i] ==
'r')
539 else if (s[i] ==
't')
541 else if (s[i] ==
'"')
543 else if (s[i] ==
'\\')
546 throw std::runtime_error(errorPrefix+
"Unknown escape character '\\" + s[i] +
"'");
548 else if (s[i] ==
'"')
561 for (i = 0; i < s.size(); ++ i)
562 if (std::isspace(s[i]))
565 std::string ret = s.substr(0, i);
586template <
class PositionalArgumentCallback>
589 const std::string& helpPreamble =
"",
590 const PositionalArgumentCallback& posArgCallback = noPositionalParameters_)
593 if (!helpPreamble.empty()) {
594 for (
int i = 1; i < argc; ++i) {
595 if (std::string(
"-h") == argv[i]
596 || std::string(
"--help") == argv[i]) {
598 return "Help called";
600 if (std::string(
"--help-all") == argv[i]) {
601 printUsage(helpPreamble,
"", std::cout,
true);
602 return "Help called";
607 std::set<std::string> seenKeys;
608 int numPositionalParams = 0;
609 for (
int i = 1; i < argc; ++i) {
611 if (strlen(argv[i]) < 4
613 || argv[i][1] !=
'-')
615 std::string errorMsg;
616 int numHandled = posArgCallback(seenKeys, errorMsg, argc, argv,
617 i, numPositionalParams);
619 if (numHandled < 1) {
620 std::ostringstream oss;
622 if (!helpPreamble.empty())
623 printUsage(helpPreamble, errorMsg, std::cerr);
628 ++ numPositionalParams;
634 std::string paramName, paramValue;
641 if (argv[i][2] == 0 || !std::isalpha(argv[i][2])) {
642 std::ostringstream oss;
643 oss <<
"Parameter name of argument " << i
644 <<
" ('" << argv[i] <<
"') "
645 <<
"is invalid because it does not start with a letter.";
647 if (!helpPreamble.empty())
648 printUsage(helpPreamble, oss.str(), std::cerr);
654 std::string s(argv[i] + 2);
658 if (seenKeys.count(paramName) > 0) {
660 std::string(
"Parameter '")+paramName+
"' specified multiple times as a "
661 "command line parameter";
663 if (!helpPreamble.empty())
667 seenKeys.insert(paramName);
669 if (s.empty() || s[0] !=
'=') {
671 std::string(
"Parameter '")+paramName+
"' is missing a value. "
672 +
" Please use "+argv[i]+
"=value.";
674 if (!helpPreamble.empty())
679 paramValue = s.substr(1);
695 std::set<std::string> seenKeys;
696 std::ifstream ifs(fileName);
697 unsigned curLineNum = 0;
701 std::getline(ifs, curLine);
703 std::string errorPrefix = fileName+
":"+std::to_string(curLineNum)+
": ";
709 if (curLine.empty() || curLine[0] ==
'#' || curLine[0] ==
';')
716 std::string canonicalKey =
transformKey_(key,
true, errorPrefix);
718 if (seenKeys.count(canonicalKey) > 0)
719 throw std::runtime_error(errorPrefix+
"Parameter '"+canonicalKey+
"' seen multiple times in the same file");
720 seenKeys.insert(canonicalKey);
724 if (curLine.empty() || curLine[0] !=
'=')
725 std::runtime_error(errorPrefix+
"Syntax error, expecting 'key=value'");
727 curLine = curLine.substr(1);
730 if (curLine.empty() || curLine[0] ==
'#' || curLine[0] ==
';')
731 std::runtime_error(errorPrefix+
"Syntax error, expecting 'key=value'");
735 if (curLine[0] ==
'"')
742 if (!curLine.empty() && curLine[0] !=
'#' && curLine[0] !=
';')
743 std::runtime_error(errorPrefix+
"Syntax error, expecting 'key=value'");
760 std::list<std::string> runTimeAllKeyList;
761 std::list<std::string> runTimeKeyList;
762 std::list<std::string> unknownKeyList;
765 for (
const auto& key : runTimeAllKeyList) {
768 unknownKeyList.push_back(key);
772 runTimeKeyList.push_back(key);
777 std::list<std::string> compileTimeKeyList;
783 compileTimeKeyList.push_back(reg.first);
789 if (runTimeKeyList.size() > 0) {
790 os <<
"# [known parameters which were specified at run-time]\n";
794 if (compileTimeKeyList.size() > 0) {
795 os <<
"# [parameters which were specified at compile-time]\n";
799 if (unknownKeyList.size() > 0) {
800 os <<
"# [unused run-time specified parameters]\n";
801 for (
const auto& unused : unknownKeyList) {
802 os << unused <<
"=\"" <<
MetaData::tree().get(unused,
"") <<
"\"\n" << std::flush;
817 std::list<std::string> runTimeAllKeyList;
818 std::list<std::string> unknownKeyList;
821 for (
const auto& key : runTimeAllKeyList) {
824 unknownKeyList.push_back(key);
828 if (unknownKeyList.size() > 0) {
829 os <<
"# [unused run-time specified parameters]\n";
830 for (
const auto& unused : unknownKeyList) {
831 os << unused <<
"=\""
839template <
class Param>
840auto Get(
bool errorIfNotRegistered)
842 const std::string paramName = detail::getParamName<Param>();
843 if (errorIfNotRegistered) {
845 throw std::runtime_error(
"Parameters can only retrieved after _all_ of them have "
849 throw std::runtime_error(
"Accessing parameter " + paramName
850 +
" without prior registration is not allowed.");
854 using ParamType = std::conditional_t<std::is_same_v<
decltype(Param::value),
855 const char*
const>, std::string,
856 std::remove_const_t<
decltype(Param::value)>>;
857 ParamType defaultValue = Param::value;
860 if constexpr (std::is_same_v<ParamType, std::string>) {
861 defaultValue = defVal;
863 else if constexpr (std::is_same_v<ParamType, bool>) {
864 defaultValue = defVal ==
"1";
867 else if constexpr (std::is_same_v<ParamType, quad>) {
868 defaultValue = std::strtold(defVal.data(),
nullptr);
871#if !HAVE_FLOATING_POINT_FROM_CHARS
872 else if constexpr (std::is_floating_point_v<ParamType>) {
873 defaultValue = std::strtod(defVal.c_str(),
nullptr);
877 std::from_chars(defVal.data(), defVal.data() + defVal.size(), defaultValue);
887 return MetaData::tree().template get<ParamType>(paramName, defaultValue);
890template <
class Param>
893 const std::string paramName = detail::getParamName<Param>();
895 throw std::runtime_error(
"Accessing parameter " + paramName +
896 " without prior registration is not allowed.");
898 std::ostringstream oss;
909template <
class Container>
910void getLists(Container& usedParams, Container& unusedParams)
913 unusedParams.clear();
916 throw std::runtime_error(
"Parameter lists can only retrieved after _all_ of them have "
921 std::list<std::string> allKeysList;
924 for (
const auto& key : allKeysList) {
947template <
class Param>
948bool IsSet(
bool errorIfNotRegistered =
true)
950 const std::string paramName = detail::getParamName<Param>();
952 if (errorIfNotRegistered) {
954 throw std::runtime_error(
"Parameters can only checked after _all_ of them have "
959 throw std::runtime_error(
"Accessing parameter " + std::string(paramName) +
960 " without prior registration is not allowed.");
983template <
class Param>
986 const std::string paramName = detail::getParamName<Param>();
988 throw std::logic_error(
"Parameter registration was already closed before "
989 "the parameter '" + paramName +
"' was registered.");
992 const auto defaultValue = Param::value;
993 using ParamType = std::conditional_t<std::is_same_v<
decltype(defaultValue),
994 const char*
const>, std::string,
995 std::remove_const_t<
decltype(defaultValue)>>;
1003 std::ostringstream oss;
1004 oss << defaultValue;
1013 throw std::logic_error(
"Parameter " + paramName
1014 +
" registered twice with non-matching characteristics.");
1026template <
class Param>
1029 const std::string paramName = detail::getParamName<Param>();
1031 throw std::logic_error(
"Parameter '" +paramName +
"' declared as hidden"
1032 " when parameter registration was already closed.");
1037 throw std::logic_error(
"Tried to declare unknown parameter '"
1038 + paramName +
"' hidden.");
1041 auto& paramInfo = paramInfoIt->second;
1042 paramInfo.isHidden =
true;
1055 throw std::logic_error(
"Parameter registration was already closed. It is only possible "
1056 "to close it once.");
Definition: parametersystem.hh:151
void retrieve() override
Definition: parametersystem.hh:153
Definition: parametersystem.hh:142
virtual void retrieve()=0
virtual ~ParamRegFinalizerBase_()
Definition: parametersystem.hh:144
bool printUnused(std::ostream &os=std::cout)
Print the list of unused run-time parameters.
Definition: parametersystem.hh:815
auto SetDefault(decltype(Param::value) new_value)
Set a runtime parameter.
Definition: parametersystem.hh:891
void printUsage(const std::string &helpPreamble, const std::string &errorMsg="", std::ostream &os=std::cerr, const bool showAll=false)
Print a usage message for all run-time parameters.
Definition: parametersystem.hh:421
void Register(const char *usageString)
Register a run-time parameter.
Definition: parametersystem.hh:984
void parseParameterFile(const std::string &fileName, bool overwrite=true)
Read the parameters from an INI-style file.
Definition: parametersystem.hh:693
std::string parseCommandLineOptions(int argc, const char **argv, const std::string &helpPreamble="", const PositionalArgumentCallback &posArgCallback=noPositionalParameters_)
Parse the parameters provided on the command line.
Definition: parametersystem.hh:587
void printValues(std::ostream &os=std::cout)
Print values of the run-time parameters.
Definition: parametersystem.hh:758
auto Get(bool errorIfNotRegistered=true)
Retrieve a runtime parameter.
Definition: parametersystem.hh:840
auto getParamName()
get the name data member of a parameter
Definition: parametersystem.hh:71
Definition: blackoilnewtonmethodparameters.hh:31
std::string parseUnquotedValue_(std::string &s, const std::string &)
Definition: parametersystem.hh:558
void removeLeadingSpace_(std::string &s)
Definition: parametersystem.hh:466
int getTtyWidth_()
Definition: parametersystem.hh:269
bool IsSet(bool errorIfNotRegistered=true)
Returns true if a parameter has been specified at runtime, false otherwise.
Definition: parametersystem.hh:948
void printParamList_(std::ostream &os, const std::list< std::string > &keyList, bool printDefaults=false)
Definition: parametersystem.hh:391
std::string parseQuotedValue_(std::string &s, const std::string &errorPrefix)
Definition: parametersystem.hh:521
void printParamUsage_(std::ostream &os, const ParamInfo ¶mInfo)
Definition: parametersystem.hh:287
void endRegistration()
Indicate that all parameters are registered for a given type tag.
Definition: parametersystem.hh:1052
std::string breakLines_(const std::string &msg, int indentWidth, int maxWidth)
Definition: parametersystem.hh:220
void reset()
Definition: parametersystem.hh:936
std::string transformKey_(const std::string &s, bool capitalizeFirstLetter=true, const std::string &errorPrefix="")
Definition: parametersystem.hh:475
void Hide()
Indicate that a given parameter should not be mentioned in the help message.
Definition: parametersystem.hh:1027
void getLists(Container &usedParams, Container &unusedParams)
Retrieves the lists of parameters specified at runtime and their values.
Definition: parametersystem.hh:910
std::string parseKey_(std::string &s)
Definition: parametersystem.hh:508
void getFlattenedKeyList_(std::list< std::string > &dest, const Dune::ParameterTree &tree, const std::string &prefix="")
Definition: parametersystem.hh:373
Definition: parametersystem.hh:89
bool operator==(const ParamInfo &other) const
Definition: parametersystem.hh:97
std::string usageString
Definition: parametersystem.hh:93
std::string typeTagName
Definition: parametersystem.hh:92
bool isHidden
Definition: parametersystem.hh:95
std::string paramTypeName
Definition: parametersystem.hh:91
std::string paramName
Definition: parametersystem.hh:90
std::string defaultValue
Definition: parametersystem.hh:94
Definition: parametersystem.hh:63