URI: 
       tParallelIO.cc - pism - [fork] customized build of PISM, the parallel ice sheet model (tillflux branch)
  HTML git clone git://src.adamsgaard.dk/pism
   DIR Log
   DIR Files
   DIR Refs
   DIR LICENSE
       ---
       tParallelIO.cc (14748B)
       ---
            1 /* Copyright (C) 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 <cassert>
           21 
           22 // Why do I need this???
           23 #define _NETCDF
           24 #include <pio.h>
           25 
           26 #include "ParallelIO.hh"
           27 
           28 #include "pism/util/error_handling.hh"
           29 #include "pism/util/io/pism_type_conversion.hh"
           30 #include "pism/util/IceGrid.hh"
           31 #include "File.hh"
           32 
           33 namespace pism {
           34 namespace io {
           35 
           36 static void check(const ErrorLocation &where, int return_code) {
           37   char message[PIO_MAX_NAME + 1];
           38   if (return_code != PIO_NOERR) {
           39     PIOc_strerror(return_code, message);
           40     throw RuntimeError(where, message);
           41   }
           42 }
           43 
           44 IO_Backend ParallelIO::best_iotype(bool netcdf3) {
           45   if (PIOc_iotype_available(PIO_IOTYPE_PNETCDF) and netcdf3) {
           46     return PISM_PIO_PNETCDF;
           47   }
           48   if (PIOc_iotype_available(PIO_IOTYPE_NETCDF4P)) {
           49     return PISM_PIO_NETCDF4P;
           50   }
           51   if (PIOc_iotype_available(PIO_IOTYPE_NETCDF4C)) {
           52     return PISM_PIO_NETCDF4C;
           53   }
           54   // always available and supports all file formats
           55   return PISM_PIO_NETCDF;
           56 }
           57 
           58 
           59 ParallelIO::ParallelIO(MPI_Comm com, int iosysid, IO_Backend iotype)
           60   : NCFile(com),
           61     m_iosysid(iosysid) {
           62   assert(iosysid != -1);
           63 
           64   switch (iotype) {
           65   case PISM_PIO_PNETCDF:
           66     m_iotype = PIO_IOTYPE_PNETCDF;
           67     break;
           68   case PISM_PIO_NETCDF4P:
           69     m_iotype = PIO_IOTYPE_NETCDF4P;
           70     break;
           71   case PISM_PIO_NETCDF4C:
           72     m_iotype = PIO_IOTYPE_NETCDF4C;
           73     break;
           74   case PISM_PIO_NETCDF:
           75     m_iotype = PIO_IOTYPE_NETCDF;
           76     break;
           77   default:
           78     throw RuntimeError::formatted(PISM_ERROR_LOCATION,
           79                                   "invalid iotype in ParallelIO");
           80   }
           81 }
           82 
           83 ParallelIO::~ParallelIO() {
           84   // empty
           85 }
           86 
           87 void ParallelIO::open_impl(const std::string &filename, IO_Mode mode) {
           88   int open_mode = mode == PISM_READONLY ? PIO_NOWRITE : PIO_WRITE;
           89 
           90   int stat = PIOc_open(m_iosysid, filename.c_str(), open_mode, &m_file_id);
           91   check(PISM_ERROR_LOCATION, stat);
           92 }
           93 
           94 void ParallelIO::create_impl(const std::string &filename) {
           95 
           96   int mode = NC_CLOBBER;
           97   if (m_iotype == PIO_IOTYPE_PNETCDF) {
           98     mode |= NC_64BIT_DATA;
           99   }
          100 
          101   int stat = PIOc_createfile(m_iosysid, &m_file_id, &m_iotype, filename.c_str(),
          102                              mode);
          103   check(PISM_ERROR_LOCATION, stat);
          104 }
          105 
          106 void ParallelIO::sync_impl() const {
          107 
          108   int stat = PIOc_sync(m_file_id); check(PISM_ERROR_LOCATION, stat);
          109 }
          110 
          111 void ParallelIO::close_impl() {
          112   int stat = PIOc_closefile(m_file_id); check(PISM_ERROR_LOCATION, stat);
          113 }
          114 
          115 // redef/enddef
          116 void ParallelIO::enddef_impl() const {
          117   int stat = PIOc_enddef(m_file_id); check(PISM_ERROR_LOCATION, stat);
          118 }
          119 
          120 void ParallelIO::redef_impl() const {
          121   int stat = PIOc_redef(m_file_id); check(PISM_ERROR_LOCATION, stat);
          122 }
          123 
          124 // dim
          125 void ParallelIO::def_dim_impl(const std::string &name, size_t length) const {
          126   int dim_id = 0;
          127   int stat = PIOc_def_dim(m_file_id, name.c_str(), length, &dim_id);
          128   check(PISM_ERROR_LOCATION, stat);
          129 }
          130 
          131 void ParallelIO::inq_dimid_impl(const std::string &dimension_name, bool &exists) const {
          132   int tmp;
          133 
          134   int stat = PIOc_inq_dimid(m_file_id, dimension_name.c_str(), &tmp);
          135 
          136   if (stat == PIO_NOERR) {
          137     exists = true;
          138   } else {
          139     exists = false;
          140   }
          141 }
          142 
          143 void ParallelIO::inq_dimlen_impl(const std::string &dimension_name, unsigned int &result) const {
          144   int stat, dimid = -1;
          145   PIO_Offset len;
          146 
          147   stat = PIOc_inq_dimid(m_file_id, dimension_name.c_str(), &dimid); check(PISM_ERROR_LOCATION, stat);
          148 
          149   stat = PIOc_inq_dimlen(m_file_id, dimid, &len); check(PISM_ERROR_LOCATION, stat);
          150 
          151   result = static_cast<unsigned int>(len);
          152 }
          153 
          154 void ParallelIO::inq_unlimdim_impl(std::string &result) const {
          155   int stat = PIO_NOERR, dimid = -1;
          156   char dimname[PIO_MAX_NAME + 1];
          157 
          158   stat = PIOc_inq_unlimdim(m_file_id, &dimid); check(PISM_ERROR_LOCATION, stat);
          159 
          160   if (dimid == -1) {
          161     result.clear();
          162   } else {
          163     stat = PIOc_inq_dimname(m_file_id, dimid, dimname); check(PISM_ERROR_LOCATION, stat);
          164 
          165     result = dimname;
          166   }
          167 }
          168 
          169 // var
          170 void ParallelIO::def_var_impl(const std::string &name, IO_Type nctype,
          171                              const std::vector<std::string> &dims) const {
          172   std::vector<int> dimids;
          173   int stat, varid;
          174 
          175   for (auto d : dims) {
          176     int dimid = -1;
          177     stat = PIOc_inq_dimid(m_file_id, d.c_str(), &dimid); check(PISM_ERROR_LOCATION, stat);
          178     dimids.push_back(dimid);
          179   }
          180 
          181   stat = PIOc_def_var(m_file_id, name.c_str(), pism_type_to_nc_type(nctype),
          182                       static_cast<int>(dims.size()), dimids.data(), &varid);
          183   check(PISM_ERROR_LOCATION, stat);
          184 }
          185 
          186 void ParallelIO::def_var_chunking_impl(const std::string &name,
          187                                       std::vector<size_t> &dimensions) const {
          188   (void) name;
          189   (void) dimensions;
          190   // FIXME
          191 }
          192 
          193 void ParallelIO::get_vara_double_impl(const std::string &variable_name,
          194                                      const std::vector<unsigned int> &start,
          195                                      const std::vector<unsigned int> &count,
          196                                      double *input) const {
          197   int stat, varid, ndims = static_cast<int>(start.size());
          198 
          199   std::vector<PIO_Offset>
          200     nc_start(ndims),
          201     nc_count(ndims);
          202 
          203   stat = PIOc_inq_varid(m_file_id, variable_name.c_str(), &varid); check(PISM_ERROR_LOCATION, stat);
          204 
          205   for (int j = 0; j < ndims; ++j) {
          206     nc_start[j] = start[j];
          207     nc_count[j] = count[j];
          208   }
          209 
          210   stat = PIOc_get_vara_double(m_file_id, varid, nc_start.data(), nc_count.data(), input);
          211   check(PISM_ERROR_LOCATION, stat);
          212 }
          213 
          214 void ParallelIO::put_vara_double_impl(const std::string &variable_name,
          215                                      const std::vector<unsigned int> &start,
          216                                      const std::vector<unsigned int> &count,
          217                                      const double *output) const {
          218   int stat, varid, ndims = static_cast<int>(start.size());
          219 
          220   std::vector<PIO_Offset>
          221     nc_start(ndims),
          222     nc_count(ndims);
          223 
          224   stat = PIOc_inq_varid(m_file_id, variable_name.c_str(), &varid); check(PISM_ERROR_LOCATION, stat);
          225 
          226   for (int j = 0; j < ndims; ++j) {
          227     nc_start[j] = start[j];
          228     nc_count[j] = count[j];
          229   }
          230 
          231   stat = PIOc_put_vara_double(m_file_id, varid, nc_start.data(), nc_count.data(), output);
          232   check(PISM_ERROR_LOCATION, stat);
          233 }
          234 
          235 template<typename T>
          236 std::vector<T> convert_data(const double *input, size_t length) {
          237   std::vector<T> buffer(length);
          238   for (size_t k = 0; k < length; ++k) {
          239     buffer[k] = static_cast<T>(input[k]);
          240   }
          241   return buffer;
          242 }
          243 
          244 void ParallelIO::write_darray_impl(const std::string &variable_name,
          245                                    const IceGrid &grid,
          246                                    unsigned int z_count,
          247                                    unsigned int record,
          248                                    const double *input) {
          249 
          250   int stat = 0, varid;
          251 
          252   stat = PIOc_inq_varid(m_file_id, variable_name.c_str(), &varid);
          253   check(PISM_ERROR_LOCATION, stat);
          254 
          255   int type = 0;
          256   stat = PIOc_inq_vartype(m_file_id, varid, &type);
          257 
          258   int decompid = grid.pio_io_decomposition(z_count, type);
          259 
          260   size_t length = grid.xm() * grid.ym() * z_count;
          261 
          262   switch (type) {
          263   case PIO_DOUBLE:
          264     // no conversion necessary
          265     stat = PIOc_put_vard_double(m_file_id, varid, decompid, (PIO_Offset)record, input);
          266     check(PISM_ERROR_LOCATION, stat);
          267     break;
          268   case PIO_FLOAT:
          269     {
          270       auto buffer = convert_data<float>(input, length);
          271       stat = PIOc_put_vard_float(m_file_id, varid, decompid, (PIO_Offset)record, buffer.data());
          272       check(PISM_ERROR_LOCATION, stat);
          273       break;
          274     }
          275   case PIO_INT:
          276     {
          277       auto buffer = convert_data<int>(input, length);
          278       stat = PIOc_put_vard_int(m_file_id, varid, decompid, (PIO_Offset)record, buffer.data());
          279       check(PISM_ERROR_LOCATION, stat);
          280       break;
          281     }
          282   default:
          283     throw RuntimeError::formatted(PISM_ERROR_LOCATION,
          284                                   "ParallelIO: type conversion is not supported");
          285   }
          286 }
          287 
          288 
          289 void ParallelIO::get_varm_double_impl(const std::string &variable_name,
          290                                      const std::vector<unsigned int> &start,
          291                                      const std::vector<unsigned int> &count,
          292                                      const std::vector<unsigned int> &imap,
          293                                      double *input) const {
          294   (void) variable_name;
          295   (void) start;
          296   (void) count;
          297   (void) imap;
          298   (void) input;
          299   throw RuntimeError::formatted(PISM_ERROR_LOCATION,
          300                                 "ParallelIO does not support transposed access");
          301 }
          302 
          303 void ParallelIO::inq_nvars_impl(int &result) const {
          304   int stat = PIOc_inq_nvars(m_file_id, &result); check(PISM_ERROR_LOCATION, stat);
          305 }
          306 
          307 void ParallelIO::inq_vardimid_impl(const std::string &variable_name, std::vector<std::string> &result) const {
          308   int stat, ndims, varid = -1;
          309   std::vector<int> dimids;
          310 
          311   stat = PIOc_inq_varid(m_file_id, variable_name.c_str(), &varid); check(PISM_ERROR_LOCATION, stat);
          312 
          313   stat = PIOc_inq_varndims(m_file_id, varid, &ndims); check(PISM_ERROR_LOCATION, stat);
          314 
          315   if (ndims == 0) {
          316     result.clear();
          317     return;
          318   }
          319 
          320   result.resize(ndims);
          321   dimids.resize(ndims);
          322 
          323   stat = PIOc_inq_vardimid(m_file_id, varid, dimids.data()); check(PISM_ERROR_LOCATION, stat);
          324 
          325   for (int k = 0; k < ndims; ++k) {
          326     char name[PIO_MAX_NAME];
          327     memset(name, 0, PIO_MAX_NAME);
          328 
          329     stat = PIOc_inq_dimname(m_file_id, dimids[k], name); check(PISM_ERROR_LOCATION, stat);
          330 
          331     result[k] = name;
          332   }
          333 }
          334 
          335 void ParallelIO::inq_varnatts_impl(const std::string &variable_name, int &result) const {
          336   int varid = get_varid(variable_name);
          337 
          338   int stat = PIO_NOERR;
          339   if (varid == PIO_GLOBAL) {
          340     stat = PIOc_inq_natts(m_file_id, &result);
          341   } else {
          342     stat = PIOc_inq_varnatts(m_file_id, varid, &result);
          343   }
          344   check(PISM_ERROR_LOCATION, stat);
          345 }
          346 
          347 void ParallelIO::inq_varid_impl(const std::string &variable_name, bool &exists) const {
          348   int stat, flag = -1;
          349 
          350   stat = PIOc_inq_varid(m_file_id, variable_name.c_str(), &flag);
          351 
          352   exists = (stat == PIO_NOERR);
          353 }
          354 
          355 void ParallelIO::inq_varname_impl(unsigned int j, std::string &result) const {
          356   int stat;
          357   char varname[PIO_MAX_NAME];
          358   memset(varname, 0, PIO_MAX_NAME);
          359 
          360   stat = PIOc_inq_varname(m_file_id, j, varname); check(PISM_ERROR_LOCATION, stat);
          361 
          362   result = varname;
          363 }
          364 
          365 // att
          366 void ParallelIO::get_att_double_impl(const std::string &variable_name,
          367                                     const std::string &att_name,
          368                                     std::vector<double> &result) const {
          369   // Read the attribute length:
          370   int varid = get_varid(variable_name);
          371 
          372   PIO_Offset attlen = 0;
          373   int stat = PIOc_inq_attlen(m_file_id, varid, att_name.c_str(), &attlen);
          374 
          375   int len = 0;
          376   if (stat == NC_NOERR) {
          377     len = static_cast<int>(attlen);
          378   } else if (stat == NC_ENOTATT) {
          379     len = 0;
          380   } else {
          381     check(PISM_ERROR_LOCATION, stat);
          382   }
          383 
          384   if (len == 0) {
          385     result.clear();
          386     return;
          387   }
          388 
          389   result.resize(len);
          390 
          391   stat = PIOc_get_att_double(m_file_id, varid, att_name.c_str(), result.data());
          392   check(PISM_ERROR_LOCATION, stat);
          393 }
          394 
          395 void ParallelIO::get_att_text_impl(const std::string &variable_name,
          396                                    const std::string &att_name,
          397                                    std::string &result) const {
          398   PIO_Offset attlen;
          399 
          400   int varid = get_varid(variable_name);
          401 
          402   int stat = PIOc_inq_attlen(m_file_id, varid, att_name.c_str(), &attlen);
          403 
          404   int len = 0;
          405   if (stat == NC_NOERR) {
          406     len = static_cast<int>(attlen);
          407   } else {
          408     len = 0;
          409   }
          410 
          411   // Allocate some memory or clear result.
          412   if (len == 0) {
          413     result.clear();
          414     return;
          415   }
          416 
          417   // Now read the string and see if we succeeded:
          418   std::vector<char> str(len + 1, 0);
          419   stat = PIOc_get_att_text(m_file_id, varid, att_name.c_str(), str.data());
          420   check(PISM_ERROR_LOCATION, stat);
          421 
          422   result = str.data();
          423 }
          424 
          425 void ParallelIO::put_att_double_impl(const std::string &variable_name,
          426                                     const std::string &att_name,
          427                                     IO_Type xtype,
          428                                     const std::vector<double> &data) const {
          429   int stat = PIOc_put_att_double(m_file_id, get_varid(variable_name), att_name.c_str(),
          430                                  pism_type_to_nc_type(xtype), data.size(), data.data());
          431   check(PISM_ERROR_LOCATION, stat);
          432 }
          433 
          434 void ParallelIO::put_att_text_impl(const std::string &variable_name,
          435                                   const std::string &att_name,
          436                                   const std::string &value) const {
          437   int stat = PIOc_put_att_text(m_file_id, get_varid(variable_name), att_name.c_str(),
          438                                value.size(), value.c_str());
          439   check(PISM_ERROR_LOCATION, stat);
          440 }
          441 
          442 void ParallelIO::inq_attname_impl(const std::string &variable_name,
          443                                  unsigned int n, std::string &result) const {
          444   std::vector<char> name(PIO_MAX_NAME + 1, 0);
          445 
          446   int stat = PIOc_inq_attname(m_file_id, get_varid(variable_name), n, name.data());
          447   check(PISM_ERROR_LOCATION, stat);
          448 
          449   result = name.data();
          450 }
          451 
          452 void ParallelIO::inq_atttype_impl(const std::string &variable_name,
          453                                  const std::string &att_name,
          454                                  IO_Type &result) const {
          455   nc_type tmp;
          456   int stat = PIOc_inq_atttype(m_file_id, get_varid(variable_name), att_name.c_str(), &tmp);
          457   if (stat == PIO_ENOTATT) {
          458     tmp = NC_NAT;
          459   } else {
          460     check(PISM_ERROR_LOCATION, stat);
          461   }
          462 
          463   result = nc_type_to_pism_type(tmp);
          464 }
          465 
          466 // misc
          467 void ParallelIO::set_fill_impl(int fillmode, int &old_modep) const {
          468 
          469   int stat = PIOc_set_fill(m_file_id, fillmode, &old_modep);
          470   check(PISM_ERROR_LOCATION, stat);
          471 }
          472 
          473 void ParallelIO::del_att_impl(const std::string &variable_name,
          474                               const std::string &att_name) const {
          475   int stat = PIOc_del_att(m_file_id, get_varid(variable_name), att_name.c_str());
          476   check(PISM_ERROR_LOCATION, stat);
          477 }
          478 
          479 int ParallelIO::get_varid(const std::string &variable_name) const {
          480   if (variable_name == "PISM_GLOBAL") {
          481     return NC_GLOBAL;
          482   } else {
          483     int varid = -2;
          484     int stat = PIOc_inq_varid(m_file_id, variable_name.c_str(), &varid);
          485     check(PISM_ERROR_LOCATION, stat);
          486     return varid;
          487   }
          488 }
          489 
          490 } // end of namespace io
          491 } // end of namespace pism