Config.cc (7441B)
1 /* Copyright (C) 2014, 2015, 2016, 2017, 2019 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 "Config.hh" 21 #include "pism/util/io/File.hh" 22 #include "pism_options.hh" 23 #include "error_handling.hh" 24 #include "io/io_helpers.hh" 25 #include "pism/util/Logger.hh" 26 #include "pism/util/pism_utilities.hh" 27 #include "pism/pism_config.hh" // pism::config_file 28 29 namespace pism { 30 31 NetCDFConfig::NetCDFConfig(MPI_Comm com, const std::string &name, units::System::Ptr system) 32 : Config(system), 33 m_com(com), 34 m_data(name, system) { 35 } 36 37 NetCDFConfig::~NetCDFConfig() { 38 } 39 40 bool NetCDFConfig::is_set_impl(const std::string &name) const { 41 return m_data.has_attribute(name); 42 } 43 44 // doubles 45 46 double NetCDFConfig::get_number_impl(const std::string &name) const { 47 const VariableMetadata::DoubleAttrs& doubles = m_data.get_all_doubles(); 48 if (doubles.find(name) != doubles.end()) { 49 return m_data.get_number(name); 50 } else { 51 throw RuntimeError::formatted(PISM_ERROR_LOCATION, 52 "parameter '%s' is unset. (Parameters read from '%s'.)", 53 name.c_str(), m_config_filename.c_str()); 54 } 55 56 return 0; // can't happen 57 } 58 59 std::vector<double> NetCDFConfig::get_numbers_impl(const std::string &name) const { 60 const VariableMetadata::DoubleAttrs& doubles = m_data.get_all_doubles(); 61 if (doubles.find(name) != doubles.end()) { 62 return m_data.get_numbers(name); 63 } else { 64 throw RuntimeError::formatted(PISM_ERROR_LOCATION, 65 "parameter '%s' is unset. (Parameters read from '%s'.)", 66 name.c_str(), m_config_filename.c_str()); 67 } 68 69 return {}; // can't happen 70 } 71 72 Config::Doubles NetCDFConfig::all_doubles_impl() const { 73 Doubles result; 74 75 for (auto d : m_data.get_all_doubles()) { 76 result[d.first] = d.second; 77 } 78 return result; 79 } 80 81 82 void NetCDFConfig::set_number_impl(const std::string &name, double value) { 83 m_data.set_number(name, value); 84 } 85 86 void NetCDFConfig::set_numbers_impl(const std::string &name, 87 const std::vector<double> &values) { 88 m_data.set_numbers(name, values); 89 } 90 91 // strings 92 93 std::string NetCDFConfig::get_string_impl(const std::string &name) const { 94 const VariableMetadata::StringAttrs& strings = m_data.get_all_strings(); 95 if (strings.find(name) != strings.end()) { 96 return m_data.get_string(name); 97 } else { 98 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "Parameter '%s' was not set. (Read from '%s'.)\n", 99 name.c_str(), m_config_filename.c_str()); 100 } 101 102 return std::string(); // will never happen 103 } 104 105 Config::Strings NetCDFConfig::all_strings_impl() const { 106 VariableMetadata::StringAttrs strings = m_data.get_all_strings(); 107 Strings result; 108 109 for (auto s : strings) { 110 std::string name = s.first; 111 std::string value = s.second; 112 113 auto k = strings.find(name + "_type"); 114 if (k != strings.end() and k->second == "flag") { 115 // Flags are stored as strings. Skip them. 116 continue; 117 } 118 119 result[name] = value; 120 } 121 return result; 122 } 123 124 void NetCDFConfig::set_string_impl(const std::string &name, const std::string &value) { 125 m_data.set_string(name, value); 126 } 127 128 // flags 129 130 static bool string_is_false(const std::string &value) { 131 return value == "false" or value == "off" or value == "no"; 132 } 133 134 static bool string_is_true(const std::string &value) { 135 return value == "true" or value == "on" or value == "yes"; 136 } 137 138 bool NetCDFConfig::get_flag_impl(const std::string &name) const { 139 const VariableMetadata::StringAttrs& strings = m_data.get_all_strings(); 140 auto j = strings.find(name); 141 if (j != strings.end()) { 142 143 const std::string &value = j->second; 144 145 if (string_is_false(value)) { 146 return false; 147 } 148 149 if (string_is_true(value)) { 150 return true; 151 } 152 153 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "Parameter '%s' (%s) cannot be interpreted as a flag.\n" 154 "Please make sure that it is set to one of 'true', 'yes', 'on', 'false', 'no', 'off'.", 155 name.c_str(), value.c_str()); 156 } 157 158 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "Parameter '%s' was not set. (Read from '%s'.)", 159 name.c_str(), m_config_filename.c_str()); 160 161 return true; // will never happen 162 } 163 164 Config::Flags NetCDFConfig::all_flags_impl() const { 165 Flags result; 166 167 for (auto b : m_data.get_all_strings()) { 168 std::string name = b.first; 169 std::string value = b.second; 170 171 if (string_is_true(value)) { 172 result[name] = true; 173 } else if (string_is_false(value)) { 174 result[name] = false; 175 } 176 } 177 return result; 178 } 179 180 //! Set a value of a flag flag. 181 void NetCDFConfig::set_flag_impl(const std::string &name, bool value) { 182 if (value) { 183 m_data.set_string(name, "true"); 184 } else { 185 m_data.set_string(name, "false"); 186 } 187 } 188 189 // file I/O 190 191 //! Read flag flags and double parameters from a NetCDF file. 192 /*! 193 Erases all the present parameters before reading. 194 */ 195 void NetCDFConfig::read_impl(const File &nc) { 196 197 io::read_attributes(nc, m_data.get_name(), m_data); 198 199 m_config_filename = nc.filename(); 200 } 201 202 //! Write a config variable to a file (with all its attributes). 203 void NetCDFConfig::write_impl(const File &nc) const { 204 205 bool variable_exists = nc.find_variable(m_data.get_name()); 206 207 if (not variable_exists) { 208 nc.define_variable(m_data.get_name(), 209 PISM_BYTE, std::vector<std::string>()); 210 211 io::write_attributes(nc, m_data, PISM_DOUBLE); 212 } else { 213 io::write_attributes(nc, m_data, PISM_DOUBLE); 214 } 215 } 216 217 218 //! Config that respects command-line options and stores data in a NetCDF variable. 219 DefaultConfig::DefaultConfig(MPI_Comm com, 220 const std::string &variable_name, 221 const std::string &option, 222 units::System::Ptr system) 223 : NetCDFConfig(com, variable_name, system), 224 m_option(option) { 225 // empty 226 } 227 228 DefaultConfig::~DefaultConfig() { 229 // empty 230 } 231 232 void DefaultConfig::init(const Logger &log, bool use_default_path) { 233 options::String file(m_option, 234 "Name of the file to read " + m_data.get_name() + " from", 235 pism::config_file); 236 if (use_default_path or file.is_set()) { 237 this->read(m_com, file); 238 log.message(2, "Reading configuration parameters (%s) from file '%s'.\n", 239 m_data.get_name().c_str(), file->c_str()); 240 } 241 } 242 243 void DefaultConfig::init_with_default(const Logger &log) { 244 this->init(log, true); 245 } 246 247 void DefaultConfig::init(const Logger &log) { 248 this->init(log, false); 249 } 250 251 } // end of namespace pism