25#include "pism/pism_config.hh"
26#include "pism/util/io/File.hh"
27#include "pism/util/Config.hh"
28#include "pism/util/Units.hh"
29#include "pism/util/pism_utilities.hh"
30#include "pism/util/pism_options.hh"
31#include "pism/util/error_handling.hh"
32#include "pism/util/io/IO_Flags.hh"
33#include "pism/util/io/OutputWriter.hh"
34#include "pism/external/nlohmann/json.hpp"
38#include "pism/util/NetCDFConfig.hh"
39#include "pism/util/Logger.hh"
62 : m_impl(new
Impl(system)) {
92 auto parameters = this->
keys();
99 "unrecognized parameter %s in %s",
100 p.first.c_str(), other.
filename().c_str());
109 "unrecognized parameter %s in %s",
110 p.first.c_str(), other.
filename().c_str());
114 for (
const auto &p : other.
all_flags()) {
119 "unrecognized parameter %s in %s",
120 p.first.c_str(), other.
filename().c_str());
127 auto parameter = s.first;
128 auto value = s.second;
134 auto last_token =
pism::split(parameter,
'.').back();
136 if (last_token ==
"file") {
137 char *resolved_path = realpath(value.c_str(), NULL);
139 if (resolved_path != NULL) {
168 if (std::get<0>(min)) {
177 if (std::get<0>(max)) {
199 if (
type(name) ==
"integer" and std::round(value) != value) {
202 "integer parameter '%s' was set to a number with a non-zero fractional part (%f)",
203 name.c_str(), value);
207 if (std::get<0>(min)) {
211 if (
type(name) ==
"integer") {
213 "Please set '%s' to a number greater than or equal to %d",
217 "Please set '%s' to a number greater than or equal to %f",
223 if (std::get<0>(max)) {
227 if (
type(name) ==
"integer") {
229 "Please set '%s' to a number less than or equal to %d",
233 "Please set '%s' to a number less than or equal to %f",
243 const std::string &units,
246 std::string input_units = this->units(name);
251 e.
add_context(
"converting \"%s\" from \"%s\" to \"%s\"",
252 name.c_str(), input_units.c_str(), units.c_str());
265 const std::string &units,
268 auto input_units = this->units(name);
272 for (
unsigned int k = 0;
k < value.size(); ++
k) {
273 value[
k] = converter(value[
k]);
277 e.
add_context(
"converting \"%s\" from \"%s\" to \"%s\"",
278 name.c_str(), input_units.c_str(), units.c_str());
288 set_by_user.insert(name);
293 set_by_user.find(name) != set_by_user.end()) {
301 const std::vector<double> &values,
306 set_by_user.insert(name);
311 set_by_user.find(name) != set_by_user.end()) {
330 const std::string &value,
335 set_by_user.insert(name);
340 set_by_user.find(name) != set_by_user.end()) {
363 set_by_user.insert(name);
368 set_by_user.find(name) != set_by_user.end()) {
376 for (
const auto &suffix : {
"_doc",
"_units",
"_type",
"_option",
"_choices",
"_valid_min",
"_valid_max"}) {
384 return (name ==
"long_name");
388 const int v = verbosity_threshhold;
397 size_t max_name_size = 0;
398 for (
const auto &s : strings) {
402 max_name_size = std::max(max_name_size, s.first.size());
406 for (
const auto &s : strings) {
407 std::string name = s.first;
408 std::string value = s.second;
414 std::string padding(max_name_size - name.size(),
' ');
416 if (config.
type(name) ==
"keyword") {
417 log.
message(v,
" %s%s = \"%s\" (allowed choices: %s)\n",
418 name.c_str(), padding.c_str(), value.c_str(),
421 log.
message(v,
" %s%s = \"%s\"\n", name.c_str(), padding.c_str(), value.c_str());
432 max_name_size = std::max(max_name_size, d.first.size());
436 std::string name = d.first;
437 double value = d.second[0];
443 std::string units = config.
units(name);
444 std::string padding(max_name_size - name.size(),
' ');
446 const double large = 1.0e7;
447 const double small = 1.0e-4;
448 if (fabs(value) >= large or fabs(value) <= small) {
450 log.
message(v,
" %s%s = %13.3e (%s)\n", name.c_str(), padding.c_str(), value, units.c_str());
452 log.
message(v,
" %s%s = %13.5f (%s)\n", name.c_str(), padding.c_str(), value, units.c_str());
462 for (
const auto &b : config.
all_flags()) {
463 max_name_size = std::max(max_name_size, b.first.size());
467 for (
const auto &b : config.
all_flags()) {
468 std::string name = b.first;
469 std::string value = b.second ?
"true" :
"false";
470 std::string padding(max_name_size - name.size(),
' ');
472 log.
message(v,
" %s%s = %s\n", name.c_str(), padding.c_str(), value.c_str());
476 "### List of configuration parameters ends here.\n"
485 if (
options::Bool(
"-options_left",
"report unused options")) {
489 for (
const auto &p : parameters_set) {
495 if (parameters_used.find(p) == parameters_used.end()) {
496 log.
message(verbosity_threshhold,
497 "PISM WARNING: flag or parameter \"%s\" was set but was not used!\n",
529 const std::string ¶meter_name) {
533 std::string doc = config.
doc(parameter_name);
543 }
else if (
set_member(opt.
value(), {
"off",
"no",
"false",
"False" })) {
549 opt.
value().c_str());
560 "Inconsistent command-line options:"
561 " both -%s and -no_%s are set.\n",
562 option.c_str(), option.c_str());
583 const std::string ¶meter) {
592 const std::string ¶meter) {
616 const std::string &choices) {
635 std::string option = name;
637 if (not config.
option(name).empty()) {
638 std::string short_option = config.
option(name);
639 std::string description = config.
doc(name);
645 "both -%s and -%s are set (please use one or the other)",
646 option.c_str(), short_option.c_str());
650 option = short_option;
654 std::string type = config.
type(name);
656 if (type ==
"string") {
658 }
else if (type ==
"flag") {
660 }
else if (type ==
"number") {
662 }
else if (type ==
"integer") {
664 }
else if (type ==
"keyword") {
675 std::map<std::string, std::string> options = {
676 {
"-extra_append",
"-spatial_append"},
677 {
"-extra_file",
"-spatial_file"},
678 {
"-extra_split",
"-spatial_split"},
679 {
"-extra_stop_missing",
"-spatial_stop_missing"},
680 {
"-extra_times",
"-spatial_times"},
681 {
"-extra_force_output_times",
"-spatial_force_output_times"},
682 {
"-extra_vars",
"-spatial_vars"},
683 {
"-ts_append",
"-scalar_append"},
684 {
"-ts_file",
"-scalar_file"},
685 {
"-ts_times",
"-scalar_times"},
686 {
"-ts_vars",
"-scalar_vars"},
689 for (
const auto &o : options) {
702 for (
const auto &b : config.
all_flags()) {
710 bool pik =
options::Bool(
"-pik",
"enable suite of PISM-PIK mechanisms");
718 if (config.
get_string(
"calving.methods").find(
"eigen_calving") != std::string::npos) {
721 config.
set_number(
"grid.max_stencil_width", 3);
725 if (not config.
get_string(
"calving.methods").empty()) {
730 if (config.
get_flag(
"geometry.remove_icebergs")) {
735 if (config.
get_string(
"hydrology.model") ==
"routing") {
736 if (config.
get_flag(
"frontal_melt.include_floating_ice")) {
737 config.
set_flag(
"hydrology.routing.include_floating_ice",
true);
741 if (config.
get_flag(
"output.ISMIP6")) {
743 config.
set_flag(
"output.use_MKS",
true);
748 options::String T(
"-ice_surface_temp",
"ice surface temperature parameterization");
753 if (IST.size() != 4) {
755 " (comma-separated list of 4 numbers)");
758 config.
set_number(
"surface.elevation_dependent.T_min", IST[0]);
759 config.
set_number(
"surface.elevation_dependent.T_max", IST[1]);
760 config.
set_number(
"surface.elevation_dependent.z_T_min", IST[2]);
761 config.
set_number(
"surface.elevation_dependent.z_T_max", IST[3]);
764 options::String M(
"-climatic_mass_balance",
"climatic mass balance parameterization");
769 if (CMB.size() != 5) {
771 " (comma-separated list of 5 numbers)");
774 config.
set_number(
"surface.elevation_dependent.M_min", CMB[0]);
775 config.
set_number(
"surface.elevation_dependent.M_max", CMB[1]);
776 config.
set_number(
"surface.elevation_dependent.z_M_min", CMB[2]);
777 config.
set_number(
"surface.elevation_dependent.z_ELA", CMB[3]);
778 config.
set_number(
"surface.elevation_dependent.z_M_max", CMB[4]);
782 "lower and upper limits of the climatic mass balance");
790 " (a comma-separated list of 2 numbers)");
795 config.
set_number(
"surface.elevation_dependent.M_limit_min", meter_per_second(
L[0]));
796 config.
set_number(
"surface.elevation_dependent.M_limit_max", meter_per_second(
L[1]));
807 auto config = std::make_shared<T>(
"pism_config", unit_system);
808 auto overrides = std::make_shared<T>(
"pism_overrides", unit_system);
810 options::String config_filename(
"-config",
"Config file name", pism::config_file);
811 options::String override_filename(
"-config_override",
"Config override file name");
815 config->read(com, config_filename);
818 if (override_filename.
is_set()) {
819 overrides->read(com, override_filename);
820 config->import_from(*overrides);
825 config->resolve_filenames();
831 std::set<std::string> result;
834 result.insert(p.first);
838 result.insert(p.first);
842 result.insert(p.first);
861 if (this->
is_set(parameter +
"_option")) {
873 if (
is_set(parameter +
"_valid_min")) {
876 return {
false, {} };
880 if (
is_set(parameter +
"_valid_max")) {
883 return {
false, {} };
898 json[p.first] = p.second;
902 const auto &name = p.first;
903 const auto &value = p.second;
908 nlohmann::json entry;
910 if (value.size() == 1) {
911 if (
type(name) ==
"integer") {
912 entry.push_back((
int)value[0]);
914 entry.push_back(value[0]);
917 entry.push_back(value);
919 entry.push_back(
units(name));
928 json[p.first] = p.second;
932 char indent_char =
' ';
933 bool ensure_ascii =
true;
934 return json.dump(indent, indent_char, ensure_ascii);
944 result[p.first] = p.second;
948 result[p.first] = p.second;
951 for (
const auto &p : config.
all_flags()) {
952 result[p.first] = p.second ?
"true" :
"false";
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
bool is_set(const std::string &name) const
std::string choices(const std::string ¶meter) const
virtual Strings all_strings_impl() const =0
std::set< std::string > keys() const
Config(std::shared_ptr< units::System > unit_system)
std::pair< bool, double > valid_max(const std::string ¶meter) 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
std::vector< double > get_numbers(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
virtual void read_impl(const File &nc)=0
virtual Flags all_flags_impl() const =0
virtual std::vector< double > get_numbers_impl(const std::string &name) const =0
const std::set< std::string > & parameters_set_by_user() const
virtual void set_flag_impl(const std::string &name, bool value)=0
void read(MPI_Comm com, const std::string &filename)
bool is_valid_number(const std::string &name) const
virtual void set_string_impl(const std::string &name, const std::string &value)=0
std::shared_ptr< units::System > unit_system() const
std::string units(const std::string ¶meter) const
void import_from(const Config &other)
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 ¶meter) const
virtual Doubles all_doubles_impl() const =0
virtual void set_number_impl(const std::string &name, double value)=0
bool get_flag(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
void set_number(const std::string &name, double value, ConfigSettingFlag flag=CONFIG_FORCE)
std::string option(const std::string ¶meter) const
std::string filename() const
Returns the name of the file used to initialize the database.
Strings all_strings() const
void set_numbers(const std::string &name, const std::vector< double > &values, ConfigSettingFlag flag=CONFIG_FORCE)
static int max_length
Maximum length of the JSON string (for writing to output files)
Doubles all_doubles() const
std::string doc(const std::string ¶meter) const
UseFlag
Flag used by get_...() methods.
std::pair< bool, double > valid_min(const std::string ¶meter) const
virtual double get_number_impl(const std::string &name) const =0
virtual bool get_flag_impl(const std::string &name) const =0
A class for storing and accessing PISM configuration flags and parameters.
High-level PISM I/O class.
void message(int threshold, const char format[],...) const __attribute__((format(printf
Print a message to the log.
int get_threshold() const
Get verbosity threshold.
A class for reading, writing and accessing PISM configuration flags and parameters.
void add_context(const std::string &message)
Add a message providing some context. This way we can (sort of) get a stack trace even though C++ exc...
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
std::shared_ptr< System > Ptr
#define PISM_ERROR_LOCATION
@ PISM_READONLY
open an existing file for reading only
void deprecated(const std::string &old_name, const std::string &new_name)
Stop if an option old_name is set, printing a message that new_name should be used instead.
bool Bool(const std::string &option, const std::string &description)
double convert(System::Ptr system, double input, const std::string &spec1, const std::string &spec2)
Convert a quantity from unit1 to unit2.
void set_integer_from_option(Config &config, const std::string &option, const std::string ¶meter)
void set_config_from_options(Config &config)
Set configuration parameters using command-line options.
bool ends_with(const std::string &str, const std::string &suffix)
Returns true if str ends with suffix and false otherwise.
std::vector< double > parse_number_list(const std::string &input)
void set_number_from_option(Config &config, const std::string &option, const std::string ¶meter)
Sets a configuration parameter from a command-line option.
void set_string_from_option(Config &config, const std::string &option, const std::string ¶meter)
Set one free-form string parameter using command-line options.
static bool special_parameter(const std::string &name)
std::shared_ptr< Config > config_from_options(MPI_Comm com, units::System::Ptr unit_system)
Create a configuration database using command-line options.
void set_flag_from_option(Config &config, const std::string &option, const std::string ¶meter_name)
Get a flag from a command-line option.
VariableMetadata config_metadata(const Config &config)
ConfigSettingFlag
Flag used by set_...() methods.
bool set_member(const std::string &string, const std::set< std::string > &set)
void print_unused_parameters(const Logger &log, int verbosity_threshhold, const Config &config)
Report unused configuration parameters to stdout.
void set_keyword_from_option(Config &config, const std::string &option, const std::string ¶meter, const std::string &choices)
Set a keyword parameter from a command-line option.
void set_parameter_from_options(Config &config, const std::string &name)
Set one parameter using command-line options.
void print_config(const Logger &log, int verbosity_threshhold, const Config &config)
Report configuration parameters to stdout.
std::vector< std::string > split(const std::string &input, char separator)
Transform a separator-separated list (a string) into a vector of strings.
units::System::Ptr unit_system
std::set< std::string > parameters_used
Set of parameters used in a run. Used to warn about parameters that were set but were not used.
Impl(units::System::Ptr sys)
std::set< std::string > parameters_set_by_user
Set of parameters set by the user. Used to warn about parameters that were set but were not used.