tNC4File.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 --- tNC4File.cc (14852B) --- 1 // Copyright (C) 2012, 2013, 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 #include "NC4File.hh" 20 21 #include <cstring> // memset 22 #include <cstdio> // stderr, fprintf 23 24 // The ing is a stupid kludge necessary to make NetCDF 4.x work in 25 // serial mode in an MPI program: 26 #ifndef MPI_INCLUDED 27 #define MPI_INCLUDED 1 28 #endif 29 #include <netcdf.h> 30 31 #include "pism_type_conversion.hh" 32 #include "pism/util/pism_utilities.hh" 33 #include "pism/util/error_handling.hh" 34 35 namespace pism { 36 namespace io { 37 38 //! \brief Prints an error message; for debugging. 39 static void check(const ErrorLocation &where, int return_code) { 40 if (return_code != NC_NOERR) { 41 throw RuntimeError(where, nc_strerror(return_code)); 42 } 43 } 44 45 NC4File::NC4File(MPI_Comm c, unsigned int compression_level) 46 : NCFile(c), m_compression_level(compression_level) { 47 // empty 48 } 49 50 NC4File::~NC4File() { 51 // empty 52 } 53 54 // open/create/close 55 56 void NC4File::sync_impl() const { 57 58 int stat = nc_sync(m_file_id); check(PISM_ERROR_LOCATION, stat); 59 } 60 61 void NC4File::close_impl() { 62 int stat = nc_close(m_file_id); check(PISM_ERROR_LOCATION, stat); 63 64 m_file_id = -1; 65 } 66 67 // redef/enddef 68 void NC4File::enddef_impl() const { 69 int stat = nc_enddef(m_file_id); check(PISM_ERROR_LOCATION, stat); 70 } 71 72 void NC4File::redef_impl() const { 73 int stat = nc_redef(m_file_id); check(PISM_ERROR_LOCATION, stat); 74 } 75 76 // dim 77 void NC4File::def_dim_impl(const std::string &name, size_t length) const { 78 int dimid = 0; 79 80 int stat = nc_def_dim(m_file_id, name.c_str(), length, &dimid); 81 check(PISM_ERROR_LOCATION, stat); 82 } 83 84 void NC4File::inq_dimid_impl(const std::string &dimension_name, bool &exists) const { 85 int tmp = 0; 86 87 int stat = nc_inq_dimid(m_file_id, dimension_name.c_str(), &tmp); 88 89 if (stat == NC_NOERR) { 90 exists = true; 91 } else { 92 exists = false; 93 } 94 } 95 96 void NC4File::inq_dimlen_impl(const std::string &dimension_name, unsigned int &result) const { 97 int dimid = -1; 98 size_t len; 99 100 int stat = nc_inq_dimid(m_file_id, dimension_name.c_str(), &dimid); 101 check(PISM_ERROR_LOCATION, stat); 102 103 stat = nc_inq_dimlen(m_file_id, dimid, &len); check(PISM_ERROR_LOCATION, stat); 104 105 result = static_cast<unsigned int>(len); 106 } 107 108 void NC4File::inq_unlimdim_impl(std::string &result) const { 109 int dimid = -1; 110 std::vector<char> dimname(NC_MAX_NAME + 1, 0); 111 112 int stat = nc_inq_unlimdim(m_file_id, &dimid); check(PISM_ERROR_LOCATION, stat); 113 114 if (dimid == -1) { 115 result.clear(); 116 } else { 117 stat = nc_inq_dimname(m_file_id, dimid, dimname.data()); check(PISM_ERROR_LOCATION, stat); 118 119 result = dimname.data(); 120 } 121 } 122 123 // var 124 void NC4File::def_var_impl(const std::string &name, 125 IO_Type nctype, 126 const std::vector<std::string> &dims) const { 127 std::vector<int> dimids; 128 int stat = 0, varid = -1; 129 130 for (auto d : dims) { 131 int dimid = -1; 132 stat = nc_inq_dimid(m_file_id, d.c_str(), &dimid); check(PISM_ERROR_LOCATION, stat); 133 dimids.push_back(dimid); 134 } 135 136 stat = nc_def_var(m_file_id, name.c_str(), pism_type_to_nc_type(nctype), 137 static_cast<int>(dims.size()), &dimids[0], &varid); 138 check(PISM_ERROR_LOCATION, stat); 139 140 // Compress 2D and 3D variables 141 if (m_compression_level > 0 and dims.size() > 1) { 142 stat = nc_inq_varid(m_file_id, name.c_str(), &varid); check(PISM_ERROR_LOCATION, stat); 143 stat = nc_def_var_deflate(m_file_id, varid, 0, 1, m_compression_level); 144 check(PISM_ERROR_LOCATION, stat); 145 } 146 } 147 148 void NC4File::def_var_chunking_impl(const std::string &name, 149 std::vector<size_t> &dimensions) const { 150 int stat = 0, varid = 0; 151 152 stat = nc_inq_varid(m_file_id, name.c_str(), &varid); 153 check(PISM_ERROR_LOCATION, stat); 154 155 stat = nc_def_var_chunking(m_file_id, varid, NC_CHUNKED, &dimensions[0]); 156 check(PISM_ERROR_LOCATION, stat); 157 } 158 159 void NC4File::get_varm_double_impl(const std::string &variable_name, 160 const std::vector<unsigned int> &start, 161 const std::vector<unsigned int> &count, 162 const std::vector<unsigned int> &imap, double *op) const { 163 return this->get_put_var_double(variable_name, 164 start, count, imap, op, 165 true /*get*/, 166 true /*transposed*/); 167 } 168 169 void NC4File::get_vara_double_impl(const std::string &variable_name, 170 const std::vector<unsigned int> &start, 171 const std::vector<unsigned int> &count, 172 double *op) const { 173 std::vector<unsigned int> dummy; 174 return this->get_put_var_double(variable_name, 175 start, count, dummy, op, 176 true /*get*/, 177 false /*not transposed*/); 178 } 179 180 void NC4File::put_vara_double_impl(const std::string &variable_name, 181 const std::vector<unsigned int> &start, 182 const std::vector<unsigned int> &count, 183 const double *op) const { 184 std::vector<unsigned int> dummy; 185 return this->get_put_var_double(variable_name, 186 start, count, dummy, const_cast<double*>(op), 187 false /*put*/, 188 false /*not transposed*/); 189 } 190 191 192 void NC4File::inq_nvars_impl(int &result) const { 193 int stat = nc_inq_nvars(m_file_id, &result); check(PISM_ERROR_LOCATION, stat); 194 } 195 196 void NC4File::inq_vardimid_impl(const std::string &variable_name, std::vector<std::string> &result) const { 197 int ndims = 0, varid = -1; 198 std::vector<int> dimids; 199 200 int stat = nc_inq_varid(m_file_id, variable_name.c_str(), &varid); check(PISM_ERROR_LOCATION, stat); 201 202 stat = nc_inq_varndims(m_file_id, varid, &ndims); check(PISM_ERROR_LOCATION, stat); 203 204 if (ndims == 0) { 205 result.clear(); 206 return; 207 } 208 209 result.resize(ndims); 210 dimids.resize(ndims); 211 212 stat = nc_inq_vardimid(m_file_id, varid, &dimids[0]); check(PISM_ERROR_LOCATION, stat); 213 214 for (int k = 0; k < ndims; ++k) { 215 std::vector<char> name(NC_MAX_NAME + 1, 0); 216 217 stat = nc_inq_dimname(m_file_id, dimids[k], name.data()); check(PISM_ERROR_LOCATION, stat); 218 219 result[k] = name.data(); 220 } 221 } 222 223 int NC4File::get_varid(const std::string &variable_name) const { 224 if (variable_name == "PISM_GLOBAL") { 225 return NC_GLOBAL; 226 } 227 228 int result = 0; 229 int stat = nc_inq_varid(m_file_id, variable_name.c_str(), &result); 230 check(PISM_ERROR_LOCATION, stat); 231 232 return result; 233 } 234 235 void NC4File::inq_varnatts_impl(const std::string &variable_name, int &result) const { 236 int stat = nc_inq_varnatts(m_file_id, get_varid(variable_name), &result); 237 check(PISM_ERROR_LOCATION, stat); 238 } 239 240 void NC4File::inq_varid_impl(const std::string &variable_name, bool &exists) const { 241 int varid = -1; 242 243 int stat = nc_inq_varid(m_file_id, variable_name.c_str(), &varid); 244 245 exists = (stat == NC_NOERR); 246 } 247 248 void NC4File::inq_varname_impl(unsigned int j, std::string &result) const { 249 std::vector<char> varname(NC_MAX_NAME + 1, 0); 250 251 int stat = nc_inq_varname(m_file_id, j, varname.data()); 252 check(PISM_ERROR_LOCATION, stat); 253 254 result = varname.data(); 255 } 256 257 // att 258 259 void NC4File::get_att_double_impl(const std::string &variable_name, 260 const std::string &att_name, 261 std::vector<double> &result) const { 262 int varid = get_varid(variable_name); 263 264 // Read the attribute length: 265 size_t attlen = 0; 266 int stat = nc_inq_attlen(m_file_id, varid, att_name.c_str(), &attlen); 267 268 int len = 0; 269 if (stat == NC_NOERR) { 270 len = static_cast<int>(attlen); 271 } else if (stat == NC_ENOTATT) { 272 len = 0; 273 } else { 274 check(PISM_ERROR_LOCATION, stat); 275 len = 0; 276 } 277 278 if (len == 0) { 279 result.clear(); 280 return; 281 } 282 283 result.resize(len); 284 285 // Now read data and see if we succeeded: 286 stat = nc_get_att_double(m_file_id, varid, att_name.c_str(), &result[0]); 287 check(PISM_ERROR_LOCATION, stat); 288 } 289 290 // Get a text (character array) attribute on rank 0. 291 static void get_att_text(int ncid, int varid, const std::string &att_name, 292 std::string &result) { 293 size_t attlen = 0; 294 int stat = nc_inq_attlen(ncid, varid, att_name.c_str(), &attlen); 295 if (stat != NC_NOERR) { 296 result = ""; 297 return; 298 } 299 300 std::vector<char> buffer(attlen + 1, 0); 301 stat = nc_get_att_text(ncid, varid, att_name.c_str(), buffer.data()); 302 303 result = (stat == NC_NOERR) ? buffer.data() : ""; 304 } 305 306 // Get a string attribute on rank 0. In "string array" attributes array elements are 307 // concatenated using "," as the separator. 308 static void get_att_string(int ncid, int varid, const std::string &att_name, 309 std::string &result) { 310 size_t attlen = 0; 311 int stat = nc_inq_attlen(ncid, varid, att_name.c_str(), &attlen); 312 if (stat != NC_NOERR) { 313 result = ""; 314 return; 315 } 316 317 std::vector<char*> buffer(attlen + 1, 0); 318 stat = nc_get_att_string(ncid, varid, att_name.c_str(), buffer.data()); 319 if (stat == NC_NOERR) { 320 std::vector<std::string> strings(attlen); 321 for (size_t k = 0; k < attlen; ++k) { 322 strings[k] = buffer[k]; 323 } 324 result = join(strings, ","); 325 } else { 326 result = ""; 327 } 328 stat = nc_free_string(attlen, buffer.data()); 329 check(PISM_ERROR_LOCATION, stat); 330 } 331 332 void NC4File::get_att_text_impl(const std::string &variable_name, 333 const std::string &att_name, std::string &result) const { 334 int varid = get_varid(variable_name); 335 336 nc_type nctype; 337 int stat = nc_inq_atttype(m_file_id, varid, att_name.c_str(), &nctype); 338 339 if (stat == NC_NOERR) { 340 if (nctype == NC_CHAR) { 341 pism::io::get_att_text(m_file_id, varid, att_name, result); 342 } else if (nctype == NC_STRING) { 343 pism::io::get_att_string(m_file_id, varid, att_name, result); 344 } else { 345 result = ""; 346 } 347 } else if (stat == NC_ENOTATT) { 348 result = ""; 349 } else { 350 check(PISM_ERROR_LOCATION, stat); 351 } 352 } 353 354 void NC4File::del_att_impl(const std::string &variable_name, const std::string &att_name) const { 355 int stat = nc_del_att(m_file_id, get_varid(variable_name), att_name.c_str()); 356 check(PISM_ERROR_LOCATION, stat); 357 } 358 359 void NC4File::put_att_double_impl(const std::string &variable_name, 360 const std::string &att_name, 361 IO_Type xtype, 362 const std::vector<double> &data) const { 363 int stat = nc_put_att_double(m_file_id, get_varid(variable_name), att_name.c_str(), 364 xtype, data.size(), &data[0]); 365 check(PISM_ERROR_LOCATION, stat); 366 } 367 368 void NC4File::put_att_text_impl(const std::string &variable_name, 369 const std::string &att_name, 370 const std::string &value) const { 371 int stat = nc_put_att_text(m_file_id, get_varid(variable_name), att_name.c_str(), 372 value.size(), value.c_str()); 373 check(PISM_ERROR_LOCATION, stat); 374 } 375 376 void NC4File::inq_attname_impl(const std::string &variable_name, 377 unsigned int n, 378 std::string &result) const { 379 std::vector<char> name(NC_MAX_NAME + 1, 0); 380 int stat = nc_inq_attname(m_file_id, get_varid(variable_name), n, name.data()); 381 check(PISM_ERROR_LOCATION, stat); 382 383 result = name.data(); 384 } 385 386 void NC4File::inq_atttype_impl(const std::string &variable_name, 387 const std::string &att_name, 388 IO_Type &result) const { 389 nc_type tmp = NC_NAT; 390 int stat = nc_inq_atttype(m_file_id, get_varid(variable_name), att_name.c_str(), &tmp); 391 392 if (stat == NC_ENOTATT) { 393 tmp = NC_NAT; 394 } else { 395 check(PISM_ERROR_LOCATION, stat); 396 } 397 398 result = nc_type_to_pism_type(tmp); 399 } 400 401 // misc 402 403 void NC4File::set_fill_impl(int fillmode, int &old_modep) const { 404 int stat = nc_set_fill(m_file_id, fillmode, &old_modep); check(PISM_ERROR_LOCATION, stat); 405 } 406 407 void NC4File::set_access_mode(int, bool) const { 408 // empty 409 } 410 411 void NC4File::get_put_var_double(const std::string &variable_name, 412 const std::vector<unsigned int> &start, 413 const std::vector<unsigned int> &count, 414 const std::vector<unsigned int> &imap_input, 415 double *op, 416 bool get, 417 bool transposed) const { 418 int stat, varid, ndims = static_cast<int>(start.size()); 419 std::vector<unsigned int> imap = imap_input; 420 421 if (not transposed) { 422 imap.resize(ndims); 423 } 424 425 std::vector<size_t> nc_start(ndims), nc_count(ndims); 426 std::vector<ptrdiff_t> nc_imap(ndims), nc_stride(ndims); 427 428 stat = nc_inq_varid(m_file_id, variable_name.c_str(), &varid); check(PISM_ERROR_LOCATION, stat); 429 430 for (int j = 0; j < ndims; ++j) { 431 nc_start[j] = start[j]; 432 nc_count[j] = count[j]; 433 nc_imap[j] = imap[j]; 434 nc_stride[j] = 1; 435 } 436 437 if (transposed) { 438 439 set_access_mode(varid, transposed); 440 441 if (get) { 442 stat = nc_get_varm_double(m_file_id, varid, 443 &nc_start[0], &nc_count[0], &nc_stride[0], &nc_imap[0], 444 op); check(PISM_ERROR_LOCATION, stat); 445 } else { 446 stat = nc_put_varm_double(m_file_id, varid, 447 &nc_start[0], &nc_count[0], &nc_stride[0], &nc_imap[0], 448 op); check(PISM_ERROR_LOCATION, stat); 449 } 450 } else { 451 452 set_access_mode(varid, transposed); 453 454 if (get) { 455 stat = nc_get_vara_double(m_file_id, varid, 456 &nc_start[0], &nc_count[0], 457 op); check(PISM_ERROR_LOCATION, stat); 458 } else { 459 stat = nc_put_vara_double(m_file_id, varid, 460 &nc_start[0], &nc_count[0], 461 op); check(PISM_ERROR_LOCATION, stat); 462 } 463 } 464 } 465 466 } // end of namespace io 467 } // end of namespace pism