tConfigInterface.cc - pism - [fork] customized build of PISM, the parallel ice sheet model (tillflux branch)
(HTM) git clone git://src.adamsgaard.dk/pism
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) LICENSE
---
tConfigInterface.cc (28456B)
---
1 /* Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020 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 {
38 Impl(units::System::Ptr sys)
39 : unit_system(sys) {
40 // empty
41 }
42
43 units::System::Ptr unit_system;
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
55 Config::Config(units::System::Ptr system)
56 : m_impl(new Impl(system)) {
57 // empty
58 }
59
60 Config::~Config() {
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 (auto p : other.all_doubles()) {
98 if (member(p.first, parameters)) {
99 this->set_numbers(p.first, p.second, CONFIG_USER);
100 } else {
101 throw RuntimeError::formatted(PISM_ERROR_LOCATION,
102 "unrecognized parameter %s in %s",
103 p.first.c_str(), other.filename().c_str());
104 }
105 }
106
107 for (auto p : other.all_strings()) {
108 if (member(p.first, parameters)) {
109 this->set_string(p.first, p.second, CONFIG_USER);
110 } else {
111 throw RuntimeError::formatted(PISM_ERROR_LOCATION,
112 "unrecognized parameter %s in %s",
113 p.first.c_str(), other.filename().c_str());
114 }
115 }
116
117 for (auto p : other.all_flags()) {
118 if (member(p.first, parameters)) {
119 this->set_flag(p.first, p.second, CONFIG_USER);
120 } else {
121 throw RuntimeError::formatted(PISM_ERROR_LOCATION,
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 {
129 return m_impl->parameters_set_by_user;
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
140 Config::Doubles Config::all_doubles() const {
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
227 Config::Strings Config::all_strings() const {
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
256 Config::Flags Config::all_flags() const {
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 (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 if (name == "long_name") {
294 return true;
295 }
296
297 return false;
298 }
299
300 void print_config(const Logger &log, int verbosity_threshhold, const Config &config) {
301 const int v = verbosity_threshhold;
302
303 log.message(v,
304 "### Strings:\n"
305 "###\n");
306
307 Config::Strings strings = config.all_strings();
308
309 // find max. name size
310 size_t max_name_size = 0;
311 for (auto s : strings) {
312 if (special_parameter(s.first)) {
313 continue;
314 }
315 max_name_size = std::max(max_name_size, s.first.size());
316 }
317
318 // print strings
319 for (auto s : strings) {
320 std::string name = s.first;
321 std::string value = s.second;
322
323 if (value.empty() or special_parameter(name)) {
324 continue;
325 }
326
327 std::string padding(max_name_size - name.size(), ' ');
328
329 if (config.type(name) == "keyword") {
330 log.message(v, " %s%s = \"%s\" (allowed choices: %s)\n",
331 name.c_str(), padding.c_str(), value.c_str(),
332 config.choices(name).c_str());
333 } else {
334 log.message(v, " %s%s = \"%s\"\n", name.c_str(), padding.c_str(), value.c_str());
335 }
336 }
337
338 log.message(v,
339 "### Doubles:\n"
340 "###\n");
341
342 // find max. name size
343 max_name_size = 0;
344 for (auto d : config.all_doubles()) {
345 max_name_size = std::max(max_name_size, d.first.size());
346 }
347 // print doubles
348 for (auto d : config.all_doubles()) {
349 std::string name = d.first;
350 double value = d.second[0];
351
352 std::string units = config.units(name); // will be empty if not set
353 std::string padding(max_name_size - name.size(), ' ');
354
355 if (fabs(value) >= 1.0e7 or fabs(value) <= 1.0e-4) {
356 // use scientific notation if a number is big or small
357 log.message(v, " %s%s = %13.3e (%s)\n", name.c_str(), padding.c_str(), value, units.c_str());
358 } else {
359 log.message(v, " %s%s = %13.5f (%s)\n", name.c_str(), padding.c_str(), value, units.c_str());
360 }
361 }
362
363 log.message(v,
364 "### Flags:\n"
365 "###\n");
366
367 // find max. name size
368 max_name_size = 0;
369 for (auto b : config.all_flags()) {
370 max_name_size = std::max(max_name_size, b.first.size());
371 }
372
373 // print flags
374 for (auto b : config.all_flags()) {
375 std::string name = b.first;
376 std::string value = b.second ? "true" : "false";
377 std::string padding(max_name_size - name.size(), ' ');
378
379 log.message(v, " %s%s = %s\n", name.c_str(), padding.c_str(), value.c_str());
380 }
381
382 log.message(v,
383 "### List of configuration parameters ends here.\n"
384 "###\n");
385 }
386
387 void print_unused_parameters(const Logger &log, int verbosity_threshhold,
388 const Config &config) {
389 std::set<std::string> parameters_set = config.parameters_set_by_user();
390 std::set<std::string> parameters_used = config.parameters_used();
391
392 if (options::Bool("-options_left", "report unused options")) {
393 verbosity_threshhold = log.get_threshold();
394 }
395
396 for (auto p : parameters_set) {
397
398 if (special_parameter(p)) {
399 continue;
400 }
401
402 if (parameters_used.find(p) == parameters_used.end()) {
403 log.message(verbosity_threshhold,
404 "PISM WARNING: flag or parameter \"%s\" was set but was not used!\n",
405 p.c_str());
406
407 }
408 }
409 }
410
411 // command-line options
412
413 //! Get a flag from a command-line option.
414 /*!
415 * Use the command-line option `option` to set the configuration parameter `parameter_name`.
416 *
417 * When called as `set_flag_from_option(config, "foo", "bar")`,
418 *
419 * sets the configuration parameter `bar` to `true` if
420 *
421 * - `-foo` is set (no argument)
422 * - `-foo true` is set
423 * - `-foo True` is set
424 * - `-foo yes` is set
425 *
426 * sets the `bar` to `false` if
427 *
428 * - `-foo false` is set
429 * - `-foo False` is set
430 * - `-foo no` is set
431 * - `-no_foo is set.
432 *
433 * `-foo X` with `X` not equal to `yes`, `no`, `true`, `True`, `false`, `False` results in an error.
434 */
435 void set_flag_from_option(Config &config, const std::string &option,
436 const std::string ¶meter_name) {
437
438 // get the default value
439 bool value = config.get_flag(parameter_name, Config::FORGET_THIS_USE);
440 std::string doc = config.doc(parameter_name);
441
442 // process the command-line option
443 options::String opt("-" + option, doc, value ? "true" : "false", options::ALLOW_EMPTY);
444
445 if (opt.is_set()) {
446 if (opt.value() == "" or
447 opt.value() == "on" or
448 opt.value() == "yes" or
449 opt.value() == "true" or
450 opt.value() == "True") { // Python's "True"
451
452 value = true;
453
454 } else if (opt.value() == "off" or
455 opt.value() == "no" or
456 opt.value() == "false" or
457 opt.value() == "False") { // Python's "False"
458
459 value = false;
460
461 } else {
462 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "invalid -%s argument: %s",
463 option.c_str(), opt.value().c_str());
464 }
465 }
466
467 // For backward compatibility we allow disabling an option -foo by setting -no_foo.
468 {
469 bool no_foo_is_set = options::Bool("-no_" + option, doc);
470
471 if (no_foo_is_set) {
472 if (opt.is_set()) {
473 throw RuntimeError::formatted(PISM_ERROR_LOCATION,
474 "Inconsistent command-line options:"
475 " both -%s and -no_%s are set.\n",
476 option.c_str(), option.c_str());
477 } else {
478 value = false;
479 }
480 }
481 }
482
483 config.set_flag(parameter_name, value, CONFIG_USER);
484 }
485
486 //! Sets a configuration parameter from a command-line option.
487 /*!
488 If called as number_from_option("foo", "foo"), checks -foo and calls set("foo", value).
489
490 Does nothing if -foo was not set.
491
492 Note that no unit conversion is performed; parameters should be stored in
493 input units and converted as needed. (This allows saving parameters without
494 converting again.)
495 */
496 void set_number_from_option(Config &config, const std::string &name, const std::string ¶meter) {
497 options::Real option("-" + name, config.doc(parameter),
498 config.get_number(parameter, Config::FORGET_THIS_USE));
499 if (option.is_set()) {
500 config.set_number(parameter, option, CONFIG_USER);
501 }
502 }
503
504 /*!
505 * Use a command-line option -option to set a parameter that is a list of numbers.
506 *
507 * The length of the list given as an argument to the command-line option has to be the
508 * same as the length of the default value of the parameter *unless* the length of the
509 * default value is less than 2. This default value length is used to disable this check.
510 */
511 void set_number_list_from_option(Config &config, const std::string &option,
512 const std::string ¶meter) {
513 auto default_value = config.get_numbers(parameter, Config::FORGET_THIS_USE);
514 options::RealList list("-" + option, config.doc(parameter), default_value);
515
516 if (list.is_set()) {
517 if (default_value.size() < 2 and list->size() != default_value.size()) {
518 throw RuntimeError::formatted(PISM_ERROR_LOCATION,
519 "Option -%s requires a list of %d numbers (got %d instead).",
520 option.c_str(),
521 (int)default_value.size(),
522 (int)list->size());
523 }
524
525 config.set_numbers(parameter, list, CONFIG_USER);
526 }
527 }
528
529 /*!
530 * Use a command-line option -option to set a parameter that is a list of integers.
531 *
532 * The length of the list given as an argument to the command-line option has to be the
533 * same as the length of the default value of the parameter *unless* the length of the
534 * default value is less than 2. This default value length is used to disable this check.
535 */
536 void set_integer_list_from_option(Config &config, const std::string &option,
537 const std::string ¶meter) {
538 std::vector<int> default_value;
539
540 for (auto v : config.get_numbers(parameter, Config::FORGET_THIS_USE)) {
541 default_value.push_back(v);
542 }
543
544 options::IntegerList list("-" + option, config.doc(parameter), default_value);
545
546 std::vector<double> value;
547 for (auto v : list.value()) {
548 value.push_back(v);
549 }
550
551 if (list.is_set()) {
552 if (default_value.size() < 2 and value.size() != default_value.size()) {
553 throw RuntimeError::formatted(PISM_ERROR_LOCATION,
554 "Option -%s requires a list of %d integers (got %d instead).",
555 option.c_str(),
556 (int)default_value.size(),
557 (int)value.size());
558 }
559
560 config.set_numbers(parameter, value, CONFIG_USER);
561 }
562 }
563
564 void set_integer_from_option(Config &config, const std::string &name, const std::string ¶meter) {
565 options::Integer option("-" + name, config.doc(parameter),
566 config.get_number(parameter, Config::FORGET_THIS_USE));
567 if (option.is_set()) {
568 config.set_number(parameter, option, CONFIG_USER);
569 }
570 }
571
572 void set_string_from_option(Config &config, const std::string &name, const std::string ¶meter) {
573
574 options::String value("-" + name, config.doc(parameter),
575 config.get_string(parameter, Config::FORGET_THIS_USE));
576 if (value.is_set()) {
577 config.set_string(parameter, value, CONFIG_USER);
578 }
579 }
580
581 //! \brief Set a keyword parameter from a command-line option.
582 /*!
583 * This sets the parameter "parameter" after checking the "-name" command-line
584 * option. This option requires an argument, which has to match one of the
585 * keyword given in a comma-separated list "choices_list".
586 */
587 void set_keyword_from_option(Config &config, const std::string &name,
588 const std::string ¶meter,
589 const std::string &choices) {
590
591 options::Keyword keyword("-" + name, config.doc(parameter), choices,
592 config.get_string(parameter, Config::FORGET_THIS_USE));
593
594 if (keyword.is_set()) {
595 config.set_string(parameter, keyword, CONFIG_USER);
596 }
597 }
598
599 void set_parameter_from_options(Config &config, const std::string &name) {
600
601 // skip special parameters ("attributes" of parameters)
602 if (special_parameter(name)) {
603 return;
604 }
605
606 // Use parameter name as its own command-line option by default. parameter_name_option can specify
607 // a different (possibly shorter) command-line option.
608 std::string option = name;
609
610 if (not config.option(name).empty()) { // there is a short version of the command-line option
611 std::string
612 short_option = config.option(name),
613 description = config.doc(name);
614
615 if (options::Bool("-" + short_option, description) or
616 options::Bool("-no_" + short_option, description)) { // short option is set
617 if (options::Bool("-" + option, description)) {
618 throw RuntimeError::formatted(PISM_ERROR_LOCATION,
619 "both -%s and -%s are set (please use one or the other)",
620 option.c_str(), short_option.c_str());
621 }
622
623 // Use the short option only if the user set it, otherwise used the full (long) option below.
624 option = short_option;
625 }
626 }
627
628 std::string type = config.type(name);
629
630 if (type == "string") {
631 set_string_from_option(config, option, name);
632 } else if (type == "flag") {
633 set_flag_from_option(config, option, name);
634 } else if (type == "number") {
635 set_number_from_option(config, option, name);
636 } else if (type == "integer") {
637 set_integer_from_option(config, option, name);
638 } else if (type == "keyword") {
639 set_keyword_from_option(config, option, name, config.choices(name));
640 } else {
641 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "parameter type \"%s\" is invalid", type.c_str());
642 }
643 }
644
645 void set_config_from_options(Config &config) {
646 for (auto d : config.all_doubles()) {
647 set_parameter_from_options(config, d.first);
648 }
649
650 for (auto s : config.all_strings()) {
651 set_parameter_from_options(config, s.first);
652 }
653
654 for (auto b : config.all_flags()) {
655 set_parameter_from_options(config, b.first);
656 }
657
658 // Energy modeling
659 {
660 options::Keyword energy("-energy",
661 "choose the energy model (one of 'none', 'cold', 'enthalpy')",
662 "none,cold,enthalpy", "enthalpy");
663
664 if (energy.is_set()) {
665 if (energy == "none") {
666 config.set_flag("energy.enabled", false, CONFIG_USER);
667 // Allow selecting cold ice flow laws in isothermal mode.
668 config.set_flag("energy.temperature_based", true, CONFIG_USER);
669 } else if (energy == "cold") {
670 config.set_flag("energy.enabled", true, CONFIG_USER);
671 config.set_flag("energy.temperature_based", true, CONFIG_USER);
672 } else if (energy == "enthalpy") {
673 config.set_flag("energy.enabled", true, CONFIG_USER);
674 config.set_flag("energy.temperature_based", false, CONFIG_USER);
675 } else {
676 throw RuntimeError(PISM_ERROR_LOCATION, "this can't happen: options::Keyword validates input");
677 }
678 }
679 }
680
681 // -topg_to_phi
682 {
683 std::vector<double> defaults = {
684 config.get_number("basal_yield_stress.mohr_coulomb.topg_to_phi.phi_min"),
685 config.get_number("basal_yield_stress.mohr_coulomb.topg_to_phi.phi_max"),
686 config.get_number("basal_yield_stress.mohr_coulomb.topg_to_phi.topg_min"),
687 config.get_number("basal_yield_stress.mohr_coulomb.topg_to_phi.topg_max")
688 };
689
690 options::RealList topg_to_phi("-topg_to_phi", "phi_min, phi_max, topg_min, topg_max",
691 defaults);
692 if (topg_to_phi.is_set()) {
693 if (topg_to_phi->size() != 4) {
694 throw RuntimeError::formatted(PISM_ERROR_LOCATION,
695 "option -topg_to_phi expected 4 numbers; got %d",
696 (int)topg_to_phi->size());
697 }
698 config.set_flag("basal_yield_stress.mohr_coulomb.topg_to_phi.enabled", true);
699 config.set_number("basal_yield_stress.mohr_coulomb.topg_to_phi.phi_min", topg_to_phi[0]);
700 config.set_number("basal_yield_stress.mohr_coulomb.topg_to_phi.phi_max", topg_to_phi[1]);
701 config.set_number("basal_yield_stress.mohr_coulomb.topg_to_phi.topg_min", topg_to_phi[2]);
702 config.set_number("basal_yield_stress.mohr_coulomb.topg_to_phi.topg_max", topg_to_phi[3]);
703 }
704 }
705 // Ice shelves
706
707 bool nu_bedrock = options::Bool("-nu_bedrock", "constant viscosity near margins");
708 if (nu_bedrock) {
709 config.set_flag("stress_balance.ssa.fd.lateral_drag.enabled", true, CONFIG_USER);
710 }
711
712 // Shortcuts
713
714 // option "-pik" turns on a suite of PISMPIK effects (but NOT a calving choice,
715 // and in particular NOT "-calving eigen_calving")
716 bool pik = options::Bool("-pik", "enable suite of PISM-PIK mechanisms");
717 if (pik) {
718 config.set_flag("stress_balance.calving_front_stress_bc", true, CONFIG_USER);
719 config.set_flag("geometry.part_grid.enabled", true, CONFIG_USER);
720 config.set_flag("geometry.remove_icebergs", true, CONFIG_USER);
721 config.set_flag("geometry.grounded_cell_fraction", true, CONFIG_USER);
722 }
723
724 if (config.get_string("calving.methods").find("eigen_calving") != std::string::npos) {
725 config.set_flag("geometry.part_grid.enabled", true, CONFIG_USER);
726 // eigen-calving requires a wider stencil:
727 config.set_number("grid.max_stencil_width", 3);
728 }
729
730 // all calving mechanisms require iceberg removal
731 if (not config.get_string("calving.methods").empty()) {
732 config.set_flag("geometry.remove_icebergs", true, CONFIG_USER);
733 }
734
735 // geometry.remove_icebergs requires part_grid
736 if (config.get_flag("geometry.remove_icebergs")) {
737 config.set_flag("geometry.part_grid.enabled", true, CONFIG_USER);
738 }
739
740 bool test_climate_models = options::Bool("-test_climate_models",
741 "Disable ice dynamics to test climate models");
742 if (test_climate_models) {
743 config.set_string("stress_balance.model", "none", CONFIG_USER);
744 config.set_flag("energy.enabled", false, CONFIG_USER);
745 config.set_flag("age.enabled", false, CONFIG_USER);
746 // let the user decide if they want to use "-no_mass" or not
747 }
748
749 // If frontal melt code includes floating ice, routing hydrology should include it also.
750 if (config.get_string("hydrology.model") == "routing") {
751 if (config.get_flag("frontal_melt.include_floating_ice")) {
752 config.set_flag("hydrology.routing.include_floating_ice", true);
753 }
754 }
755
756 if (config.get_flag("output.ISMIP6")) {
757 // use MKS units in ISMIP6 mode
758 config.set_flag("output.use_MKS", true);
759 }
760
761 // old options
762 options::deprecated("-sliding_scale_brutal",
763 "-brutal_sliding' and '-brutal_sliding_scale");
764 options::deprecated("-ssa_sliding", "-stress_balance ...");
765 options::deprecated("-ssa_floating_only", "-stress_balance ...");
766 options::deprecated("-sia", "-stress_balance ...");
767 options::deprecated("-no_sia", "-stress_balance ...");
768 options::deprecated("-hold_tauc", "-yield_stress constant");
769 options::deprecated("-ocean_kill_file", "-front_retreat_file");
770 options::deprecated("-eigen_calving", "-calving eigen_calving -eigen_calving_K XXX");
771 options::deprecated("-calving_at_thickness",
772 "-calving thickness_calving -thickness_calving_threshold XXX");
773 options::deprecated("-float_kill", "-calving float_kill");
774 options::deprecated("-no_energy", "-energy none");
775 options::deprecated("-cold", "-energy cold");
776 options::deprecated("-boot_file", "-bootstrap -i");
777 }
778
779 //! Create a configuration database using command-line options.
780 Config::Ptr config_from_options(MPI_Comm com, const Logger &log, units::System::Ptr sys) {
781
782 DefaultConfig::Ptr config(new DefaultConfig(com, "pism_config", "-config", sys)),
783 overrides(new DefaultConfig(com, "pism_overrides", "-config_override", sys));
784 overrides->init(log);
785 config->init_with_default(log);
786 config->import_from(*overrides);
787 set_config_from_options(*config);
788
789 return config;
790 }
791
792 ConfigWithPrefix::ConfigWithPrefix(Config::ConstPtr c, const std::string &prefix)
793 : m_prefix(prefix), m_config(c) {
794 // empty
795 }
796
797 double ConfigWithPrefix::get_number(const std::string &name) const {
798 return m_config->get_number(m_prefix + name);
799 }
800
801 double ConfigWithPrefix::get_number(const std::string &name, const std::string &units) const {
802 return m_config->get_number(m_prefix + name, units);
803 }
804
805 std::string ConfigWithPrefix::get_string(const std::string &name) const {
806 return m_config->get_string(m_prefix + name);
807 }
808
809 bool ConfigWithPrefix::get_flag(const std::string& name) const {
810 return m_config->get_flag(m_prefix + name);
811 }
812
813 void ConfigWithPrefix::reset_prefix(const std::string &prefix) {
814 m_prefix = prefix;
815 }
816
817 std::set<std::string> Config::keys() const {
818 std::set<std::string> result;
819
820 for (auto p : all_doubles()) {
821 result.insert(p.first);
822 }
823
824 for (auto p : all_strings()) {
825 result.insert(p.first);
826 }
827
828 for (auto p : all_flags()) {
829 result.insert(p.first);
830 }
831
832 return result;
833 }
834
835 std::string Config::doc(const std::string ¶meter) const {
836 return this->get_string(parameter + "_doc", Config::FORGET_THIS_USE);
837 }
838
839 std::string Config::units(const std::string ¶meter) const {
840 return this->get_string(parameter + "_units", Config::FORGET_THIS_USE);
841 }
842
843 std::string Config::type(const std::string ¶meter) const {
844 return this->get_string(parameter + "_type", Config::FORGET_THIS_USE);
845 }
846
847 std::string Config::option(const std::string ¶meter) const {
848 if (this->is_set(parameter + "_option")) {
849 return this->get_string(parameter + "_option", Config::FORGET_THIS_USE);
850 } else {
851 return "";
852 }
853 }
854
855 std::string Config::choices(const std::string ¶meter) const {
856 return this->get_string(parameter + "_choices", Config::FORGET_THIS_USE);
857 }
858
859
860
861 } // end of namespace pism