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