PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
ConfigInterface.cc
Go to the documentation of this file.
1 /* Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 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>
22 #include <climits> // PATH_MAX
23 #include <cstdlib> // realpath()
24 
25 
26 #include "pism/util/io/File.hh"
27 #include "pism/util/ConfigInterface.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 
34 // include an implementation header so that we can allocate a DefaultConfig instance in
35 // config_from_options()
36 #include "pism/util/Config.hh"
37 #include "pism/util/Logger.hh"
38 
39 namespace pism {
40 
41 struct Config::Impl {
43  : unit_system(sys) {
44  // empty
45  }
46 
48 
49  std::string filename;
50 
51  //! @brief Set of parameters set by the user. Used to warn about parameters that were set but were
52  //! not used.
53  std::set<std::string> parameters_set_by_user;
54  //! @brief Set of parameters used in a run. Used to warn about parameters that were set but were
55  //! not used.
56  std::set<std::string> parameters_used;
57 };
58 
60  : m_impl(new Impl(system)) {
61  // empty
62 }
63 
65  delete m_impl;
66 }
67 
68 void Config::read(MPI_Comm com, const std::string &filename) {
69 
70  File file(com, filename, io::PISM_NETCDF3, io::PISM_READONLY); // OK to use netcdf3
71  this->read(file);
72 }
73 
74 void Config::read(const File &file) {
75  this->read_impl(file);
76 
77  m_impl->filename = file.filename();
78 }
79 
80 void Config::write(const File &file) const {
81  this->write_impl(file);
82 }
83 
84 void Config::write(MPI_Comm com, const std::string &filename, bool append) const {
85 
87 
88  File file(com, filename, io::PISM_NETCDF3, mode); // OK to use netcdf3
89 
90  this->write(file);
91 }
92 
93 //! \brief Returns the name of the file used to initialize the database.
94 std::string Config::filename() const {
95  return m_impl->filename;
96 }
97 
98 void Config::import_from(const Config &other) {
99  auto parameters = this->keys();
100 
101  for (const auto &p : other.all_doubles()) {
102  if (member(p.first, parameters)) {
103  this->set_numbers(p.first, p.second, CONFIG_USER);
104  } else {
106  "unrecognized parameter %s in %s",
107  p.first.c_str(), other.filename().c_str());
108  }
109  }
110 
111  for (const auto &p : other.all_strings()) {
112  if (member(p.first, parameters)) {
113  this->set_string(p.first, p.second, CONFIG_USER);
114  } else {
116  "unrecognized parameter %s in %s",
117  p.first.c_str(), other.filename().c_str());
118  }
119  }
120 
121  for (const auto &p : other.all_flags()) {
122  if (member(p.first, parameters)) {
123  this->set_flag(p.first, p.second, CONFIG_USER);
124  } else {
126  "unrecognized parameter %s in %s",
127  p.first.c_str(), other.filename().c_str());
128  }
129  }
130 }
131 
133  for (const auto &s : all_strings()) {
134  auto parameter = s.first;
135  auto value = s.second;
136 
137  if (value.empty()) {
138  continue;
139  }
140 
141  auto last_token = pism::split(parameter, '.').back();
142 
143  if (last_token == "file") {
144  char resolved_path[PATH_MAX];
145 
146  if (realpath(value.c_str(), resolved_path) != NULL) {
147  set_string(parameter, resolved_path, CONFIG_USER);
148  }
149  // Note: we keep the old value if `realpath()` failed
150  }
151  } // end of the loop over all strings
152 }
153 
154 const std::set<std::string>& Config::parameters_set_by_user() const {
156 }
157 
158 const std::set<std::string>& Config::parameters_used() const {
159  return m_impl->parameters_used;
160 }
161 
162 bool 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 
170 double Config::get_number(const std::string &name, UseFlag flag) const {
171  if (flag == REMEMBER_THIS_USE) {
172  m_impl->parameters_used.insert(name);
173  }
174  return this->get_number_impl(name);
175 }
176 
177 double Config::get_number(const std::string &name,
178  const std::string &units,
179  UseFlag flag) const {
180  double value = this->get_number(name, flag);
181  std::string input_units = this->units(name);
182 
183  try {
184  return units::convert(m_impl->unit_system, value, input_units, units);
185  } catch (RuntimeError &e) {
186  e.add_context("converting \"%s\" from \"%s\" to \"%s\"",
187  name.c_str(), input_units.c_str(), units.c_str());
188  throw;
189  }
190 }
191 
192 std::vector<double> Config::get_numbers(const std::string &name, UseFlag flag) const {
193  if (flag == REMEMBER_THIS_USE) {
194  m_impl->parameters_used.insert(name);
195  }
196  return this->get_numbers_impl(name);
197 }
198 
199 std::vector<double> Config::get_numbers(const std::string &name,
200  const std::string &units,
201  UseFlag flag) const {
202  auto value = this->get_numbers(name, flag);
203  auto input_units = this->units(name);
204 
205  try {
206  units::Converter converter(m_impl->unit_system, input_units, units);
207  for (unsigned int k = 0; k < value.size(); ++k) {
208  value[k] = converter(value[k]);
209  }
210  return value;
211  } catch (RuntimeError &e) {
212  e.add_context("converting \"%s\" from \"%s\" to \"%s\"",
213  name.c_str(), input_units.c_str(), units.c_str());
214  throw;
215  }
216 }
217 
218 void Config::set_number(const std::string &name, double value,
219  ConfigSettingFlag flag) {
220  std::set<std::string> &set_by_user = m_impl->parameters_set_by_user;
221 
222  if (flag == CONFIG_USER) {
223  set_by_user.insert(name);
224  }
225 
226  // stop if we're setting the default value and this parameter was set by user already
227  if (flag == CONFIG_DEFAULT and
228  set_by_user.find(name) != set_by_user.end()) {
229  return;
230  }
231 
232  this->set_number_impl(name, value);
233 }
234 
235 void Config::set_numbers(const std::string &name,
236  const std::vector<double> &values,
237  ConfigSettingFlag flag) {
238  std::set<std::string> &set_by_user = m_impl->parameters_set_by_user;
239 
240  if (flag == CONFIG_USER) {
241  set_by_user.insert(name);
242  }
243 
244  // stop if we're setting the default value and this parameter was set by user already
245  if (flag == CONFIG_DEFAULT and
246  set_by_user.find(name) != set_by_user.end()) {
247  return;
248  }
249 
250  this->set_numbers_impl(name, values);
251 }
252 
254  return this->all_strings_impl();
255 }
256 
257 std::string Config::get_string(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_string_impl(name);
262 }
263 
264 void Config::set_string(const std::string &name,
265  const std::string &value,
266  ConfigSettingFlag flag) {
267  std::set<std::string> &set_by_user = m_impl->parameters_set_by_user;
268 
269  if (flag == CONFIG_USER) {
270  set_by_user.insert(name);
271  }
272 
273  // stop if we're setting the default value and this parameter was set by user already
274  if (flag == CONFIG_DEFAULT and
275  set_by_user.find(name) != set_by_user.end()) {
276  return;
277  }
278 
279  this->set_string_impl(name, value);
280 }
281 
283  return this->all_flags_impl();
284 }
285 
286 bool Config::get_flag(const std::string& name, UseFlag flag) const {
287  if (flag == REMEMBER_THIS_USE) {
288  m_impl->parameters_used.insert(name);
289  }
290  return this->get_flag_impl(name);
291 }
292 
293 void Config::set_flag(const std::string& name, bool value,
294  ConfigSettingFlag flag) {
295  std::set<std::string> &set_by_user = m_impl->parameters_set_by_user;
296 
297  if (flag == CONFIG_USER) {
298  set_by_user.insert(name);
299  }
300 
301  // stop if we're setting the default value and this parameter was set by user already
302  if (flag == CONFIG_DEFAULT and
303  set_by_user.find(name) != set_by_user.end()) {
304  return;
305  }
306 
307  this->set_flag_impl(name, value);
308 }
309 
310 static bool special_parameter(const std::string &name) {
311  for (const auto &suffix : {"_doc", "_units", "_type", "_option", "_choices"}) {
312  if (ends_with(name, suffix)) {
313  return true;
314  }
315  }
316 
317  // The NetCDF-based configuration database stores parameters as attributes of a variable
318  // and CF conventions require that all variables have a "long name."
319  return (name == "long_name");
320 }
321 
322 void print_config(const Logger &log, int verbosity_threshhold, const Config &config) {
323  const int v = verbosity_threshhold;
324 
325  log.message(v,
326  "### Strings:\n"
327  "###\n");
328 
329  Config::Strings strings = config.all_strings();
330 
331  // find max. name size
332  size_t max_name_size = 0;
333  for (const auto &s : strings) {
334  if (special_parameter(s.first)) {
335  continue;
336  }
337  max_name_size = std::max(max_name_size, s.first.size());
338  }
339 
340  // print strings
341  for (const auto &s : strings) {
342  std::string name = s.first;
343  std::string value = s.second;
344 
345  if (value.empty() or special_parameter(name)) {
346  continue;
347  }
348 
349  std::string padding(max_name_size - name.size(), ' ');
350 
351  if (config.type(name) == "keyword") {
352  log.message(v, " %s%s = \"%s\" (allowed choices: %s)\n",
353  name.c_str(), padding.c_str(), value.c_str(),
354  config.choices(name).c_str());
355  } else {
356  log.message(v, " %s%s = \"%s\"\n", name.c_str(), padding.c_str(), value.c_str());
357  }
358  }
359 
360  log.message(v,
361  "### Doubles:\n"
362  "###\n");
363 
364  // find max. name size
365  max_name_size = 0;
366  for (const auto &d : config.all_doubles()) {
367  max_name_size = std::max(max_name_size, d.first.size());
368  }
369  // print doubles
370  for (auto d : config.all_doubles()) {
371  std::string name = d.first;
372  double value = d.second[0];
373 
374  std::string units = config.units(name); // will be empty if not set
375  std::string padding(max_name_size - name.size(), ' ');
376 
377  const double large = 1.0e7;
378  const double small = 1.0e-4;
379  if (fabs(value) >= large or fabs(value) <= small) {
380  // use scientific notation if a number is big or small
381  log.message(v, " %s%s = %13.3e (%s)\n", name.c_str(), padding.c_str(), value, units.c_str());
382  } else {
383  log.message(v, " %s%s = %13.5f (%s)\n", name.c_str(), padding.c_str(), value, units.c_str());
384  }
385  }
386 
387  log.message(v,
388  "### Flags:\n"
389  "###\n");
390 
391  // find max. name size
392  max_name_size = 0;
393  for (const auto &b : config.all_flags()) {
394  max_name_size = std::max(max_name_size, b.first.size());
395  }
396 
397  // print flags
398  for (const auto &b : config.all_flags()) {
399  std::string name = b.first;
400  std::string value = b.second ? "true" : "false";
401  std::string padding(max_name_size - name.size(), ' ');
402 
403  log.message(v, " %s%s = %s\n", name.c_str(), padding.c_str(), value.c_str());
404  }
405 
406  log.message(v,
407  "### List of configuration parameters ends here.\n"
408  "###\n");
409 }
410 
411 void print_unused_parameters(const Logger &log, int verbosity_threshhold,
412  const Config &config) {
413  std::set<std::string> parameters_set = config.parameters_set_by_user();
414  std::set<std::string> parameters_used = config.parameters_used();
415 
416  if (options::Bool("-options_left", "report unused options")) {
417  verbosity_threshhold = log.get_threshold();
418  }
419 
420  for (const auto &p : parameters_set) {
421 
422  if (special_parameter(p)) {
423  continue;
424  }
425 
426  if (parameters_used.find(p) == parameters_used.end()) {
427  log.message(verbosity_threshhold,
428  "PISM WARNING: flag or parameter \"%s\" was set but was not used!\n",
429  p.c_str());
430 
431  }
432  }
433 }
434 
435 // command-line options
436 
437 //! Get a flag from a command-line option.
438 /*!
439  * Use the command-line option `option` to set the configuration parameter `parameter_name`.
440  *
441  * When called as `set_flag_from_option(config, "foo", "bar")`,
442  *
443  * sets the configuration parameter `bar` to `true` if
444  *
445  * - `-foo` is set (no argument)
446  * - `-foo true` is set
447  * - `-foo True` is set
448  * - `-foo yes` is set
449  *
450  * sets the `bar` to `false` if
451  *
452  * - `-foo false` is set
453  * - `-foo False` is set
454  * - `-foo no` is set
455  * - `-no_foo is set.
456  *
457  * `-foo X` with `X` not equal to `yes`, `no`, `true`, `True`, `false`, `False` results in an error.
458  */
459 void set_flag_from_option(Config &config, const std::string &option,
460  const std::string &parameter_name) {
461 
462  // get the default value
463  bool value = config.get_flag(parameter_name, Config::FORGET_THIS_USE);
464  std::string doc = config.doc(parameter_name);
465 
466  // process the command-line option
467  options::String opt("-" + option, doc, value ? "true" : "false", options::ALLOW_EMPTY);
468 
469  if (opt.is_set()) {
470  if (member(opt.value(), { "", "on", "yes", "true", "True" })) {
471 
472  value = true;
473 
474  } else if (member(opt.value(), { "off", "no", "false", "False" })) {
475 
476  value = false;
477 
478  } else {
479  throw RuntimeError::formatted(PISM_ERROR_LOCATION, "invalid -%s argument: %s", option.c_str(),
480  opt.value().c_str());
481  }
482  }
483 
484  // For backward compatibility we allow disabling an option -foo by setting -no_foo.
485  {
486  bool no_foo_is_set = options::Bool("-no_" + option, doc);
487 
488  if (no_foo_is_set) {
489  if (opt.is_set()) {
491  "Inconsistent command-line options:"
492  " both -%s and -no_%s are set.\n",
493  option.c_str(), option.c_str());
494  }
495 
496  value = false;
497  }
498  }
499 
500  config.set_flag(parameter_name, value, CONFIG_USER);
501 }
502 
503 //! Sets a configuration parameter from a command-line option.
504 /*!
505  If called as number_from_option("foo", "foo"), checks -foo and calls set("foo", value).
506 
507  Does nothing if -foo was not set.
508 
509  Note that no unit conversion is performed; parameters should be stored in
510  input units and converted as needed. (This allows saving parameters without
511  converting again.)
512 */
513 void set_number_from_option(units::System::Ptr unit_system, Config &config, const std::string &name,
514  const std::string &parameter) {
515  options::Real option(unit_system, "-" + name, config.doc(parameter), config.units(parameter),
516  config.get_number(parameter, Config::FORGET_THIS_USE));
517  if (option.is_set()) {
518  config.set_number(parameter, option, CONFIG_USER);
519  }
520 }
521 
522 /*!
523  * Use a command-line option -option to set a parameter that is a list of numbers.
524  *
525  * The length of the list given as an argument to the command-line option has to be the
526  * same as the length of the default value of the parameter *unless* the length of the
527  * default value is less than 2. This default value length is used to disable this check.
528  */
529 void set_number_list_from_option(Config &config, const std::string &option,
530  const std::string &parameter) {
531  auto default_value = config.get_numbers(parameter, Config::FORGET_THIS_USE);
532  options::RealList list("-" + option, config.doc(parameter), default_value);
533 
534  if (list.is_set()) {
535  if (default_value.size() < 2 and list->size() != default_value.size()) {
537  "Option -%s requires a list of %d numbers (got %d instead).",
538  option.c_str(), (int)default_value.size(), (int)list->size());
539  }
540 
541  config.set_numbers(parameter, list, CONFIG_USER);
542  }
543 }
544 
545 /*!
546  * Use a command-line option -option to set a parameter that is a list of integers.
547  *
548  * The length of the list given as an argument to the command-line option has to be the
549  * same as the length of the default value of the parameter *unless* the length of the
550  * default value is less than 2. This default value length is used to disable this check.
551  */
552 void set_integer_list_from_option(Config &config, const std::string &option,
553  const std::string &parameter) {
554  std::vector<int> default_value;
555 
556  for (auto v : config.get_numbers(parameter, Config::FORGET_THIS_USE)) {
557  default_value.push_back(v);
558  }
559 
560  options::IntegerList list("-" + option, config.doc(parameter), default_value);
561 
562  std::vector<double> value;
563  for (auto v : list.value()) {
564  value.push_back(v);
565  }
566 
567  if (list.is_set()) {
568  if (default_value.size() < 2 and value.size() != default_value.size()) {
570  "Option -%s requires a list of %d integers (got %d instead).",
571  option.c_str(), (int)default_value.size(), (int)value.size());
572  }
573 
574  config.set_numbers(parameter, value, CONFIG_USER);
575  }
576 }
577 
578 void set_integer_from_option(Config &config, const std::string &name,
579  const std::string &parameter) {
580  options::Integer option("-" + name, config.doc(parameter),
581  (int)config.get_number(parameter, Config::FORGET_THIS_USE));
582  if (option.is_set()) {
583  config.set_number(parameter, option, CONFIG_USER);
584  }
585 }
586 
587 void set_string_from_option(Config &config, const std::string &name, const std::string &parameter) {
588 
589  options::String value("-" + name, config.doc(parameter),
590  config.get_string(parameter, Config::FORGET_THIS_USE));
591  if (value.is_set()) {
592  config.set_string(parameter, value, CONFIG_USER);
593  }
594 }
595 
596 //! \brief Set a keyword parameter from a command-line option.
597 /*!
598  * This sets the parameter "parameter" after checking the "-name" command-line
599  * option. This option requires an argument, which has to match one of the
600  * keyword given in a comma-separated list "choices_list".
601  */
602 void set_keyword_from_option(Config &config, const std::string &name, const std::string &parameter,
603  const std::string &choices) {
604 
605  options::Keyword keyword("-" + name, config.doc(parameter), choices,
606  config.get_string(parameter, Config::FORGET_THIS_USE));
607 
608  if (keyword.is_set()) {
609  config.set_string(parameter, keyword, CONFIG_USER);
610  }
611 }
612 
614  const std::string &name) {
615 
616  // skip special parameters ("attributes" of parameters)
617  if (special_parameter(name)) {
618  return;
619  }
620 
621  // Use parameter name as its own command-line option by default. parameter_name_option can specify
622  // a different (possibly shorter) command-line option.
623  std::string option = name;
624 
625  if (not config.option(name).empty()) { // there is a short version of the command-line option
626  std::string short_option = config.option(name);
627  std::string description = config.doc(name);
628 
629  if (options::Bool("-" + short_option, description) or
630  options::Bool("-no_" + short_option, description)) { // short option is set
631  if (options::Bool("-" + option, description)) {
633  "both -%s and -%s are set (please use one or the other)",
634  option.c_str(), short_option.c_str());
635  }
636 
637  // Use the short option only if the user set it, otherwise used the full (long) option below.
638  option = short_option;
639  }
640  }
641 
642  std::string type = config.type(name);
643 
644  if (type == "string") {
645  set_string_from_option(config, option, name);
646  } else if (type == "flag") {
647  set_flag_from_option(config, option, name);
648  } else if (type == "number") {
649  set_number_from_option(unit_system, config, option, name);
650  } else if (type == "integer") {
651  set_integer_from_option(config, option, name);
652  } else if (type == "keyword") {
653  set_keyword_from_option(config, option, name, config.choices(name));
654  } else {
655  throw RuntimeError::formatted(PISM_ERROR_LOCATION, "parameter type \"%s\" is invalid",
656  type.c_str());
657  }
658 }
659 
661  for (const auto &d : config.all_doubles()) {
662  set_parameter_from_options(unit_system, config, d.first);
663  }
664 
665  for (const auto &s : config.all_strings()) {
666  set_parameter_from_options(unit_system, config, s.first);
667  }
668 
669  for (const auto &b : config.all_flags()) {
670  set_parameter_from_options(unit_system, config, b.first);
671  }
672 
673  // Energy modeling
674  {
675  options::Keyword energy("-energy",
676  "choose the energy model (one of 'none', 'cold', 'enthalpy')",
677  "none,cold,enthalpy", "enthalpy");
678 
679  if (energy.is_set()) {
680  if (energy == "none") {
681  config.set_flag("energy.enabled", false, CONFIG_USER);
682  // Allow selecting cold ice flow laws in isothermal mode.
683  config.set_flag("energy.temperature_based", true, CONFIG_USER);
684  } else if (energy == "cold") {
685  config.set_flag("energy.enabled", true, CONFIG_USER);
686  config.set_flag("energy.temperature_based", true, CONFIG_USER);
687  } else if (energy == "enthalpy") {
688  config.set_flag("energy.enabled", true, CONFIG_USER);
689  config.set_flag("energy.temperature_based", false, CONFIG_USER);
690  } else {
692  "this can't happen: options::Keyword validates input");
693  }
694  }
695  }
696 
697  // -topg_to_phi
698  {
699  std::vector<double> defaults = {
700  config.get_number("basal_yield_stress.mohr_coulomb.topg_to_phi.phi_min"),
701  config.get_number("basal_yield_stress.mohr_coulomb.topg_to_phi.phi_max"),
702  config.get_number("basal_yield_stress.mohr_coulomb.topg_to_phi.topg_min"),
703  config.get_number("basal_yield_stress.mohr_coulomb.topg_to_phi.topg_max")
704  };
705 
706  options::RealList topg_to_phi("-topg_to_phi", "phi_min, phi_max, topg_min, topg_max", defaults);
707  if (topg_to_phi.is_set()) {
708  if (topg_to_phi->size() != 4) {
710  "option -topg_to_phi expected 4 numbers; got %d",
711  (int)topg_to_phi->size());
712  }
713  config.set_flag("basal_yield_stress.mohr_coulomb.topg_to_phi.enabled", true);
714  config.set_number("basal_yield_stress.mohr_coulomb.topg_to_phi.phi_min", topg_to_phi[0]);
715  config.set_number("basal_yield_stress.mohr_coulomb.topg_to_phi.phi_max", topg_to_phi[1]);
716  config.set_number("basal_yield_stress.mohr_coulomb.topg_to_phi.topg_min", topg_to_phi[2]);
717  config.set_number("basal_yield_stress.mohr_coulomb.topg_to_phi.topg_max", topg_to_phi[3]);
718  }
719  }
720  // Ice shelves
721 
722  bool nu_bedrock = options::Bool("-nu_bedrock", "constant viscosity near margins");
723  if (nu_bedrock) {
724  config.set_flag("stress_balance.ssa.fd.lateral_drag.enabled", true, CONFIG_USER);
725  }
726 
727  // Shortcuts
728 
729  // option "-pik" turns on a suite of PISMPIK effects (but NOT a calving choice,
730  // and in particular NOT "-calving eigen_calving")
731  bool pik = options::Bool("-pik", "enable suite of PISM-PIK mechanisms");
732  if (pik) {
733  config.set_flag("stress_balance.calving_front_stress_bc", true, CONFIG_USER);
734  config.set_flag("geometry.part_grid.enabled", true, CONFIG_USER);
735  config.set_flag("geometry.remove_icebergs", true, CONFIG_USER);
736  config.set_flag("geometry.grounded_cell_fraction", true, CONFIG_USER);
737  }
738 
739  if (config.get_string("calving.methods").find("eigen_calving") != std::string::npos) {
740  config.set_flag("geometry.part_grid.enabled", true, CONFIG_USER);
741  // eigen-calving requires a wider stencil:
742  config.set_number("grid.max_stencil_width", 3);
743  }
744 
745  // all calving mechanisms require iceberg removal
746  if (not config.get_string("calving.methods").empty()) {
747  config.set_flag("geometry.remove_icebergs", true, CONFIG_USER);
748  }
749 
750  // geometry.remove_icebergs requires part_grid
751  if (config.get_flag("geometry.remove_icebergs")) {
752  config.set_flag("geometry.part_grid.enabled", true, CONFIG_USER);
753  }
754 
755  bool test_climate_models =
756  options::Bool("-test_climate_models", "Disable ice dynamics to test climate models");
757  if (test_climate_models) {
758  config.set_string("stress_balance.model", "none", CONFIG_USER);
759  config.set_flag("energy.enabled", false, CONFIG_USER);
760  config.set_flag("age.enabled", false, CONFIG_USER);
761  // let the user decide if they want to use "-no_mass" or not
762  }
763 
764  // If frontal melt code includes floating ice, routing hydrology should include it also.
765  if (config.get_string("hydrology.model") == "routing") {
766  if (config.get_flag("frontal_melt.include_floating_ice")) {
767  config.set_flag("hydrology.routing.include_floating_ice", true);
768  }
769  }
770 
771  if (config.get_flag("output.ISMIP6")) {
772  // use MKS units in ISMIP6 mode
773  config.set_flag("output.use_MKS", true);
774  }
775 }
776 
777 //! Create a configuration database using command-line options.
778 Config::Ptr config_from_options(MPI_Comm com, const Logger &log, units::System::Ptr unit_system) {
779 
780  DefaultConfig::Ptr config(new DefaultConfig(com, "pism_config", "-config", unit_system)),
781  overrides(new DefaultConfig(com, "pism_overrides", "-config_override", unit_system));
782  overrides->init(log);
783  config->init_with_default(log);
784  config->import_from(*overrides);
785  set_config_from_options(unit_system, *config);
786  config->resolve_filenames();
787 
788  return config;
789 }
790 
792  : m_prefix(prefix), m_config(c) {
793  // empty
794 }
795 
796 double ConfigWithPrefix::get_number(const std::string &name) const {
797  return m_config->get_number(m_prefix + name);
798 }
799 
800 double ConfigWithPrefix::get_number(const std::string &name, const std::string &units) const {
801  return m_config->get_number(m_prefix + name, units);
802 }
803 
804 std::string ConfigWithPrefix::get_string(const std::string &name) const {
805  return m_config->get_string(m_prefix + name);
806 }
807 
808 bool ConfigWithPrefix::get_flag(const std::string &name) const {
809  return m_config->get_flag(m_prefix + name);
810 }
811 
812 void ConfigWithPrefix::reset_prefix(const std::string &prefix) {
813  m_prefix = prefix;
814 }
815 
816 std::set<std::string> Config::keys() const {
817  std::set<std::string> result;
818 
819  for (const auto &p : all_doubles()) {
820  result.insert(p.first);
821  }
822 
823  for (const auto &p : all_strings()) {
824  result.insert(p.first);
825  }
826 
827  for (const auto &p : all_flags()) {
828  result.insert(p.first);
829  }
830 
831  return result;
832 }
833 
834 std::string Config::doc(const std::string &parameter) const {
835  return this->get_string(parameter + "_doc", Config::FORGET_THIS_USE);
836 }
837 
838 std::string Config::units(const std::string &parameter) const {
839  return this->get_string(parameter + "_units", Config::FORGET_THIS_USE);
840 }
841 
842 std::string Config::type(const std::string &parameter) const {
843  return this->get_string(parameter + "_type", Config::FORGET_THIS_USE);
844 }
845 
846 std::string Config::option(const std::string &parameter) const {
847  if (this->is_set(parameter + "_option")) {
848  return this->get_string(parameter + "_option", Config::FORGET_THIS_USE);
849  }
850 
851  return "";
852 }
853 
854 std::string Config::choices(const std::string &parameter) const {
855  return this->get_string(parameter + "_choices", Config::FORGET_THIS_USE);
856 }
857 
858 
859 
860 } // 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::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
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)
virtual void set_string_impl(const std::string &name, const std::string &value)=0
std::string units(const std::string &parameter) const
virtual std::vector< double > get_numbers_impl(const std::string &name) const =0
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.
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()
A class for storing and accessing PISM configuration flags and parameters.
std::shared_ptr< DefaultConfig > Ptr
Definition: Config.hh:80
Default PISM configuration database: uses NetCDF files; can be initialized from a file specified usin...
Definition: Config.hh:72
std::string filename() const
Definition: File.cc:307
High-level PISM I/O class.
Definition: File.hh:56
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
double max(const array::Scalar &input)
Finds maximum over all the values in an array::Scalar object. Ignores ghosts.
Definition: Scalar.cc:165
@ 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:78
@ PISM_READONLY
open an existing file for reading only
Definition: IO_Flags.hh:72
@ PISM_READWRITE
open an existing file for reading and writing
Definition: IO_Flags.hh:74
bool Bool(const std::string &option, const std::string &description)
Definition: options.cc:240
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_list_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.
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 &name, const std::string &parameter)
Sets a configuration parameter from a command-line option.
void set_string_from_option(Config &config, const std::string &name, 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_integer_from_option(Config &config, const std::string &name, const std::string &parameter)
void set_flag_from_option(Config &config, const std::string &option, const std::string &parameter_name)
Get a flag from a command-line option.
void set_number_list_from_option(Config &config, const std::string &option, const std::string &parameter)
ConfigSettingFlag
Flag used by set_...() methods.
@ CONFIG_DEFAULT
void print_unused_parameters(const Logger &log, int verbosity_threshhold, const Config &config)
Report unused configuration parameters to stdout.
void set_parameter_from_options(units::System::Ptr unit_system, Config &config, const std::string &name)
Set one parameter using command-line options.
void set_keyword_from_option(Config &config, const std::string &name, const std::string &parameter, const std::string &choices)
Set a keyword parameter from a command-line option.
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.