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