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