Loading [MathJax]/extensions/tex2jax.js
PISM, A Parallel Ice Sheet Model 2.2.2-d6b3a29ca committed by Constantine Khrulev on 2025-03-28
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ConfigInterface.cc
Go to the documentation of this file.
1/* Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025 PISM Authors
2 *
3 * This file is part of PISM.
4 *
5 * PISM is free software; you can redistribute it and/or modify it under the
6 * terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 3 of the License, or (at your option) any later
8 * version.
9 *
10 * PISM is distributed in the hope that it will be useful, but WITHOUT ANY
11 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 * details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with PISM; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20#include <mpi.h>
21#include <cmath> // std::round()
22#include <cstdlib> // realpath()
23
24
25#include "pism/util/io/File.hh"
26#include "pism/util/ConfigInterface.hh"
27#include "pism/util/Units.hh"
28#include "pism/util/pism_utilities.hh"
29#include "pism/util/pism_options.hh"
30#include "pism/util/error_handling.hh"
31#include "pism/util/io/IO_Flags.hh"
32
33// include an implementation header so that we can allocate a DefaultConfig instance in
34// config_from_options()
35#include "pism/util/Config.hh"
36#include "pism/util/Logger.hh"
37
38namespace pism {
39
42 : unit_system(sys) {
43 // empty
44 }
45
47
48 std::string filename;
49
50 //! @brief Set of parameters set by the user. Used to warn about parameters that were set but were
51 //! not used.
52 std::set<std::string> parameters_set_by_user;
53 //! @brief Set of parameters used in a run. Used to warn about parameters that were set but were
54 //! not used.
55 std::set<std::string> parameters_used;
56};
57
59 : m_impl(new Impl(system)) {
60 // empty
61}
62
64 delete m_impl;
65}
66
67void Config::read(MPI_Comm com, const std::string &filename) {
68
69 File file(com, filename, io::PISM_NETCDF3, io::PISM_READONLY); // OK to use netcdf3
70 this->read(file);
71}
72
73void Config::read(const File &file) {
74 this->read_impl(file);
75
76 m_impl->filename = file.name();
77}
78
79void Config::write(const File &file) const {
80 this->write_impl(file);
81}
82
83void Config::write(MPI_Comm com, const std::string &filename, bool append) const {
84
86
87 File file(com, filename, io::PISM_NETCDF3, mode); // OK to use netcdf3
88
89 this->write(file);
90}
91
92//! \brief Returns the name of the file used to initialize the database.
93std::string Config::filename() const {
94 return m_impl->filename;
95}
96
97void Config::import_from(const Config &other) {
98 auto parameters = this->keys();
99
100 for (const auto &p : other.all_doubles()) {
101 if (member(p.first, parameters)) {
102 this->set_numbers(p.first, p.second, CONFIG_USER);
103 } else {
105 "unrecognized parameter %s in %s",
106 p.first.c_str(), other.filename().c_str());
107 }
108 }
109
110 for (const auto &p : other.all_strings()) {
111 if (member(p.first, parameters)) {
112 this->set_string(p.first, p.second, CONFIG_USER);
113 } else {
115 "unrecognized parameter %s in %s",
116 p.first.c_str(), other.filename().c_str());
117 }
118 }
119
120 for (const auto &p : other.all_flags()) {
121 if (member(p.first, parameters)) {
122 this->set_flag(p.first, p.second, CONFIG_USER);
123 } else {
125 "unrecognized parameter %s in %s",
126 p.first.c_str(), other.filename().c_str());
127 }
128 }
129}
130
132 for (const auto &s : all_strings()) {
133 auto parameter = s.first;
134 auto value = s.second;
135
136 if (value.empty()) {
137 continue;
138 }
139
140 auto last_token = pism::split(parameter, '.').back();
141
142 if (last_token == "file") {
143 char *resolved_path = realpath(value.c_str(), NULL);
144
145 if (resolved_path != NULL) {
146 set_string(parameter, resolved_path, CONFIG_USER);
147 free(resolved_path);
148 }
149 // Note: we keep the old value if `realpath()` failed
150 }
151 } // end of the loop over all strings
152}
153
154const std::set<std::string>& Config::parameters_set_by_user() const {
156}
157
158const std::set<std::string>& Config::parameters_used() const {
159 return m_impl->parameters_used;
160}
161
162bool Config::is_set(const std::string &name) const {
163 return this->is_set_impl(name);
164}
165
167 return this->all_doubles_impl();
168}
169
170bool Config::is_valid_number(const std::string &name) const {
171 auto value = get_number(name, FORGET_THIS_USE);
172 auto min = valid_min(name);
173
174 if (std::get<0>(min)) {
175 auto valid_min = std::get<1>(min);
176
177 if (value < valid_min) {
178 return false;
179 }
180 }
181
182 auto max = valid_max(name);
183 if (std::get<0>(max)) {
184 auto valid_max = std::get<1>(max);
185
186 if (value > valid_max) {
187 return false;
188 }
189 }
190
191 return true;
192}
193
194double Config::get_number(const std::string &name, UseFlag flag) const {
195 auto value = get_number_impl(name);
196
197 if (flag == REMEMBER_THIS_USE) {
198 // check the valid range (if set) and remember that this parameter was used
199 //
200 // note that we don't check the valid range when flag == FORGET_THIS_USE. This way we
201 // can get the default value of a parameter. Parameters without a default value should
202 // be set to values outside of their respective valid ranges (if possible).
203 m_impl->parameters_used.insert(name);
204
205 if (type(name) == "integer" and std::round(value) != value) {
208 "integer parameter '%s' was set to a number with a non-zero fractional part (%f)",
209 name.c_str(), value);
210 }
211
212 auto min = valid_min(name);
213 if (std::get<0>(min)) {
214 auto valid_min = std::get<1>(min);
215
216 if (value < valid_min) {
217 if (type(name) == "integer") {
219 "Please set '%s' to a number greater than or equal to %d",
220 name.c_str(), (int)valid_min);
221 }
223 "Please set '%s' to a number greater than or equal to %f",
224 name.c_str(), valid_min);
225 }
226 }
227
228 auto max = valid_max(name);
229 if (std::get<0>(max)) {
230 auto valid_max = std::get<1>(max);
231
232 if (value > valid_max) {
233 if (type(name) == "integer") {
235 "Please set '%s' to a number less than or equal to %d",
236 name.c_str(), (int)valid_max);
237 }
239 "Please set '%s' to a number less than or equal to %f",
240 name.c_str(), valid_max);
241 }
242 }
243 }
244
245 return value;
246}
247
248double Config::get_number(const std::string &name,
249 const std::string &units,
250 UseFlag flag) const {
251 double value = this->get_number(name, flag);
252 std::string input_units = this->units(name);
253
254 try {
255 return units::convert(m_impl->unit_system, value, input_units, units);
256 } catch (RuntimeError &e) {
257 e.add_context("converting \"%s\" from \"%s\" to \"%s\"",
258 name.c_str(), input_units.c_str(), units.c_str());
259 throw;
260 }
261}
262
263std::vector<double> Config::get_numbers(const std::string &name, UseFlag flag) const {
264 if (flag == REMEMBER_THIS_USE) {
265 m_impl->parameters_used.insert(name);
266 }
267 return this->get_numbers_impl(name);
268}
269
270std::vector<double> Config::get_numbers(const std::string &name,
271 const std::string &units,
272 UseFlag flag) const {
273 auto value = this->get_numbers(name, flag);
274 auto input_units = this->units(name);
275
276 try {
277 units::Converter converter(m_impl->unit_system, input_units, units);
278 for (unsigned int k = 0; k < value.size(); ++k) {
279 value[k] = converter(value[k]);
280 }
281 return value;
282 } catch (RuntimeError &e) {
283 e.add_context("converting \"%s\" from \"%s\" to \"%s\"",
284 name.c_str(), input_units.c_str(), units.c_str());
285 throw;
286 }
287}
288
289void Config::set_number(const std::string &name, double value,
290 ConfigSettingFlag flag) {
291 std::set<std::string> &set_by_user = m_impl->parameters_set_by_user;
292
293 if (flag == CONFIG_USER) {
294 set_by_user.insert(name);
295 }
296
297 // stop if we're setting the default value and this parameter was set by user already
298 if (flag == CONFIG_DEFAULT and
299 set_by_user.find(name) != set_by_user.end()) {
300 return;
301 }
302
303 this->set_number_impl(name, value);
304}
305
306void Config::set_numbers(const std::string &name,
307 const std::vector<double> &values,
308 ConfigSettingFlag flag) {
309 std::set<std::string> &set_by_user = m_impl->parameters_set_by_user;
310
311 if (flag == CONFIG_USER) {
312 set_by_user.insert(name);
313 }
314
315 // stop if we're setting the default value and this parameter was set by user already
316 if (flag == CONFIG_DEFAULT and
317 set_by_user.find(name) != set_by_user.end()) {
318 return;
319 }
320
321 this->set_numbers_impl(name, values);
322}
323
325 return this->all_strings_impl();
326}
327
328std::string Config::get_string(const std::string &name, UseFlag flag) const {
329 if (flag == REMEMBER_THIS_USE) {
330 m_impl->parameters_used.insert(name);
331 }
332 return this->get_string_impl(name);
333}
334
335void Config::set_string(const std::string &name,
336 const std::string &value,
337 ConfigSettingFlag flag) {
338 std::set<std::string> &set_by_user = m_impl->parameters_set_by_user;
339
340 if (flag == CONFIG_USER) {
341 set_by_user.insert(name);
342 }
343
344 // stop if we're setting the default value and this parameter was set by user already
345 if (flag == CONFIG_DEFAULT and
346 set_by_user.find(name) != set_by_user.end()) {
347 return;
348 }
349
350 this->set_string_impl(name, value);
351}
352
354 return this->all_flags_impl();
355}
356
357bool Config::get_flag(const std::string& name, UseFlag flag) const {
358 if (flag == REMEMBER_THIS_USE) {
359 m_impl->parameters_used.insert(name);
360 }
361 return this->get_flag_impl(name);
362}
363
364void Config::set_flag(const std::string& name, bool value,
365 ConfigSettingFlag flag) {
366 std::set<std::string> &set_by_user = m_impl->parameters_set_by_user;
367
368 if (flag == CONFIG_USER) {
369 set_by_user.insert(name);
370 }
371
372 // stop if we're setting the default value and this parameter was set by user already
373 if (flag == CONFIG_DEFAULT and
374 set_by_user.find(name) != set_by_user.end()) {
375 return;
376 }
377
378 this->set_flag_impl(name, value);
379}
380
381static bool special_parameter(const std::string &name) {
382 for (const auto &suffix : {"_doc", "_units", "_type", "_option", "_choices", "_valid_min", "_valid_max"}) {
383 if (ends_with(name, suffix)) {
384 return true;
385 }
386 }
387
388 // The NetCDF-based configuration database stores parameters as attributes of a variable
389 // and CF conventions require that all variables have a "long name."
390 return (name == "long_name");
391}
392
393void print_config(const Logger &log, int verbosity_threshhold, const Config &config) {
394 const int v = verbosity_threshhold;
395
396 log.message(v,
397 "### Strings:\n"
398 "###\n");
399
400 Config::Strings strings = config.all_strings();
401
402 // find max. name size
403 size_t max_name_size = 0;
404 for (const auto &s : strings) {
405 if (special_parameter(s.first)) {
406 continue;
407 }
408 max_name_size = std::max(max_name_size, s.first.size());
409 }
410
411 // print strings
412 for (const auto &s : strings) {
413 std::string name = s.first;
414 std::string value = s.second;
415
416 if (value.empty() or special_parameter(name)) {
417 continue;
418 }
419
420 std::string padding(max_name_size - name.size(), ' ');
421
422 if (config.type(name) == "keyword") {
423 log.message(v, " %s%s = \"%s\" (allowed choices: %s)\n",
424 name.c_str(), padding.c_str(), value.c_str(),
425 config.choices(name).c_str());
426 } else {
427 log.message(v, " %s%s = \"%s\"\n", name.c_str(), padding.c_str(), value.c_str());
428 }
429 }
430
431 log.message(v,
432 "### Doubles:\n"
433 "###\n");
434
435 // find max. name size
436 max_name_size = 0;
437 for (const auto &d : config.all_doubles()) {
438 max_name_size = std::max(max_name_size, d.first.size());
439 }
440 // print doubles
441 for (auto d : config.all_doubles()) {
442 std::string name = d.first;
443 double value = d.second[0];
444
445 if (special_parameter(name)) {
446 continue;
447 }
448
449 std::string units = config.units(name); // will be empty if not set
450 std::string padding(max_name_size - name.size(), ' ');
451
452 const double large = 1.0e7;
453 const double small = 1.0e-4;
454 if (fabs(value) >= large or fabs(value) <= small) {
455 // use scientific notation if a number is big or small
456 log.message(v, " %s%s = %13.3e (%s)\n", name.c_str(), padding.c_str(), value, units.c_str());
457 } else {
458 log.message(v, " %s%s = %13.5f (%s)\n", name.c_str(), padding.c_str(), value, units.c_str());
459 }
460 }
461
462 log.message(v,
463 "### Flags:\n"
464 "###\n");
465
466 // find max. name size
467 max_name_size = 0;
468 for (const auto &b : config.all_flags()) {
469 max_name_size = std::max(max_name_size, b.first.size());
470 }
471
472 // print flags
473 for (const auto &b : config.all_flags()) {
474 std::string name = b.first;
475 std::string value = b.second ? "true" : "false";
476 std::string padding(max_name_size - name.size(), ' ');
477
478 log.message(v, " %s%s = %s\n", name.c_str(), padding.c_str(), value.c_str());
479 }
480
481 log.message(v,
482 "### List of configuration parameters ends here.\n"
483 "###\n");
484}
485
486void print_unused_parameters(const Logger &log, int verbosity_threshhold,
487 const Config &config) {
488 std::set<std::string> parameters_set = config.parameters_set_by_user();
489 std::set<std::string> parameters_used = config.parameters_used();
490
491 if (options::Bool("-options_left", "report unused options")) {
492 verbosity_threshhold = log.get_threshold();
493 }
494
495 for (const auto &p : parameters_set) {
496
497 if (special_parameter(p)) {
498 continue;
499 }
500
501 if (parameters_used.find(p) == parameters_used.end()) {
502 log.message(verbosity_threshhold,
503 "PISM WARNING: flag or parameter \"%s\" was set but was not used!\n",
504 p.c_str());
505
506 }
507 }
508}
509
510// command-line options
511
512//! Get a flag from a command-line option.
513/*!
514 * Use the command-line option `option` to set the configuration parameter `parameter_name`.
515 *
516 * When called as `set_flag_from_option(config, "foo", "bar")`,
517 *
518 * sets the configuration parameter `bar` to `true` if
519 *
520 * - `-foo` is set (no argument)
521 * - `-foo true` is set
522 * - `-foo True` is set
523 * - `-foo yes` is set
524 *
525 * sets the `bar` to `false` if
526 *
527 * - `-foo false` is set
528 * - `-foo False` is set
529 * - `-foo no` is set
530 * - `-no_foo is set.
531 *
532 * `-foo X` with `X` not equal to `yes`, `no`, `true`, `True`, `false`, `False` results in an error.
533 */
534void set_flag_from_option(Config &config, const std::string &option,
535 const std::string &parameter_name) {
536
537 // get the default value
538 bool value = config.get_flag(parameter_name, Config::FORGET_THIS_USE);
539 std::string doc = config.doc(parameter_name);
540
541 // process the command-line option
542 options::String opt("-" + option, doc, value ? "true" : "false", options::ALLOW_EMPTY);
543
544 if (opt.is_set()) {
545 if (member(opt.value(), { "", "on", "yes", "true", "True" })) {
546
547 value = true;
548
549 } else if (member(opt.value(), { "off", "no", "false", "False" })) {
550
551 value = false;
552
553 } else {
554 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "invalid -%s argument: %s", option.c_str(),
555 opt.value().c_str());
556 }
557 }
558
559 // For backward compatibility we allow disabling an option -foo by setting -no_foo.
560 {
561 bool no_foo_is_set = options::Bool("-no_" + option, doc);
562
563 if (no_foo_is_set) {
564 if (opt.is_set()) {
566 "Inconsistent command-line options:"
567 " both -%s and -no_%s are set.\n",
568 option.c_str(), option.c_str());
569 }
570
571 value = false;
572 }
573 }
574
575 config.set_flag(parameter_name, value, CONFIG_USER);
576}
577
578//! Sets a configuration parameter from a command-line option.
579/*!
580 If called as number_from_option("foo", "foo"), checks -foo and calls set("foo", value).
581
582 Does nothing if -foo was not set.
583
584 Note that no unit conversion is performed; parameters should be stored in
585 input units and converted as needed. (This allows saving parameters without
586 converting again.)
587*/
588void set_number_from_option(units::System::Ptr unit_system, Config &config, const std::string &option,
589 const std::string &parameter) {
590 options::Real opt(unit_system, "-" + option, config.doc(parameter), config.units(parameter),
591 config.get_number(parameter, Config::FORGET_THIS_USE));
592 if (opt.is_set()) {
593 config.set_number(parameter, opt, CONFIG_USER);
594 }
595}
596
597void set_integer_from_option(Config &config, const std::string &option,
598 const std::string &parameter) {
599 options::Integer opt("-" + option, config.doc(parameter),
600 (int)config.get_number(parameter, Config::FORGET_THIS_USE));
601 if (opt.is_set()) {
602 config.set_number(parameter, opt, CONFIG_USER);
603 }
604}
605
606void set_string_from_option(Config &config, const std::string &option, const std::string &parameter) {
607
608 options::String value("-" + option, config.doc(parameter),
609 config.get_string(parameter, Config::FORGET_THIS_USE));
610 if (value.is_set()) {
611 config.set_string(parameter, value, CONFIG_USER);
612 }
613}
614
615//! \brief Set a keyword parameter from a command-line option.
616/*!
617 * This sets the parameter "parameter" after checking the "-name" command-line
618 * option. This option requires an argument, which has to match one of the
619 * keyword given in a comma-separated list "choices_list".
620 */
621void set_keyword_from_option(Config &config, const std::string &option, const std::string &parameter,
622 const std::string &choices) {
623
624 options::Keyword keyword("-" + option, config.doc(parameter), choices,
625 config.get_string(parameter, Config::FORGET_THIS_USE));
626
627 if (keyword.is_set()) {
628 config.set_string(parameter, keyword, CONFIG_USER);
629 }
630}
631
633 const std::string &name) {
634
635 // skip special parameters ("attributes" of parameters)
636 if (special_parameter(name)) {
637 return;
638 }
639
640 // Use parameter name as its own command-line option by default. parameter_name_option can specify
641 // a different (possibly shorter) command-line option.
642 std::string option = name;
643
644 if (not config.option(name).empty()) { // there is a short version of the command-line option
645 std::string short_option = config.option(name);
646 std::string description = config.doc(name);
647
648 if (options::Bool("-" + short_option, description) or
649 options::Bool("-no_" + short_option, description)) { // short option is set
650 if (options::Bool("-" + option, description)) {
652 "both -%s and -%s are set (please use one or the other)",
653 option.c_str(), short_option.c_str());
654 }
655
656 // Use the short option only if the user set it, otherwise used the full (long) option below.
657 option = short_option;
658 }
659 }
660
661 std::string type = config.type(name);
662
663 if (type == "string") {
664 set_string_from_option(config, option, name);
665 } else if (type == "flag") {
666 set_flag_from_option(config, option, name);
667 } else if (type == "number") {
668 set_number_from_option(unit_system, config, option, name);
669 } else if (type == "integer") {
670 set_integer_from_option(config, option, name);
671 } else if (type == "keyword") {
672 set_keyword_from_option(config, option, name, config.choices(name));
673 } else {
674 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "parameter type \"%s\" is invalid",
675 type.c_str());
676 }
677}
678
680 for (const auto &d : config.all_doubles()) {
681 set_parameter_from_options(unit_system, config, d.first);
682 }
683
684 for (const auto &s : config.all_strings()) {
685 set_parameter_from_options(unit_system, config, s.first);
686 }
687
688 for (const auto &b : config.all_flags()) {
689 set_parameter_from_options(unit_system, config, b.first);
690 }
691
692 // Shortcuts
693
694 // option "-pik" turns on a suite of PISMPIK effects (but NOT a calving choice,
695 // and in particular NOT "-calving eigen_calving")
696 bool pik = options::Bool("-pik", "enable suite of PISM-PIK mechanisms");
697 if (pik) {
698 config.set_flag("stress_balance.calving_front_stress_bc", true, CONFIG_USER);
699 config.set_flag("geometry.part_grid.enabled", true, CONFIG_USER);
700 config.set_flag("geometry.remove_icebergs", true, CONFIG_USER);
701 config.set_flag("geometry.grounded_cell_fraction", true, CONFIG_USER);
702 }
703
704 if (config.get_string("calving.methods").find("eigen_calving") != std::string::npos) {
705 config.set_flag("geometry.part_grid.enabled", true, CONFIG_USER);
706 // eigen-calving requires a wider stencil:
707 config.set_number("grid.max_stencil_width", 3);
708 }
709
710 // all calving mechanisms require iceberg removal
711 if (not config.get_string("calving.methods").empty()) {
712 config.set_flag("geometry.remove_icebergs", true, CONFIG_USER);
713 }
714
715 // geometry.remove_icebergs requires part_grid
716 if (config.get_flag("geometry.remove_icebergs")) {
717 config.set_flag("geometry.part_grid.enabled", true, CONFIG_USER);
718 }
719
720 // If frontal melt code includes floating ice, routing hydrology should include it also.
721 if (config.get_string("hydrology.model") == "routing") {
722 if (config.get_flag("frontal_melt.include_floating_ice")) {
723 config.set_flag("hydrology.routing.include_floating_ice", true);
724 }
725 }
726
727 if (config.get_flag("output.ISMIP6")) {
728 // use MKS units in ISMIP6 mode
729 config.set_flag("output.use_MKS", true);
730 }
731
732 // Special command-line options for "-surface elevation,...":
733 {
734 options::String T("-ice_surface_temp", "ice surface temperature parameterization");
735
736 if (T.is_set()) {
737 auto IST = parse_number_list(T);
738
739 if (IST.size() != 4) {
740 throw RuntimeError(PISM_ERROR_LOCATION, "option -ice_surface_temp requires an argument"
741 " (comma-separated list of 4 numbers)");
742 }
743
744 config.set_number("surface.elevation_dependent.T_min", IST[0]);
745 config.set_number("surface.elevation_dependent.T_max", IST[1]);
746 config.set_number("surface.elevation_dependent.z_T_min", IST[2]);
747 config.set_number("surface.elevation_dependent.z_T_max", IST[3]);
748 }
749
750 options::String M("-climatic_mass_balance", "climatic mass balance parameterization");
751
752 if (M.is_set()) {
753 auto CMB = parse_number_list(M);
754
755 if (CMB.size() != 5) {
756 throw RuntimeError(PISM_ERROR_LOCATION, "-climatic_mass_balance requires an argument"
757 " (comma-separated list of 5 numbers)");
758 }
759
760 config.set_number("surface.elevation_dependent.M_min", CMB[0]);
761 config.set_number("surface.elevation_dependent.M_max", CMB[1]);
762 config.set_number("surface.elevation_dependent.z_M_min", CMB[2]);
763 config.set_number("surface.elevation_dependent.z_ELA", CMB[3]);
764 config.set_number("surface.elevation_dependent.z_M_max", CMB[4]);
765 }
766
767 options::String limits("-climatic_mass_balance_limits",
768 "lower and upper limits of the climatic mass balance");
769
770 if (limits.is_set()) {
771
772 auto L = parse_number_list(limits);
773
774 if (L.size() != 2) {
775 throw RuntimeError(PISM_ERROR_LOCATION, "-climatic_mass_balance_limits requires an argument"
776 " (a comma-separated list of 2 numbers)");
777 }
778
779 units::Converter meter_per_second(unit_system, "m year^-1", "m second^-1");
780
781 config.set_number("surface.elevation_dependent.M_limit_min", meter_per_second(L[0]));
782 config.set_number("surface.elevation_dependent.M_limit_max", meter_per_second(L[1]));
783 }
784 }
785}
786
787//! Create a configuration database using command-line options.
788Config::Ptr config_from_options(MPI_Comm com, const Logger &log, units::System::Ptr unit_system) {
789
790 using T = DefaultConfig;
791 auto config = std::make_shared<T>(com, "pism_config", "-config", unit_system);
792 auto overrides = std::make_shared<T>(com, "pism_overrides", "-config_override", unit_system);
793
794 overrides->init(log);
795
796 config->init_with_default(log);
797
798 config->import_from(*overrides);
799
800 set_config_from_options(unit_system, *config);
801
802 config->resolve_filenames();
803
804 return config;
805}
806
808 : m_prefix(prefix), m_config(c) {
809 // empty
810}
811
812double ConfigWithPrefix::get_number(const std::string &name) const {
813 return m_config->get_number(m_prefix + name);
814}
815
816double ConfigWithPrefix::get_number(const std::string &name, const std::string &units) const {
817 return m_config->get_number(m_prefix + name, units);
818}
819
820std::string ConfigWithPrefix::get_string(const std::string &name) const {
821 return m_config->get_string(m_prefix + name);
822}
823
824bool ConfigWithPrefix::get_flag(const std::string &name) const {
825 return m_config->get_flag(m_prefix + name);
826}
827
828void ConfigWithPrefix::reset_prefix(const std::string &prefix) {
829 m_prefix = prefix;
830}
831
832std::set<std::string> Config::keys() const {
833 std::set<std::string> result;
834
835 for (const auto &p : all_doubles()) {
836 result.insert(p.first);
837 }
838
839 for (const auto &p : all_strings()) {
840 result.insert(p.first);
841 }
842
843 for (const auto &p : all_flags()) {
844 result.insert(p.first);
845 }
846
847 return result;
848}
849
850std::string Config::doc(const std::string &parameter) const {
851 return this->get_string(parameter + "_doc", Config::FORGET_THIS_USE);
852}
853
854std::string Config::units(const std::string &parameter) const {
855 return this->get_string(parameter + "_units", Config::FORGET_THIS_USE);
856}
857
858std::string Config::type(const std::string &parameter) const {
859 return this->get_string(parameter + "_type", Config::FORGET_THIS_USE);
860}
861
862std::string Config::option(const std::string &parameter) const {
863 if (this->is_set(parameter + "_option")) {
864 return this->get_string(parameter + "_option", Config::FORGET_THIS_USE);
865 }
866
867 return "";
868}
869
870std::string Config::choices(const std::string &parameter) const {
871 return this->get_string(parameter + "_choices", Config::FORGET_THIS_USE);
872}
873
874std::pair<bool, double> Config::valid_min(const std::string &parameter) const {
875 if (is_set(parameter + "_valid_min")) {
876 return { true, get_number(parameter + "_valid_min", Config::FORGET_THIS_USE) };
877 }
878 return { false, {} };
879}
880
881std::pair<bool, double> Config::valid_max(const std::string &parameter) const {
882 if (is_set(parameter + "_valid_max")) {
883 return { true, get_number(parameter + "_valid_max", Config::FORGET_THIS_USE) };
884 }
885 return { false, {} };
886}
887
888} // end of namespace pism
void reset_prefix(const std::string &prefix)
bool get_flag(const std::string &name) const
std::string get_string(const std::string &name) const
double get_number(const std::string &name) const
Config::ConstPtr m_config
ConfigWithPrefix(Config::ConstPtr c, const std::string &prefix)
virtual bool is_set_impl(const std::string &name) const =0
std::map< std::string, std::string > Strings
const std::set< std::string > & parameters_used() const
std::shared_ptr< Config > Ptr
bool is_set(const std::string &name) const
std::string choices(const std::string &parameter) const
virtual Strings all_strings_impl() const =0
std::set< std::string > keys() const
std::pair< bool, double > valid_max(const std::string &parameter) const
std::map< std::string, std::vector< double > > Doubles
void set_string(const std::string &name, const std::string &value, ConfigSettingFlag flag=CONFIG_FORCE)
double get_number(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
virtual void set_numbers_impl(const std::string &name, const std::vector< double > &values)=0
Flags all_flags() const
std::vector< double > get_numbers(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
virtual void read_impl(const File &nc)=0
std::shared_ptr< const Config > ConstPtr
virtual Flags all_flags_impl() const =0
virtual std::vector< double > get_numbers_impl(const std::string &name) const =0
const std::set< std::string > & parameters_set_by_user() const
virtual void set_flag_impl(const std::string &name, bool value)=0
void read(MPI_Comm com, const std::string &filename)
bool is_valid_number(const std::string &name) const
virtual void set_string_impl(const std::string &name, const std::string &value)=0
std::string units(const std::string &parameter) const
void import_from(const Config &other)
Config(units::System::Ptr unit_system)
void set_flag(const std::string &name, bool value, ConfigSettingFlag flag=CONFIG_FORCE)
virtual std::string get_string_impl(const std::string &name) const =0
std::map< std::string, bool > Flags
std::string get_string(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
std::string type(const std::string &parameter) const
virtual ~Config()
virtual Doubles all_doubles_impl() const =0
virtual void set_number_impl(const std::string &name, double value)=0
void write(MPI_Comm com, const std::string &filename, bool append=true) const
bool get_flag(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
void set_number(const std::string &name, double value, ConfigSettingFlag flag=CONFIG_FORCE)
std::string option(const std::string &parameter) const
std::string filename() const
Returns the name of the file used to initialize the database.
Strings all_strings() const
virtual void write_impl(const File &nc) const =0
void set_numbers(const std::string &name, const std::vector< double > &values, ConfigSettingFlag flag=CONFIG_FORCE)
Doubles all_doubles() const
std::string doc(const std::string &parameter) const
UseFlag
Flag used by get_...() methods.
std::pair< bool, double > valid_min(const std::string &parameter) const
virtual double get_number_impl(const std::string &name) const =0
virtual bool get_flag_impl(const std::string &name) const =0
A class for storing and accessing PISM configuration flags and parameters.
Default PISM configuration database: uses NetCDF files; can be initialized from a file specified usin...
Definition Config.hh:72
std::string name() const
Definition File.cc:274
High-level PISM I/O class.
Definition File.hh:55
void message(int threshold, const char format[],...) const __attribute__((format(printf
Print a message to the log.
Definition Logger.cc:49
int get_threshold() const
Get verbosity threshold.
Definition Logger.cc:96
A basic logging class.
Definition Logger.hh:40
void add_context(const std::string &message)
Add a message providing some context. This way we can (sort of) get a stack trace even though C++ exc...
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
bool is_set() const
Definition options.hh:35
std::shared_ptr< System > Ptr
Definition Units.hh:47
#define PISM_ERROR_LOCATION
static const double L
Definition exactTestL.cc:40
@ PISM_NETCDF3
Definition IO_Flags.hh:57
@ PISM_READWRITE_MOVE
create a file for writing, move foo.nc to foo.nc~ if present
Definition IO_Flags.hh:74
@ PISM_READONLY
open an existing file for reading only
Definition IO_Flags.hh:68
@ PISM_READWRITE
open an existing file for reading and writing
Definition IO_Flags.hh:70
bool Bool(const std::string &option, const std::string &description)
Definition options.cc:190
double convert(System::Ptr system, double input, const std::string &spec1, const std::string &spec2)
Convert a quantity from unit1 to unit2.
Definition Units.cc:70
void set_integer_from_option(Config &config, const std::string &option, const std::string &parameter)
bool ends_with(const std::string &str, const std::string &suffix)
Returns true if str ends with suffix and false otherwise.
std::vector< double > parse_number_list(const std::string &input)
Config::Ptr config_from_options(MPI_Comm com, const Logger &log, units::System::Ptr unit_system)
Create a configuration database using command-line options.
static const double k
Definition exactTestP.cc:42
void set_number_from_option(units::System::Ptr unit_system, Config &config, const std::string &option, const std::string &parameter)
Sets a configuration parameter from a command-line option.
void set_string_from_option(Config &config, const std::string &option, const std::string &parameter)
Set one free-form string parameter using command-line options.
bool member(const std::string &string, const std::set< std::string > &set)
void set_config_from_options(units::System::Ptr unit_system, Config &config)
Set configuration parameters using command-line options.
static bool special_parameter(const std::string &name)
void set_flag_from_option(Config &config, const std::string &option, const std::string &parameter_name)
Get a flag from a command-line option.
ConfigSettingFlag
Flag used by set_...() methods.
void print_unused_parameters(const Logger &log, int verbosity_threshhold, const Config &config)
Report unused configuration parameters to stdout.
void set_keyword_from_option(Config &config, const std::string &option, const std::string &parameter, const std::string &choices)
Set a keyword parameter from a command-line option.
void set_parameter_from_options(units::System::Ptr unit_system, Config &config, const std::string &name)
Set one parameter using command-line options.
void print_config(const Logger &log, int verbosity_threshhold, const Config &config)
Report configuration parameters to stdout.
std::vector< std::string > split(const std::string &input, char separator)
Transform a separator-separated list (a string) into a vector of strings.
units::System::Ptr unit_system
std::set< std::string > parameters_used
Set of parameters used in a run. Used to warn about parameters that were set but were not used.
Impl(units::System::Ptr sys)
std::set< std::string > parameters_set_by_user
Set of parameters set by the user. Used to warn about parameters that were set but were not used.