PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
PNCFile.cc
Go to the documentation of this file.
1// Copyright (C) 2012, 2013, 2014, 2015, 2016, 2017, 2019, 2020, 2021, 2023, 2024, 2025 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 <pnetcdf.h>
20#include <sstream>
21#include <cstring> // memset
22
23#include "pism/util/io/PNCFile.hh"
24
25#include "pism/util/io/pism_type_conversion.hh" // has to go after pnetcdf.h
26
27#include "pism/util/error_handling.hh"
28#include "pism/util/pism_utilities.hh"
29
30namespace pism {
31namespace io {
32
34 : NCFile(c) {
35 MPI_Info_create(&m_mpi_info);
36}
37
38
40 MPI_Info_free(&m_mpi_info);
41}
42
43static void check(const ErrorLocation &where, int return_code) {
44 if (return_code != NC_NOERR) {
45 throw RuntimeError(where, ncmpi_strerror(return_code));
46 }
47}
48
49void PNCFile::open_impl(const std::string &fname, io::Mode mode) {
50 int stat;
51
52 init_hints();
53
54 int open_mode = mode == io::PISM_READONLY ? NC_NOWRITE : NC_WRITE;
55
56 stat = ncmpi_open(m_com, fname.c_str(), open_mode, m_mpi_info, &m_file_id);
58}
59
60
61void PNCFile::create_impl(const std::string &fname) {
62 int stat;
63
64 init_hints();
65
66 stat = ncmpi_create(m_com, fname.c_str(), NC_CLOBBER | NC_64BIT_DATA, m_mpi_info, &m_file_id);
68}
69
70void PNCFile::sync_impl() const {
71
72 int stat = ncmpi_sync(m_file_id);
74}
75
76
78 int stat = ncmpi_close(m_file_id);
80
81 m_file_id = -1;
82}
83
84
86
87 int stat = ncmpi_enddef(m_file_id);
89}
90
91
92void PNCFile::redef_impl() const {
93
94 int stat = ncmpi_redef(m_file_id);
96}
97
98
99void PNCFile::def_dim_impl(const std::string &name, size_t length) const {
100 int dimid = 0, stat;
101
102 stat = ncmpi_def_dim(m_file_id, name.c_str(), length, &dimid);
104}
105
106
107void PNCFile::inq_dimid_impl(const std::string &dimension_name, bool &exists) const {
108 int tmp, stat;
109
110 stat = ncmpi_inq_dimid(m_file_id, dimension_name.c_str(), &tmp);
111
112 if (stat == NC_NOERR) {
113 exists = true;
114 } else {
115 exists = false;
116 }
117}
118
119
120void PNCFile::inq_dimlen_impl(const std::string &dimension_name, unsigned int &result) const {
121 int stat, dimid = -1;
122 MPI_Offset len;
123
124 stat = ncmpi_inq_dimid(m_file_id, dimension_name.c_str(), &dimid);
126
127 stat = ncmpi_inq_dimlen(m_file_id, dimid, &len);
129
130 result = static_cast<unsigned int>(len);
131}
132
133
134void PNCFile::inq_unlimdim_impl(std::string &result) const {
135 int stat = NC_NOERR, dimid = -1;
136 char dimname[NC_MAX_NAME];
137
138 stat = ncmpi_inq_unlimdim(m_file_id, &dimid);
140
141 if (dimid == -1) {
142 result.clear();
143 } else {
144 stat = ncmpi_inq_dimname(m_file_id, dimid, dimname);
146
147 result = dimname;
148 }
149}
150
151void PNCFile::def_var_impl(const std::string &name, io::Type nctype,
152 const std::vector<std::string> &dims) const {
153 std::vector<int> dimids;
154 int stat, varid;
155
156 for (auto d : dims) {
157 int dimid = -1;
158 stat = ncmpi_inq_dimid(m_file_id, d.c_str(), &dimid);
160 dimids.push_back(dimid);
161 }
162
163 stat = ncmpi_def_var(m_file_id, name.c_str(), pism_type_to_nc_type(nctype),
164 static_cast<int>(dims.size()), dimids.data(), &varid);
166}
167
168
169void PNCFile::get_vara_double_impl(const std::string &variable_name,
170 const std::vector<unsigned int> &start,
171 const std::vector<unsigned int> &count, double *ip) const {
172 return this->get_var_double(variable_name, start, count, ip);
173}
174
175
176void PNCFile::put_vara_double_impl(const std::string &variable_name,
177 const std::vector<unsigned int> &start,
178 const std::vector<unsigned int> &count, const double *op) const {
179 int stat, varid, ndims = static_cast<int>(start.size());
180
181 std::vector<MPI_Offset> nc_start(ndims), nc_count(ndims);
182
183 stat = ncmpi_inq_varid(m_file_id, variable_name.c_str(), &varid);
185
186 for (int j = 0; j < ndims; ++j) {
187 nc_start[j] = start[j];
188 nc_count[j] = count[j];
189 }
190
191 stat = ncmpi_put_vara_double_all(m_file_id, varid, nc_start.data(), nc_count.data(), op);
193}
194
195void PNCFile::put_vara_text_impl(const std::string &variable_name,
196 const std::vector<unsigned int> &start,
197 const std::vector<unsigned int> &count, const char *data) const {
198 int stat, varid, ndims = static_cast<int>(start.size());
199
200 std::vector<MPI_Offset> nc_start(ndims), nc_count(ndims);
201
202 stat = ncmpi_inq_varid(m_file_id, variable_name.c_str(), &varid);
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 = ncmpi_put_vara_text_all(m_file_id, varid, nc_start.data(), nc_count.data(), data);
212}
213
214
215void PNCFile::inq_nvars_impl(int &result) const {
216 int stat;
217
218 stat = ncmpi_inq_nvars(m_file_id, &result);
220}
221
222
223void PNCFile::inq_vardimid_impl(const std::string &variable_name,
224 std::vector<std::string> &result) const {
225 int stat, ndims, varid = -1;
226 std::vector<int> dimids;
227
228 stat = ncmpi_inq_varid(m_file_id, variable_name.c_str(), &varid);
230
231 stat = ncmpi_inq_varndims(m_file_id, varid, &ndims);
233
234 if (ndims == 0) {
235 result.clear();
236 return;
237 }
238
239 result.resize(ndims);
240 dimids.resize(ndims);
241
242 stat = ncmpi_inq_vardimid(m_file_id, varid, dimids.data());
244
245 for (int k = 0; k < ndims; ++k) {
246 char name[NC_MAX_NAME];
247 memset(name, 0, NC_MAX_NAME);
248
249 stat = ncmpi_inq_dimname(m_file_id, dimids[k], name);
251
252 result[k] = name;
253 }
254}
255
256int PNCFile::get_varid(const std::string &variable_name) const {
257 if (variable_name == "PISM_GLOBAL") {
258 return NC_GLOBAL;
259 }
260
261 int varid = -1;
262 int stat = ncmpi_inq_varid(m_file_id, variable_name.c_str(), &varid);
264
265 return varid;
266}
267
268void PNCFile::inq_varnatts_impl(const std::string &variable_name, int &result) const {
269
270 int stat = ncmpi_inq_varnatts(m_file_id, get_varid(variable_name), &result);
272}
273
274
275void PNCFile::inq_varid_impl(const std::string &variable_name, bool &exists) const {
276 int stat, flag = -1;
277
278 stat = ncmpi_inq_varid(m_file_id, variable_name.c_str(), &flag);
279
280 exists = (stat == NC_NOERR);
281}
282
283
284void PNCFile::inq_varname_impl(unsigned int j, std::string &result) const {
285 int stat;
286 char varname[NC_MAX_NAME];
287 memset(varname, 0, NC_MAX_NAME);
288
289 stat = ncmpi_inq_varname(m_file_id, j, varname);
291
292 result = varname;
293}
294
295void PNCFile::get_att_double_impl(const std::string &variable_name, const std::string &att_name,
296 std::vector<double> &result) const {
297 int len, varid = get_varid(variable_name);
298 MPI_Offset attlen = 0;
299
300 // Read the attribute length:
301 int stat = ncmpi_inq_attlen(m_file_id, varid, att_name.c_str(), &attlen);
302
303 if (stat == NC_NOERR) {
304 len = static_cast<int>(attlen);
305 } else if (stat == NC_ENOTATT) {
306 len = 0;
307 } else {
309 len = 0;
310 }
311
312 if (len == 0) {
313 result.clear();
314 return;
315 }
316
317 result.resize(len);
318
319 // Now read data and broadcast stat to see if we succeeded:
320 stat = ncmpi_get_att_double(m_file_id, varid, att_name.c_str(), result.data());
322
323 // On error, print a message and stop.
324 if (stat != NC_NOERR) {
325 fprintf(stderr, "Error reading the %s attribute; (varid %d, NetCDF error %s)", att_name.c_str(),
326 varid, ncmpi_strerror(stat));
327 }
328}
329
330
331void PNCFile::get_att_text_impl(const std::string &variable_name, const std::string &att_name,
332 std::string &result) const {
333 int varid = get_varid(variable_name);
334
335 // Read the attribute length:
336 MPI_Offset attlen = 0;
337
338 int stat = ncmpi_inq_attlen(m_file_id, varid, att_name.c_str(), &attlen);
339 int len = (stat == NC_NOERR) ? static_cast<int>(attlen) : 0;
340
341 // Allocate some memory or set result to NULL and return:
342 if (len == 0) {
343 result.clear();
344 return;
345 }
346
347 std::vector<char> str(len + 1, 0);
348
349 // Now read the string and see if we succeeded:
350 stat = ncmpi_get_att_text(m_file_id, varid, att_name.c_str(), str.data());
352
353 result = str.data();
354}
355
356void PNCFile::del_att_impl(const std::string &variable_name, const std::string &att_name) const {
357 int stat = ncmpi_del_att(m_file_id, get_varid(variable_name), att_name.c_str());
359}
360
361void PNCFile::put_att_double_impl(const std::string &variable_name, const std::string &att_name,
362 io::Type nctype, const std::vector<double> &data) const {
363
364 int stat = ncmpi_put_att_double(m_file_id, get_varid(variable_name), att_name.c_str(),
365 pism_type_to_nc_type(nctype), data.size(), data.data());
367}
368
369
370void PNCFile::put_att_text_impl(const std::string &variable_name, const std::string &att_name,
371 const std::string &value) const {
372 int stat = ncmpi_put_att_text(m_file_id, get_varid(variable_name), att_name.c_str(), value.size(),
373 value.c_str());
375}
376
377
378void PNCFile::inq_attname_impl(const std::string &variable_name, unsigned int n,
379 std::string &result) const {
380 int stat;
381 char name[NC_MAX_NAME];
382 memset(name, 0, NC_MAX_NAME);
383
384 int varid = get_varid(variable_name);
385
386 stat = ncmpi_inq_attname(m_file_id, varid, n, name);
388
389 result = name;
390}
391
392
393void PNCFile::inq_atttype_impl(const std::string &variable_name, const std::string &att_name,
394 io::Type &result) const {
395 int varid = get_varid(variable_name);
396
397 nc_type tmp = NC_NAT;
398 int stat = ncmpi_inq_atttype(m_file_id, varid, att_name.c_str(), &tmp);
399 if (stat == NC_ENOTATT) {
400 tmp = NC_NAT;
401 } else {
403 }
404
405 result = nc_type_to_pism_type(tmp);
406}
407
408
409void PNCFile::set_fill_impl(int fillmode, int &old_modep) const {
410 int stat = ncmpi_set_fill(m_file_id, fillmode, &old_modep);
412}
413
414
415void PNCFile::get_var_double(const std::string &variable_name,
416 const std::vector<unsigned int> &start,
417 const std::vector<unsigned int> &count, double *ip) const {
418 int stat, varid, ndims = static_cast<int>(start.size());
419
420 std::vector<MPI_Offset> nc_start(ndims), nc_count(ndims);
421
422 stat = ncmpi_inq_varid(m_file_id, variable_name.c_str(), &varid);
424
425 for (int j = 0; j < ndims; ++j) {
426 nc_start[j] = start[j];
427 nc_count[j] = count[j];
428 }
429
430 stat = ncmpi_get_vara_double_all(m_file_id, varid, nc_start.data(), nc_count.data(), ip);
432}
433
435
436 for (auto hint : m_mpi_io_hints) {
437 auto words = split(hint, ':');
438
439 if (words.size() == 2) {
440 // printf("Setting MPI I/O hint \"%s\" to \"%s\"...\n",
441 // words[0].c_str(), words[1].c_str());
442
443 MPI_Info_set(m_mpi_info,
444 const_cast<char*>(words[0].c_str()),
445 const_cast<char*>(words[1].c_str()));
446 } else {
447 int rank = 0;
448 MPI_Comm_rank(m_com, &rank);
449 if (rank == 0) {
450 printf("PISM WARNING: invalid MPI I/O hint: %s. Ignoring it...\n",
451 hint.c_str());
452 }
453 }
454 }
455}
456
458 (void) level;
459 // NetCDF-3 does not support compression.
460}
461
462} // end of namespace io
463} // end of namespace pism
MPI_Comm m_com
Definition NCFile.hh:231
The PISM wrapper for a subset of the NetCDF C API.
Definition NCFile.hh:61
void def_dim_impl(const std::string &name, size_t length) const
Definition PNCFile.cc:99
PNCFile(MPI_Comm com)
Definition PNCFile.cc:33
void inq_unlimdim_impl(std::string &result) const
Definition PNCFile.cc:134
void get_vara_double_impl(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, double *ip) const
Definition PNCFile.cc:169
void inq_varid_impl(const std::string &variable_name, bool &exists) const
Definition PNCFile.cc:275
void close_impl()
Definition PNCFile.cc:77
void inq_varname_impl(unsigned int j, std::string &result) const
Definition PNCFile.cc:284
void inq_dimid_impl(const std::string &dimension_name, bool &exists) const
Definition PNCFile.cc:107
void inq_nvars_impl(int &result) const
Definition PNCFile.cc:215
void del_att_impl(const std::string &variable_name, const std::string &att_name) const
Definition PNCFile.cc:356
void enddef_impl() const
Definition PNCFile.cc:85
void put_vara_double_impl(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const double *op) const
Definition PNCFile.cc:176
void inq_varnatts_impl(const std::string &variable_name, int &result) const
Definition PNCFile.cc:268
void inq_dimlen_impl(const std::string &dimension_name, unsigned int &result) const
Definition PNCFile.cc:120
std::vector< std::string > m_mpi_io_hints
Definition PNCFile.hh:115
void sync_impl() const
Definition PNCFile.cc:70
void put_att_double_impl(const std::string &variable_name, const std::string &att_name, io::Type xtype, const std::vector< double > &data) const
Definition PNCFile.cc:361
void inq_attname_impl(const std::string &variable_name, unsigned int n, std::string &result) const
Definition PNCFile.cc:378
void get_var_double(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, double *ip) const
Definition PNCFile.cc:415
void inq_atttype_impl(const std::string &variable_name, const std::string &att_name, io::Type &result) const
Definition PNCFile.cc:393
virtual ~PNCFile()
Definition PNCFile.cc:39
void inq_vardimid_impl(const std::string &variable_name, std::vector< std::string > &result) const
Definition PNCFile.cc:223
void get_att_text_impl(const std::string &variable_name, const std::string &att_name, std::string &result) const
Definition PNCFile.cc:331
MPI_Info m_mpi_info
Definition PNCFile.hh:124
void redef_impl() const
Definition PNCFile.cc:92
void set_fill_impl(int fillmode, int &old_modep) const
Definition PNCFile.cc:409
void set_compression_level_impl(int level) const
Definition PNCFile.cc:457
void create_impl(const std::string &filename)
Definition PNCFile.cc:61
void get_att_double_impl(const std::string &variable_name, const std::string &att_name, std::vector< double > &result) const
Definition PNCFile.cc:295
int get_varid(const std::string &variable_name) const
Definition PNCFile.cc:256
void open_impl(const std::string &filename, io::Mode mode)
Definition PNCFile.cc:49
void put_att_text_impl(const std::string &variable_name, const std::string &att_name, const std::string &value) const
Definition PNCFile.cc:370
void def_var_impl(const std::string &name, io::Type nctype, const std::vector< std::string > &dims) const
Definition PNCFile.cc:151
void put_vara_text_impl(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const char *data) const
Definition PNCFile.cc:195
#define PISM_ERROR_LOCATION
#define n
Definition exactTestM.c:37
@ PISM_READONLY
open an existing file for reading only
Definition IO_Flags.hh:69
static void check(const ErrorLocation &where, int return_code)
Prints an error message; for debugging.
Definition NC4_Par.cc:42
std::string printf(const char *format,...)
static const double k
Definition exactTestP.cc:42
static pism::io::Type nc_type_to_pism_type(int input)
static nc_type pism_type_to_nc_type(pism::io::Type input)
std::vector< std::string > split(const std::string &input, char separator)
Transform a separator-separated list (a string) into a vector of strings.
int count
Definition test_cube.c:16