parametersystem.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*
4 This file is part of the Open Porous Media project (OPM).
5
6 OPM is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
10
11 OPM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with OPM. If not, see <http://www.gnu.org/licenses/>.
18
19 Consult the COPYING file in the top-level source directory of this
20 module for the precise wording of the license and the list of
21 copyright holders.
22*/
32#ifndef OPM_PARAMETER_SYSTEM_HH
33#define OPM_PARAMETER_SYSTEM_HH
34
36
37#if HAVE_QUAD
38#include <opm/material/common/quad.hpp>
39#endif // HAVE_QUAD
40
41#include <dune/common/classname.hh>
42#include <dune/common/parametertree.hh>
43
44#include <fstream>
45#include <iostream>
46#include <list>
47#include <map>
48#include <set>
49#include <sstream>
50#include <stdexcept>
51#include <string>
52#include <tuple>
53#include <type_traits>
54
55#include <unistd.h>
56#include <sys/ioctl.h>
57
58namespace Opm {
59namespace Parameters {
60
62{
63 std::string paramName;
64 std::string paramTypeName;
65 std::string typeTagName;
66 std::string usageString;
67 std::string compileTimeValue;
69
70 bool operator==(const ParamInfo& other) const
71 {
72 return other.paramName == paramName
74 && other.typeTagName == typeTagName
75 && other.usageString == usageString
77 }
78};
79
95template <class TypeTag, template<class,class> class Property>
96auto get(bool errorIfNotRegistered = true);
97
99{
100public:
102 {}
103 virtual void retrieve() = 0;
104};
105
106template <class TypeTag, template<class,class> class Property>
108{
109public:
110 void retrieve() override
111 {
112 // retrieve the parameter once to make sure that its value does
113 // not contain a syntax error.
114 std::ignore = get<TypeTag, Property>(/*errorIfNotRegistered=*/true);
115 }
116};
117} // namespace Parameters
118
119} // namespace Opm
120
121namespace Opm::Properties {
122
123namespace TTag {
124
125// type tag which is supposed to spliced in or inherited from if the
126// parameter system is to be used
128
129} // namespace TTag
130
131template<class TypeTag, class MyTypeTag>
133
134
136template<class TypeTag>
137struct ParameterMetaData<TypeTag, TTag::ParameterSystem>
138{
139 using type = Dune::ParameterTree;
140
141 static Dune::ParameterTree& tree()
142 { return *storage_().tree; }
143
144 static std::map<std::string, ::Opm::Parameters::ParamInfo>& mutableRegistry()
145 { return storage_().registry; }
146
147 static const std::map<std::string, ::Opm::Parameters::ParamInfo>& registry()
148 { return storage_().registry; }
149
150 static std::list<std::unique_ptr<::Opm::Parameters::ParamRegFinalizerBase_> > &registrationFinalizers()
151 { return storage_().finalizers; }
152
153 static bool& registrationOpen()
154 { return storage_().registrationOpen; }
155
156 static void clear()
157 {
158 storage_().tree.reset(new Dune::ParameterTree());
159 storage_().finalizers.clear();
160 storage_().registrationOpen = true;
161 storage_().registry.clear();
162 }
163
164private:
165 // this is not pretty, but handling these attributes as static variables inside
166 // member functions of the ParameterMetaData property class triggers a bug in clang
167 // 3.5's address sanitizer which causes these variables to be initialized multiple
168 // times...
169 struct Storage_ {
170 Storage_()
171 {
172 tree.reset(new Dune::ParameterTree());
173 registrationOpen = true;
174 }
175
176 std::unique_ptr<Dune::ParameterTree> tree;
177 std::map<std::string, ::Opm::Parameters::ParamInfo> registry;
178 std::list<std::unique_ptr<::Opm::Parameters::ParamRegFinalizerBase_> > finalizers;
179 bool registrationOpen;
180 };
181 static Storage_& storage_() {
182 static Storage_ obj;
183 return obj;
184 }
185};
186
187} // namespace Opm::Properties
188
189namespace Opm::Parameters {
190
191// function prototype declarations
192void printParamUsage_(std::ostream& os, const ParamInfo& paramInfo);
193void getFlattenedKeyList_(std::list<std::string>& dest,
194 const Dune::ParameterTree& tree,
195 const std::string& prefix = "");
196
197inline std::string breakLines_(const std::string& msg,
198 int indentWidth,
199 int maxWidth)
200{
201 std::string result;
202 int startInPos = 0;
203 int inPos = 0;
204 int lastBreakPos = 0;
205 int ttyPos = 0;
206 for (; inPos < int(msg.size()); ++ inPos, ++ ttyPos) {
207 if (msg[inPos] == '\n') {
208 result += msg.substr(startInPos, inPos - startInPos + 1);
209 startInPos = inPos + 1;
210 lastBreakPos = startInPos + 1;
211
212 // we need to use -1 here because ttyPos is incremented after the loop body
213 ttyPos = -1;
214 continue;
215 }
216
217 if (std::isspace(msg[inPos]))
218 lastBreakPos = inPos;
219
220 if (ttyPos >= maxWidth) {
221 if (lastBreakPos > startInPos) {
222 result += msg.substr(startInPos, lastBreakPos - startInPos);
223 startInPos = lastBreakPos + 1;
224 lastBreakPos = startInPos;
225 inPos = startInPos;
226 }
227 else {
228 result += msg.substr(startInPos, inPos - startInPos);
229 startInPos = inPos;
230 lastBreakPos = startInPos;
231 inPos = startInPos;
232 }
233
234 result += "\n";
235 for (int i = 0; i < indentWidth; ++i)
236 result += " ";
237 ttyPos = indentWidth;
238 }
239 }
240
241 result += msg.substr(startInPos);
242
243 return result;
244}
245
246inline int getTtyWidth_()
247{
248 int ttyWidth = 10*1000; // effectively do not break lines at all.
249 if (isatty(STDOUT_FILENO)) {
250#if defined TIOCGWINSZ
251 // This is a bit too linux specific, IMO. let's do it anyway
252 struct winsize ttySize;
253 ioctl(STDOUT_FILENO, TIOCGWINSZ, &ttySize);
254 ttyWidth = std::max<int>(80, ttySize.ws_col);
255#else
256 // default for systems that do not implement the TIOCGWINSZ ioctl
257 ttyWidth = 100;
258#endif
259 }
260
261 return ttyWidth;
262}
263
264inline void printParamUsage_(std::ostream& os, const ParamInfo& paramInfo)
265{
266 std::string paramMessage, paramType, paramDescription;
267
268 int ttyWidth = getTtyWidth_();
269
270 // convert the CamelCase name to a command line --parameter-name.
271 std::string cmdLineName = "-";
272 const std::string camelCaseName = paramInfo.paramName;
273 for (unsigned i = 0; i < camelCaseName.size(); ++i) {
274 if (isupper(camelCaseName[i]))
275 cmdLineName += "-";
276 cmdLineName += static_cast<char>(std::tolower(camelCaseName[i]));
277 }
278
279 // assemble the printed output
280 paramMessage = " ";
281 paramMessage += cmdLineName;
282
283 // add the =VALUE_TYPE part
284 bool isString = false;
285 if (paramInfo.paramTypeName == Dune::className<std::string>()
286 || paramInfo.paramTypeName == "const char *")
287 {
288 paramMessage += "=STRING";
289 isString = true;
290 }
291 else if (paramInfo.paramTypeName == Dune::className<float>()
292 || paramInfo.paramTypeName == Dune::className<double>()
293 || paramInfo.paramTypeName == Dune::className<long double>()
294#if HAVE_QUAD
295 || paramInfo.paramTypeName == Dune::className<quad>()
296#endif // HAVE_QUAD
297 )
298 paramMessage += "=SCALAR";
299 else if (paramInfo.paramTypeName == Dune::className<int>()
300 || paramInfo.paramTypeName == Dune::className<unsigned int>()
301 || paramInfo.paramTypeName == Dune::className<short>()
302 || paramInfo.paramTypeName == Dune::className<unsigned short>())
303 paramMessage += "=INTEGER";
304 else if (paramInfo.paramTypeName == Dune::className<bool>())
305 paramMessage += "=BOOLEAN";
306 else if (paramInfo.paramTypeName.empty()) {
307 // the parameter is a flag. Do nothing!
308 }
309 else {
310 // unknown type
311 paramMessage += "=VALUE";
312 }
313
314 // fill up the up help string to the 50th character
315 paramMessage += " ";
316 while (paramMessage.size() < 50)
317 paramMessage += " ";
318
319
320 // append the parameter usage string.
321 paramMessage += paramInfo.usageString;
322
323 // add the default value
324 if (!paramInfo.paramTypeName.empty()) {
325 if (paramMessage.back() != '.')
326 paramMessage += '.';
327 paramMessage += " Default: ";
328 if (paramInfo.paramTypeName == "bool") {
329 if (paramInfo.compileTimeValue == "0")
330 paramMessage += "false";
331 else
332 paramMessage += "true";
333 }
334 else if (isString) {
335 paramMessage += "\"";
336 paramMessage += paramInfo.compileTimeValue;
337 paramMessage += "\"";
338 }
339 else
340 paramMessage += paramInfo.compileTimeValue;
341 }
342
343 paramMessage = breakLines_(paramMessage, /*indent=*/52, ttyWidth);
344 paramMessage += "\n";
345
346 // print everything
347 os << paramMessage;
348}
349
350inline void getFlattenedKeyList_(std::list<std::string>& dest,
351 const Dune::ParameterTree& tree,
352 const std::string& prefix)
353{
354 // add the keys of the current sub-structure
355 for (const auto& valueKey : tree.getValueKeys()) {
356 std::string newKey(prefix + valueKey);
357 dest.push_back(newKey);
358 }
359
360 // recursively add all substructure keys
361 for (const auto& subKey : tree.getSubKeys()) {
362 std::string newPrefix(prefix + subKey + '.');
363 getFlattenedKeyList_(dest, tree.sub(subKey), newPrefix);
364 }
365}
366
367// print the values of a list of parameters
368template <class TypeTag>
369void printParamList_(std::ostream& os, const std::list<std::string>& keyList, bool printDefaults = false)
370{
372
373 const Dune::ParameterTree& tree = ParamsMeta::tree();
374
375 for (const auto& key : keyList) {
376 const auto& paramInfo = ParamsMeta::registry().at(key);
377 const std::string& defaultValue = paramInfo.compileTimeValue;
378 std::string value = defaultValue;
379 if (tree.hasKey(key))
380 value = tree.get(key, "");
381 os << key << "=\"" << value << "\"";
382 if (printDefaults)
383 os << " # default: \"" << defaultValue << "\"";
384 os << "\n";
385 }
386}
387
389
399template <class TypeTag>
400void printUsage(const std::string& helpPreamble,
401 const std::string& errorMsg = "",
402 std::ostream& os = std::cerr,
403 const bool showAll = false)
404{
406
407 if (errorMsg != "") {
408 os << errorMsg << "\n"
409 << "\n";
410 }
411
412 os << breakLines_(helpPreamble, /*indent=*/2, /*maxWidth=*/getTtyWidth_());
413 os << "\n";
414
415 os << "Recognized options:\n";
416
417 if (!helpPreamble.empty()) {
418 ParamInfo pInfo;
419 pInfo.paramName = "h,--help";
420 pInfo.usageString = "Print this help message and exit";
421 printParamUsage_(os, pInfo);
422 pInfo.paramName = "-help-all";
423 pInfo.usageString = "Print all parameters, including obsolete, hidden and deprecated ones.";
424 printParamUsage_(os, pInfo);
425 }
426
427 auto paramIt = ParamsMeta::registry().begin();
428 const auto& paramEndIt = ParamsMeta::registry().end();
429 for (; paramIt != paramEndIt; ++paramIt) {
430 if (showAll || !paramIt->second.isHidden)
431 printParamUsage_(os, paramIt->second);
432 }
433}
434
436inline int noPositionalParameters_(std::set<std::string>&,
437 std::string& errorMsg,
438 int,
439 const char** argv,
440 int paramIdx,
441 int)
442{
443 errorMsg = std::string("Illegal parameter \"")+argv[paramIdx]+"\".";
444 return 0;
445}
446
448
449
450inline void removeLeadingSpace_(std::string& s)
451{
452 unsigned i;
453 for (i = 0; i < s.size(); ++ i)
454 if (!std::isspace(s[i]))
455 break;
456 s = s.substr(i);
457}
458
459inline std::string transformKey_(const std::string& s,
460 bool capitalizeFirstLetter = true,
461 const std::string& errorPrefix = "")
462{
463 std::string result;
464
465 if (s.empty())
466 throw std::runtime_error(errorPrefix+"Empty parameter names are invalid");
467
468 if (!std::isalpha(s[0]))
469 throw std::runtime_error(errorPrefix+"Parameter name '" + s + "' is invalid: First character must be a letter");
470
471 if (capitalizeFirstLetter)
472 result += static_cast<char>(std::toupper(s[0]));
473 else
474 result += s[0];
475
476 for (unsigned i = 1; i < s.size(); ++i) {
477 if (s[i] == '-') {
478 ++ i;
479 if (s.size() <= i || !std::isalpha(s[i]))
480 throw std::runtime_error(errorPrefix+"Invalid parameter name '" + s + "'");
481 result += static_cast<char>(std::toupper(s[i]));
482 }
483 else if (!std::isalnum(s[i]))
484 throw std::runtime_error(errorPrefix+"Invalid parameter name '" + s + "'");
485 else
486 result += s[i];
487 }
488
489 return result;
490}
491
492inline std::string parseKey_(std::string& s)
493{
494 unsigned i;
495 for (i = 0; i < s.size(); ++ i)
496 if (std::isspace(s[i]) || s[i] == '=')
497 break;
498
499 std::string ret = s.substr(0, i);
500 s = s.substr(i);
501 return ret;
502}
503
504// parse a quoted string
505inline std::string parseQuotedValue_(std::string& s, const std::string& errorPrefix)
506{
507 if (s.empty() || s[0] != '"')
508 throw std::runtime_error(errorPrefix+"Expected quoted string");
509
510 std::string result;
511 unsigned i = 1;
512 for (; i < s.size(); ++i) {
513 // handle escape characters
514 if (s[i] == '\\') {
515 ++ i;
516 if (s.size() <= i)
517 throw std::runtime_error(errorPrefix+"Unexpected end of quoted string");
518
519 if (s[i] == 'n')
520 result += '\n';
521 else if (s[i] == 'r')
522 result += '\r';
523 else if (s[i] == 't')
524 result += '\t';
525 else if (s[i] == '"')
526 result += '"';
527 else if (s[i] == '\\')
528 result += '\\';
529 else
530 throw std::runtime_error(errorPrefix+"Unknown escape character '\\" + s[i] + "'");
531 }
532 else if (s[i] == '"')
533 break;
534 else
535 result += s[i];
536 }
537
538 s = s.substr(i+1);
539 return result;
540}
541
542inline std::string parseUnquotedValue_(std::string& s, const std::string&)
543{
544 unsigned i;
545 for (i = 0; i < s.size(); ++ i)
546 if (std::isspace(s[i]))
547 break;
548
549 std::string ret = s.substr(0, i);
550 s = s.substr(i);
551 return ret;
552}
553
570template <class TypeTag, class PositionalArgumentCallback>
571std::string parseCommandLineOptions(int argc,
572 const char **argv,
573 const std::string& helpPreamble = "",
574 const PositionalArgumentCallback& posArgCallback = noPositionalParameters_)
575{
576 Dune::ParameterTree& paramTree = GetProp<TypeTag, Properties::ParameterMetaData>::tree();
577
578 // handle the "--help" parameter
579 if (!helpPreamble.empty()) {
580 for (int i = 1; i < argc; ++i) {
581 if (std::string("-h") == argv[i]
582 || std::string("--help") == argv[i]) {
583 printUsage<TypeTag>(helpPreamble, /*errorMsg=*/"", std::cout);
584 return "Help called";
585 }
586 if (std::string("--help-all") == argv[i]) {
587 printUsage<TypeTag>(helpPreamble, /*errorMsg=*/"", std::cout, true);
588 return "Help called";
589 }
590 }
591 }
592
593 std::set<std::string> seenKeys;
594 int numPositionalParams = 0;
595 for (int i = 1; i < argc; ++i) {
596 // All non-positional command line options need to start with '-'
597 if (strlen(argv[i]) < 4
598 || argv[i][0] != '-'
599 || argv[i][1] != '-')
600 {
601 std::string errorMsg;
602 int numHandled = posArgCallback(seenKeys, errorMsg, argc, argv, i, numPositionalParams);
603
604 if (numHandled < 1) {
605 std::ostringstream oss;
606
607 if (!helpPreamble.empty())
608 printUsage<TypeTag>(helpPreamble, errorMsg, std::cerr);
609
610 return errorMsg;
611 }
612 else {
613 ++ numPositionalParams;
614 i += numHandled - 1;
615 continue;
616 }
617 }
618
619 std::string paramName, paramValue;
620
621 // read a --my-opt=abc option. This gets transformed
622 // into the parameter "MyOpt" with the value being
623 // "abc"
624
625 // There is nothing after the '-'
626 if (argv[i][2] == 0 || !std::isalpha(argv[i][2])) {
627 std::ostringstream oss;
628 oss << "Parameter name of argument " << i
629 << " ('" << argv[i] << "') "
630 << "is invalid because it does not start with a letter.";
631
632 if (!helpPreamble.empty())
633 printUsage<TypeTag>(helpPreamble, oss.str(), std::cerr);
634
635 return oss.str();
636 }
637
638 // copy everything after the "--" into a separate string
639 std::string s(argv[i] + 2);
640
641 // parse argument
642 paramName = transformKey_(parseKey_(s), /*capitalizeFirst=*/true);
643 if (seenKeys.count(paramName) > 0) {
644 std::string msg =
645 std::string("Parameter '")+paramName+"' specified multiple times as a "
646 "command line parameter";
647
648 if (!helpPreamble.empty())
649 printUsage<TypeTag>(helpPreamble, msg, std::cerr);
650 return msg;
651 }
652 seenKeys.insert(paramName);
653
654 if (s.empty() || s[0] != '=') {
655 std::string msg =
656 std::string("Parameter '")+paramName+"' is missing a value. "
657 +" Please use "+argv[i]+"=value.";
658
659 if (!helpPreamble.empty())
660 printUsage<TypeTag>(helpPreamble, msg, std::cerr);
661 return msg;
662 }
663
664 paramValue = s.substr(1);
665
666 // Put the key=value pair into the parameter tree
667 paramTree[paramName] = paramValue;
668 }
669 return "";
670}
671
678template <class TypeTag>
679void parseParameterFile(const std::string& fileName, bool overwrite = true)
680{
681 Dune::ParameterTree& paramTree = GetProp<TypeTag, Properties::ParameterMetaData>::tree();
682
683 std::set<std::string> seenKeys;
684 std::ifstream ifs(fileName);
685 unsigned curLineNum = 0;
686 while (ifs) {
687 // string and file processing in c++ is quite blunt!
688 std::string curLine;
689 std::getline(ifs, curLine);
690 curLineNum += 1;
691 std::string errorPrefix = fileName+":"+std::to_string(curLineNum)+": ";
692
693 // strip leading white space
694 removeLeadingSpace_(curLine);
695
696 // ignore empty and comment lines
697 if (curLine.empty() || curLine[0] == '#' || curLine[0] == ';')
698 continue;
699
700 // TODO (?): support for parameter groups.
701
702 // find the "key" of the key=value pair
703 std::string key = parseKey_(curLine);
704 std::string canonicalKey = transformKey_(key, /*capitalizeFirst=*/true, errorPrefix);
705
706 if (seenKeys.count(canonicalKey) > 0)
707 throw std::runtime_error(errorPrefix+"Parameter '"+canonicalKey+"' seen multiple times in the same file");
708 seenKeys.insert(canonicalKey);
709
710 // deal with the equals sign
711 removeLeadingSpace_(curLine);
712 if (curLine.empty() || curLine[0] != '=')
713 std::runtime_error(errorPrefix+"Syntax error, expecting 'key=value'");
714
715 curLine = curLine.substr(1);
716 removeLeadingSpace_(curLine);
717
718 if (curLine.empty() || curLine[0] == '#' || curLine[0] == ';')
719 std::runtime_error(errorPrefix+"Syntax error, expecting 'key=value'");
720
721 // get the value
722 std::string value;
723 if (curLine[0] == '"')
724 value = parseQuotedValue_(curLine, errorPrefix);
725 else
726 value = parseUnquotedValue_(curLine, errorPrefix);
727
728 // ignore trailing comments
729 removeLeadingSpace_(curLine);
730 if (!curLine.empty() && curLine[0] != '#' && curLine[0] != ';')
731 std::runtime_error(errorPrefix+"Syntax error, expecting 'key=value'");
732
733 // all went well, add the parameter to the database object
734 if (overwrite || !paramTree.hasKey(canonicalKey))
735 paramTree[canonicalKey] = value;
736 }
737}
738
745template <class TypeTag>
746void printValues(std::ostream& os = std::cout)
747{
749
750 const Dune::ParameterTree& tree = ParamsMeta::tree();
751
752 std::list<std::string> runTimeAllKeyList;
753 std::list<std::string> runTimeKeyList;
754 std::list<std::string> unknownKeyList;
755
756 getFlattenedKeyList_(runTimeAllKeyList, tree);
757 for (const auto& key : runTimeAllKeyList) {
758 if (ParamsMeta::registry().find(key) == ParamsMeta::registry().end()) {
759 // key was not registered by the program!
760 unknownKeyList.push_back(key);
761 }
762 else {
763 // the key was specified at run-time
764 runTimeKeyList.push_back(key);
765 }
766 }
767
768 // loop over all registered parameters
769 std::list<std::string> compileTimeKeyList;
770 for (const auto& reg : ParamsMeta::registry()) {
771 // check whether the key was specified at run-time
772 if (tree.hasKey(reg.first)) {
773 continue;
774 } else {
775 compileTimeKeyList.push_back(reg.first);
776 }
777 }
778
779 // report the values of all registered (and unregistered)
780 // parameters
781 if (runTimeKeyList.size() > 0) {
782 os << "# [known parameters which were specified at run-time]\n";
783 printParamList_<TypeTag>(os, runTimeKeyList, /*printDefaults=*/true);
784 }
785
786 if (compileTimeKeyList.size() > 0) {
787 os << "# [parameters which were specified at compile-time]\n";
788 printParamList_<TypeTag>(os, compileTimeKeyList, /*printDefaults=*/false);
789 }
790
791 if (unknownKeyList.size() > 0) {
792 os << "# [unused run-time specified parameters]\n";
793 for (const auto& unused : unknownKeyList) {
794 os << unused << "=\"" << tree.get(unused, "") << "\"\n" << std::flush;
795 }
796 }
797}
798
807template <class TypeTag>
808bool printUnused(std::ostream& os = std::cout)
809{
811
812 const Dune::ParameterTree& tree = ParamsMeta::tree();
813 std::list<std::string> runTimeAllKeyList;
814 std::list<std::string> unknownKeyList;
815
816 getFlattenedKeyList_(runTimeAllKeyList, tree);
817 for (const auto& key : runTimeAllKeyList) {
818 if (ParamsMeta::registry().find(key) == ParamsMeta::registry().end()) {
819 // key was not registered by the program!
820 unknownKeyList.push_back(key);
821 }
822 }
823
824 if (unknownKeyList.size() > 0) {
825 os << "# [unused run-time specified parameters]\n";
826 for (const auto& unused : unknownKeyList) {
827 os << unused << "=\"" << tree.get(unused, "") << "\"\n" << std::flush;
828 }
829 return true;
830 }
831 return false;
832}
833
834template <class TypeTag, template<class,class> class Param>
835auto get(bool errorIfNotRegistered)
836{
838 const std::string paramName = getPropName<TypeTag, Param>();
839 const auto defaultValue = getPropValue<TypeTag, Param>();
840 using ParamType = std::conditional_t<std::is_same_v<decltype(defaultValue),
841 const char* const>, std::string,
842 std::remove_const_t<decltype(defaultValue)>>;
843 if (errorIfNotRegistered) {
844 if (ParamsMeta::registrationOpen())
845 throw std::runtime_error("Parameters can only retrieved after _all_ of them have "
846 "been registered.");
847
848 if (ParamsMeta::registry().find(paramName) == ParamsMeta::registry().end())
849 throw std::runtime_error("Accessing parameter " + paramName
850 +" without prior registration is not allowed.");
851 }
852
853 // prefix the parameter name by the model's GroupName. E.g. If
854 // the model specifies its group name to be 'Stokes', in an
855 // INI file this would result in something like:
856 //
857 // [Stokes]
858 // NewtonWriteConvergence = true
859 // retrieve actual parameter from the parameter tree
860 return ParamsMeta::tree().template get<ParamType>(paramName, defaultValue);
861}
862
869template <class TypeTag, class Container>
870void getLists(Container& usedParams, Container& unusedParams)
871{
872 usedParams.clear();
873 unusedParams.clear();
874
876 if (ParamsMeta::registrationOpen())
877 throw std::runtime_error("Parameter lists can only retieved after _all_ of them have "
878 "been registered.");
879
880 // get all parameter keys
881 std::list<std::string> allKeysList;
882 const auto& paramTree = ParamsMeta::tree();
883 getFlattenedKeyList_(allKeysList, paramTree);
884
885 for (const auto& key : allKeysList) {
886 if (ParamsMeta::registry().find(key) == ParamsMeta::registry().end()) {
887 // key was not registered
888 unusedParams.emplace_back(key, paramTree[key]);
889 }
890 else {
891 // key was registered
892 usedParams.emplace_back(key, paramTree[key]);
893 }
894 }
895}
896
897template <class TypeTag>
898void reset()
899{
901 ParamsMeta::clear();
902}
903
910template <class TypeTag, template<class, class> class Param>
911bool isSet(bool errorIfNotRegistered = true)
912{
914 const std::string paramName = getPropName<TypeTag,Param>();
915
916 if (errorIfNotRegistered) {
917 if (ParamsMeta::registrationOpen())
918 throw std::runtime_error("Parameters can only checked after _all_ of them have "
919 "been registered.");
920
921 if (ParamsMeta::registry().find(paramName) == ParamsMeta::registry().end())
922 throw std::runtime_error("Accessing parameter "+std::string(paramName)
923 +" without prior registration is not allowed.");
924 }
925
926 // check whether the parameter is in the parameter tree
927 return ParamsMeta::tree().hasKey(paramName);
928}
929
946template <class TypeTag, template<class,class> class Param>
947void registerParam(const char* usageString)
948{
950 const std::string paramName = getPropName<TypeTag,Param>();
951 if (!ParamsMeta::registrationOpen()) {
952 throw std::logic_error("Parameter registration was already closed before "
953 "the parameter '" + paramName + "' was registered.");
954 }
955
956 const auto defaultValue = getPropValue<TypeTag, Param>();
957 using ParamType = std::conditional_t<std::is_same_v<decltype(defaultValue),
958 const char* const>, std::string,
959 std::remove_const_t<decltype(defaultValue)>>;
960 ParamsMeta::registrationFinalizers().push_back(
961 std::make_unique<ParamRegFinalizer_<TypeTag, Param>>());
962
963 ParamInfo paramInfo;
964 paramInfo.paramName = paramName;
965 paramInfo.paramTypeName = Dune::className<ParamType>();
966 std::string tmp = Dune::className<TypeTag>();
967 tmp.replace(0, strlen("Opm::Properties::TTag::"), "");
968 paramInfo.usageString = usageString;
969 std::ostringstream oss;
970 oss << defaultValue;
971 paramInfo.compileTimeValue = oss.str();
972 paramInfo.isHidden = false;
973 if (ParamsMeta::registry().find(paramName) != ParamsMeta::registry().end()) {
974 // allow to register a parameter twice, but only if the
975 // parameter name, type and usage string are exactly the same.
976 if (ParamsMeta::registry().at(paramName) == paramInfo)
977 return;
978 throw std::logic_error("Parameter " + paramName
979 +" registered twice with non-matching characteristics.");
980 }
981
982 ParamsMeta::mutableRegistry()[paramName] = paramInfo;
983}
984
990template <class TypeTag, template<class,class> class Param>
992{
993 const std::string paramName = getPropName<TypeTag,Param>();
995 if (!ParamsMeta::registrationOpen())
996 throw std::logic_error("Parameter '" +paramName + "' declared as hidden"
997 " when parameter registration was already closed.");
998
999 auto paramInfoIt = ParamsMeta::mutableRegistry().find(paramName);
1000 if (paramInfoIt == ParamsMeta::mutableRegistry().end())
1001 throw std::logic_error("Tried to declare unknown parameter '"
1002 + paramName + "' hidden.");
1003
1004 auto& paramInfo = paramInfoIt->second;
1005 paramInfo.isHidden = true;
1006}
1007
1015template <class TypeTag>
1017{
1019 if (!ParamsMeta::registrationOpen())
1020 throw std::logic_error("Parameter registration was already closed. It is only possible "
1021 "to close it once.");
1022
1023 ParamsMeta::registrationOpen() = false;
1024
1025 // loop over all parameters and retrieve their values to make sure
1026 // that there is no syntax error
1027 for (const auto& param : ParamsMeta::registrationFinalizers()) {
1028 param->retrieve();
1029 }
1030 ParamsMeta::registrationFinalizers().clear();
1031}
1033
1034} // namespace Opm::Parameters
1035
1036#endif // OPM_PARAMETER_SYSTEM_HH
Definition: parametersystem.hh:108
void retrieve() override
Definition: parametersystem.hh:110
Definition: parametersystem.hh:99
virtual ~ParamRegFinalizerBase_()
Definition: parametersystem.hh:101
void registerParam(const char *usageString)
Register a run-time parameter.
Definition: parametersystem.hh:947
bool printUnused(std::ostream &os=std::cout)
Print the list of unused run-time parameters.
Definition: parametersystem.hh:808
void parseParameterFile(const std::string &fileName, bool overwrite=true)
Read the parameters from an INI-style file.
Definition: parametersystem.hh:679
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:400
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:571
auto get(bool errorIfNotRegistered=true)
Retrieve a runtime parameter.
Definition: parametersystem.hh:835
void printValues(std::ostream &os=std::cout)
Print values of the run-time parameters.
Definition: parametersystem.hh:746
Definition: parametersystem.hh:59
std::string parseUnquotedValue_(std::string &s, const std::string &)
Definition: parametersystem.hh:542
void removeLeadingSpace_(std::string &s)
Definition: parametersystem.hh:450
int getTtyWidth_()
Definition: parametersystem.hh:246
std::string parseQuotedValue_(std::string &s, const std::string &errorPrefix)
Definition: parametersystem.hh:505
void printParamUsage_(std::ostream &os, const ParamInfo &paramInfo)
Definition: parametersystem.hh:264
std::string breakLines_(const std::string &msg, int indentWidth, int maxWidth)
Definition: parametersystem.hh:197
void printParamList_(std::ostream &os, const std::list< std::string > &keyList, bool printDefaults=false)
Definition: parametersystem.hh:369
bool isSet(bool errorIfNotRegistered=true)
Returns true if a parameter has been specified at runtime, false otherwise.
Definition: parametersystem.hh:911
std::string transformKey_(const std::string &s, bool capitalizeFirstLetter=true, const std::string &errorPrefix="")
Definition: parametersystem.hh:459
std::string parseKey_(std::string &s)
Definition: parametersystem.hh:492
void hideParam()
Indicate that a given parameter should not be mentioned in the help message.
Definition: parametersystem.hh:991
void endParamRegistration()
Indicate that all parameters are registered for a given type tag.
Definition: parametersystem.hh:1016
void getLists(Container &usedParams, Container &unusedParams)
Retrieves the lists of parameters specified at runtime and their values.
Definition: parametersystem.hh:870
void reset()
Definition: parametersystem.hh:898
void getFlattenedKeyList_(std::list< std::string > &dest, const Dune::ParameterTree &tree, const std::string &prefix="")
Definition: parametersystem.hh:350
Definition: blackoilmodel.hh:72
Definition: blackoilboundaryratevector.hh:37
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type GetProp
get the type of a property (equivalent to old macro GET_PROP(...))
Definition: propertysystem.hh:233
The Opm property system, traits with inheritance.
Definition: parametersystem.hh:62
bool operator==(const ParamInfo &other) const
Definition: parametersystem.hh:70
std::string usageString
Definition: parametersystem.hh:66
std::string typeTagName
Definition: parametersystem.hh:65
bool isHidden
Definition: parametersystem.hh:68
std::string paramTypeName
Definition: parametersystem.hh:64
std::string compileTimeValue
Definition: parametersystem.hh:67
std::string paramName
Definition: parametersystem.hh:63
static const std::map< std::string, ::Opm::Parameters::ParamInfo > & registry()
Definition: parametersystem.hh:147
static bool & registrationOpen()
Definition: parametersystem.hh:153
static void clear()
Definition: parametersystem.hh:156
static Dune::ParameterTree & tree()
Definition: parametersystem.hh:141
Dune::ParameterTree type
Definition: parametersystem.hh:139
static std::map< std::string, ::Opm::Parameters::ParamInfo > & mutableRegistry()
Definition: parametersystem.hh:144
static std::list< std::unique_ptr<::Opm::Parameters::ParamRegFinalizerBase_ > > & registrationFinalizers()
Definition: parametersystem.hh:150
Definition: parametersystem.hh:132
Definition: parametersystem.hh:127
a tag to mark properties as undefined
Definition: propertysystem.hh:40