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