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