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