PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
File.cc
Go to the documentation of this file.
1// Copyright (C) 2012--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 <cassert>
20#include <cstdio>
21#include <memory>
22#include <map>
23
24#include <petscvec.h>
25#include <set>
26
27#include "pism/util/io/File.hh"
28#include "pism/util/Grid.hh"
29#include "pism/util/io/NC_Serial.hh"
30#include "pism/util/io/NC4_Serial.hh"
31
32#include "pism/pism_config.hh"
33
34#if (Pism_USE_PARALLEL_NETCDF4==1)
35#include "pism/util/io/NC4_Par.hh"
36#endif
37
38#if (Pism_USE_PNETCDF==1)
39#include "pism/util/io/PNCFile.hh"
40#endif
41
42#include "pism/util/error_handling.hh"
43#include "pism/util/io/io_helpers.hh"
44#include "pism/util/io/IO_Flags.hh"
45#include "pism/util/pism_utilities.hh"
46
47namespace pism {
48
49struct File::Impl {
50 MPI_Comm com;
51 std::shared_ptr<io::NCFile> nc;
52
53 std::set<std::string> written_variables;
54};
55
56io::Backend string_to_backend(const std::string &backend) {
57 std::map<std::string, io::Backend> backends =
58 {
59 {"netcdf3", io::PISM_NETCDF3},
60 {"netcdf4_parallel", io::PISM_NETCDF4_PARALLEL},
61 {"netcdf4_serial", io::PISM_NETCDF4_SERIAL},
62 {"pnetcdf", io::PISM_PNETCDF},
63 };
64
65 if (backends.find(backend) != backends.end()) {
66 return backends[backend];
67 }
68
70 "unknown or unsupported I/O backend: %s",
71 backend.c_str());
72}
73
74static std::string backend_to_string(io::Backend backend) {
75 std::map<io::Backend, std::string> backends =
76 {
77 {io::PISM_GUESS, "unknown"},
78 {io::PISM_NETCDF3, "netcdf3"},
79 {io::PISM_NETCDF4_PARALLEL, "netcdf4_parallel"},
80 {io::PISM_NETCDF4_SERIAL, "netcdf4_serial"},
81 {io::PISM_PNETCDF, "pnetcdf"}
82 };
83
84 return backends[backend];
85}
86
87// Chooses the best available I/O backend for reading from 'filename'.
88static io::Backend choose_backend(MPI_Comm com, const std::string &filename) {
89
90 std::string format;
91 {
92 // This is the rank-0-only purely-serial mode of accessing NetCDF files, but it
93 // supports all the kinds of NetCDF, so this is fine.
94 io::NC_Serial file(com);
95
96 file.open(filename, io::PISM_READONLY);
97 format = file.get_format();
98 file.close();
99 }
100
101#if (Pism_USE_PARALLEL_NETCDF4==1)
102 if (format == "netcdf4") {
104 }
105#endif
106
107#if (Pism_USE_PNETCDF==1)
108 if (format != "netcdf4") {
109 return io::PISM_PNETCDF;
110 }
111#endif
112
113 // this choice is appropriate for both NetCDF-3 and NetCDF-4
114 return io::PISM_NETCDF3;
115}
116
117static std::shared_ptr<io::NCFile> create_backend(MPI_Comm com, io::Backend backend) {
118 int size = 1;
119 MPI_Comm_size(com, &size);
120
121 switch (backend) {
122
123 case io::PISM_NETCDF3:
124 return std::make_shared<io::NC_Serial>(com);
125
127 return std::make_shared<io::NC4_Serial>(com);
128
130#if (Pism_USE_PARALLEL_NETCDF4 == 1)
131 return std::make_shared<io::NC4_Par>(com);
132#else
133 break;
134#endif
135
136 case io::PISM_PNETCDF:
137#if (Pism_USE_PNETCDF == 1)
138 return std::make_shared<io::PNCFile>(com);
139#else
140 break;
141#endif
142
143 case io::PISM_GUESS:
144 break;
145 } // end of switch (backend)
146
147 auto backend_name = backend_to_string(backend);
148
150 "unknown or unsupported I/O backend: %s",
151 backend_name.c_str());
152}
153
154File::File(MPI_Comm com, const std::string &filename, io::Backend backend, io::Mode mode)
155 : m_impl(new Impl) {
156
157 if (filename.empty()) {
159 "cannot open file: provided file name is empty");
160 }
161
162 if (backend == io::PISM_GUESS) {
163 backend = choose_backend(com, filename);
164 }
165
166 m_impl->com = com;
167 m_impl->nc = create_backend(m_impl->com, backend);
168
169 this->open(filename, mode);
170}
171
173 if (m_impl->nc and not name().empty()) {
174 try {
175 // a file is still open, so we try to close it
176 this->close();
177 } catch (...) {
178 // don't ever throw from here
179 handle_fatal_errors(MPI_COMM_SELF);
180 }
181 }
182 delete m_impl;
183}
184
185MPI_Comm File::com() const {
186 return m_impl->com;
187}
188
189void File::set_compression_level(int level) const {
190 m_impl->nc->set_compression_level(level);
191}
192
193void File::open(const std::string &filename, io::Mode mode) {
194 try {
195
196 // opening for reading
197 if (mode == io::PISM_READONLY) {
198
199 m_impl->nc->open(filename, mode);
200
201 } else if (mode == io::PISM_READWRITE_CLOBBER or mode == io::PISM_READWRITE_MOVE) {
202
203 if (mode == io::PISM_READWRITE_MOVE) {
204 io::move_if_exists(m_impl->com, filename);
205 } else {
206 io::remove_if_exists(m_impl->com, filename);
207 }
208
209 m_impl->nc->create(filename);
210
211 int old_fill;
212 m_impl->nc->set_fill(io::PISM_NOFILL, old_fill);
213 } else if (mode == io::PISM_READWRITE) { // mode == io::PISM_READWRITE
214
215 m_impl->nc->open(filename, mode);
216
217 int old_fill;
218 m_impl->nc->set_fill(io::PISM_NOFILL, old_fill);
219 } else {
220 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "invalid mode: %d", mode);
221 }
222 } catch (RuntimeError &e) {
223 e.add_context("opening or creating \"" + filename + "\"");
224 throw;
225 }
226}
227
228void File::remove_attribute(const std::string &variable_name, const std::string &att_name) const {
229 try {
230 m_impl->nc->del_att(variable_name, att_name);
231 } catch (RuntimeError &e) {
232 e.add_context("deleting the attribute %s:%s", variable_name.c_str(), att_name.c_str());
233 throw;
234 }
235}
236
238 try {
239 m_impl->nc->close();
240 } catch (RuntimeError &e) {
241 e.add_context("closing \"" + name() + "\"");
242 throw;
243 }
244}
245
246void File::sync() const {
247 try {
248 m_impl->nc->sync();
249 } catch (RuntimeError &e) {
250 e.add_context("synchronizing \"" + name() + "\"");
251 throw;
252 }
253}
254
255void File::redef() const {
256 try {
257 m_impl->nc->redef();
258 } catch (RuntimeError &e) {
259 e.add_context("switching to define mode; file \"" + name() + "\"");
260 throw;
261 }
262}
263
264
265void File::enddef() const {
266 try {
267 m_impl->nc->enddef();
268 } catch (RuntimeError &e) {
269 e.add_context("switching to data mode; file \"" + name() + "\"");
270 throw;
271 }
272}
273
274std::string File::name() const {
275 return m_impl->nc->filename();
276}
277
278
279//! \brief Get the number of records. Uses the length of an unlimited dimension.
280unsigned int File::nrecords() const {
281 try {
282 std::string dim;
283 m_impl->nc->inq_unlimdim(dim);
284
285 if (dim.empty()) {
286 return 1; // one record
287 }
288
289 return this->dimension_length(dim);
290 } catch (RuntimeError &e) {
291 e.add_context("getting the number of records in file \"" + name() + "\"");
292 throw;
293 }
294 return 0; // LCOV_EXCL_LINE
295}
296
297//! \brief Get the number of records of a certain variable. Uses the length of
298//! an associated "time" dimension.
299unsigned int File::nrecords(const std::string &variable_name, const std::string &std_name,
300 units::System::Ptr unit_system) const {
301 try {
302 auto var = find_variable(variable_name, std_name);
303
304 if (not var.exists) {
305 return 0;
306 }
307
308 for (const auto &d : dimensions(var.name)) {
309 if (dimension_type(d, unit_system) == T_AXIS) {
310 return this->dimension_length(d);
311 }
312 }
313
314 return 1; // one record
315 } catch (RuntimeError &e) {
316 e.add_context("getting the number of records of variable '%s' ('%s') in '%s'",
317 variable_name.c_str(), std_name.c_str(), name().c_str());
318 throw;
319 }
320 return 0; // LCOV_EXCL_LINE
321}
322
323
324//! \brief Find a variable using its standard name and/or short name.
325/*!
326 * Sets "result" to the short name found.
327 */
328VariableLookupData File::find_variable(const std::string &short_name, const std::string &std_name) const {
329 VariableLookupData result;
330 try {
331 result.exists = false;
332
333 if (not std_name.empty()) {
334
335 int n_variables = nvariables();
336
337 for (int j = 0; j < n_variables; ++j) {
338 std::string var_name = variable_name(j);
339 std::string attribute = read_text_attribute(var_name, "standard_name");
340
341 if (attribute.empty()) {
342 continue;
343 }
344
345 if (attribute == std_name) {
346 if (not result.exists) {
347 result.exists = true;
348 result.name = var_name;
349 } else {
350 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "inconsistency in '%s': variables '%s' and '%s'\n"
351 "have the same standard_name (%s)",
352 name().c_str(), result.name.c_str(),
353 var_name.c_str(), attribute.c_str());
354 }
355 }
356
357 } // end of the for loop
358 } // end of if (not std_name.empty())
359
360 if (not result.exists) {
361 m_impl->nc->inq_varid(short_name, result.exists);
362 if (result.exists) {
363 result.name = short_name;
364 } else {
365 result.name = "";
366 }
367 }
368
369 } catch (RuntimeError &e) {
370 e.add_context("searching for variable '%s' ('%s') in '%s'", short_name.c_str(), std_name.c_str(), name().c_str());
371 throw;
372 }
373
374 return result;
375}
376
377//! \brief Checks if a variable exists.
378bool File::variable_exists(const std::string &variable_name) const {
379 try {
380 bool exists = false;
381 m_impl->nc->inq_varid(variable_name, exists);
382 return exists;
383 } catch (RuntimeError &e) {
384 e.add_context("searching for variable '%s' in '%s'", variable_name.c_str(),
385 name().c_str());
386 throw;
387 }
388}
389
390std::vector<std::string> File::dimensions(const std::string &variable_name) const {
391 try {
392 std::vector<std::string> result;
393 m_impl->nc->inq_vardimid(variable_name, result);
394 return result;
395 } catch (RuntimeError &e) {
396 e.add_context("getting dimensions of variable '%s' in '%s'", variable_name.c_str(),
397 name().c_str());
398 throw;
399 }
400}
401
402
403//! \brief Checks if a dimension exists.
404bool File::dimension_exists(const std::string &dimension_name) const {
405 try {
406 bool exists = false;
407 m_impl->nc->inq_dimid(dimension_name, exists);
408 return exists;
409 } catch (RuntimeError &e) {
410 e.add_context("searching for dimension '%s' in '%s'", dimension_name.c_str(),
411 name().c_str());
412 throw;
413 }
414}
415
416//! \brief Get the length of a dimension.
417/*!
418 * Sets result to 0 if a dimension does not exist.
419 */
420unsigned int File::dimension_length(const std::string &dimension_name) const {
421 try {
422 if (dimension_exists(dimension_name)) {
423 unsigned int result = 0;
424 m_impl->nc->inq_dimlen(dimension_name, result);
425 return result;
426 }
427
428 return 0;
429 } catch (RuntimeError &e) {
430 e.add_context("getting the length of dimension '%s' in '%s'", dimension_name.c_str(),
431 name().c_str());
432 throw;
433 }
434}
435
436AxisType axis_type_from_string(const std::string &input) {
437 if (input == "T" or input == "t") {
438 return T_AXIS;
439 }
440
441 if (input == "X" or input == "x") {
442 return X_AXIS;
443 }
444
445 if (input == "Y" or input == "y") {
446 return Y_AXIS;
447 }
448
449 if (input == "Z" or input == "z") {
450 return Z_AXIS;
451 }
452
453 return UNKNOWN_AXIS;
454}
455
456//! \brief Get the "type" of a dimension.
457/*!
458 * The "type" is one of X_AXIS, Y_AXIS, Z_AXIS, T_AXIS.
459 */
460AxisType File::dimension_type(const std::string &dimension_name,
461 units::System::Ptr unit_system) const {
462 try {
463 if (not variable_exists(dimension_name)) {
464 throw RuntimeError(PISM_ERROR_LOCATION, "coordinate variable " + dimension_name + " is missing");
465 }
466
467 std::string
468 axis = read_text_attribute(dimension_name, "axis"),
469 standard_name = read_text_attribute(dimension_name, "standard_name"),
470 long_name = read_text_attribute(dimension_name, "long_name"),
471 units = read_text_attribute(dimension_name, "units");
472
473 if (long_name == "experiment ID") {
474 return EXP_ID_AXIS;
475 }
476
477 // check if it has units compatible with "seconds":
478
479 units::Unit seconds(unit_system, "seconds");
480 if (units::are_convertible(units::Unit(unit_system, units), seconds)) {
481 return T_AXIS;
482 }
483
484 // check the standard_name attribute:
485 if (standard_name == "time") {
486 return T_AXIS;
487 }
488
489 if (set_member(standard_name, { "projection_x_coordinate", "grid_longitude", "longitude" }) or
490 units == "degree_east") {
491 return X_AXIS;
492 }
493
494 if (set_member(standard_name, { "projection_y_coordinate", "grid_latitude", "latitude" }) or
495 units == "degree_north") {
496 return Y_AXIS;
497 }
498
499 {
501 if (tmp != UNKNOWN_AXIS) {
502 return tmp;
503 }
504 }
505
506 // check the variable name:
507 if (set_member(dimension_name, {"x", "X", "rlon", "lon", "longitude"}) or
508 dimension_name.find('x') == 0 or dimension_name.find('X') == 0) {
509 return X_AXIS;
510 }
511
512 if (set_member(dimension_name, {"y", "Y", "rlat", "lat", "latitude"}) or
513 dimension_name.find('y') == 0 or dimension_name.find('Y') == 0) {
514 return Y_AXIS;
515 }
516
517 if (dimension_name == "z" or dimension_name == "Z" or
518 dimension_name.find('z') == 0 or dimension_name.find('Z') == 0) {
519 return Z_AXIS;
520 }
521
522 if (dimension_name == "t" or dimension_name == "T" or dimension_name == "time" or
523 dimension_name.find('t') == 0 or dimension_name.find('T') == 0) {
524 return T_AXIS;
525 }
526
527 // we have no clue:
528 return UNKNOWN_AXIS;
529 } catch (RuntimeError &e) {
530 e.add_context("getting the type of dimension '%s' in '%s'",
531 dimension_name.c_str(), name().c_str());
532 throw;
533 }
534 return UNKNOWN_AXIS; // LCOV_EXCL_LINE
535}
536
537void File::define_dimension(const std::string &dimension_name, size_t length) const {
538 try {
539 m_impl->nc->def_dim(dimension_name, length);
540 } catch (RuntimeError &e) {
541 e.add_context("defining dimension '%s' in '%s'", dimension_name.c_str(),
542 name().c_str());
543 throw;
544 }
545}
546
547//! \brief Define a variable.
548void File::define_variable(const std::string &variable_name, io::Type nctype,
549 const std::vector<std::string> &dims) const {
550 try {
551 m_impl->nc->def_var(variable_name, nctype, dims);
552
553 // FIXME: I need to write and tune chunk_dimensions that would be called below before we use
554 // this.
555 //
556 /*
557 // if it's not a spatial variable, we're done
558 if (dims.size() < 2) {
559 return;
560 }
561
562 std::vector<size_t> dim_lengths;
563 for (unsigned int k = 0; k < dims.size(); ++k) {
564 dim_lengths.push_back(this->dimension_length(dims[k]));
565 }
566
567 std::vector<size_t> chunk_dims = chunk_dimensions(nctype, dim_lengths);
568
569 m_impl->nc->def_var_chunking(name, chunk_dims);
570 */
571
572 } catch (RuntimeError &e) {
573 e.add_context("defining variable '%s' in '%s'", variable_name.c_str(),
574 name().c_str());
575 throw;
576 }
577}
578
579//! \brief Append to the history global attribute.
580/*!
581 * Use write_attribute("PISM_GLOBAL", "history", ...) to overwrite "history".
582 */
583void File::append_history(const std::string &history) const {
584 try {
585 std::string old_history = read_text_attribute("PISM_GLOBAL", "history");
586 redef();
587 write_attribute("PISM_GLOBAL", "history", history + old_history);
588 } catch (RuntimeError &e) {
589 e.add_context("appending to the history attribute in \"" + name() + "\"");
590 throw;
591 }
592}
593
594//! \brief Write a multiple-valued double attribute.
595void File::write_attribute(const std::string &var_name, const std::string &att_name, io::Type nctype,
596 const std::vector<double> &values) const {
597 try {
598 redef();
599 m_impl->nc->put_att_double(var_name, att_name, nctype, values);
600 } catch (RuntimeError &e) {
601 e.add_context("writing double attribute '%s:%s' in '%s'",
602 var_name.c_str(), att_name.c_str(), name().c_str());
603 throw;
604 }
605}
606
607//! \brief Write a text attribute.
608void File::write_attribute(const std::string &var_name, const std::string &att_name,
609 const std::string &value) const {
610 try {
611 redef();
612 // ensure that the string is null-terminated
613 m_impl->nc->put_att_text(var_name, att_name, value + "\0");
614 } catch (RuntimeError &e) {
615 e.add_context("writing text attribute '%s:%s' in '%s'",
616 var_name.c_str(), att_name.c_str(), name().c_str());
617 throw;
618 }
619}
620
621//! \brief Get a double attribute.
622std::vector<double> File::read_double_attribute(const std::string &var_name, const std::string &att_name) const {
623 try {
624 auto att_type = attribute_type(var_name, att_name);
625
626 // Give an understandable error message if a string attribute was found when
627 // a number (or a list of numbers) was expected. (We've seen datasets with
628 // "valid_min" stored as a string...)
629 if (att_type == io::PISM_CHAR) {
630 std::string tmp = read_text_attribute(var_name, att_name);
631
633 "attribute %s is a string '%s'; expected a number or a list of numbers",
634 att_name.c_str(), tmp.c_str());
635 }
636
637 // In this case att_type might be io::PISM_NAT (if an attribute does not
638 // exist), but read_double_attribute can handle that.
639 std::vector<double> result;
640 m_impl->nc->get_att_double(var_name, att_name, result);
641 return result;
642 } catch (RuntimeError &e) {
643 e.add_context("reading double attribute '%s:%s' from '%s'",
644 var_name.c_str(), att_name.c_str(), name().c_str());
645 throw;
646 }
647}
648
649//! \brief Get a text attribute.
650std::string File::read_text_attribute(const std::string &var_name, const std::string &att_name) const {
651 try {
652 auto att_type = attribute_type(var_name, att_name);
653 if (att_type != io::PISM_NAT and att_type != io::PISM_CHAR) {
654 // attribute exists and is not a string
656 "attribute %s is not a string", att_name.c_str());
657 }
658
659 std::string result;
660 m_impl->nc->get_att_text(var_name, att_name, result);
661 return result;
662 } catch (RuntimeError &e) {
663 e.add_context("reading text attribute '%s:%s' from %s", var_name.c_str(), att_name.c_str(), name().c_str());
664 throw;
665 }
666}
667
668unsigned int File::nattributes(const std::string &var_name) const {
669 try {
670 int result = 0;
671 m_impl->nc->inq_varnatts(var_name, result);
672 return result;
673 } catch (RuntimeError &e) {
674 e.add_context("getting the number of attributes of variable '%s' in '%s'", var_name.c_str(), name().c_str());
675 throw;
676 }
677}
678
679
680std::string File::attribute_name(const std::string &var_name, unsigned int n) const {
681 try {
682 std::string result;
683 m_impl->nc->inq_attname(var_name, n, result);
684 return result;
685 } catch (RuntimeError &e) {
686 e.add_context("getting the name of an attribute of variable '%s' in '%s'", var_name.c_str(), name().c_str());
687 throw;
688 }
689}
690
691
692io::Type File::attribute_type(const std::string &var_name, const std::string &att_name) const {
693 try {
694 io::Type result;
695 m_impl->nc->inq_atttype(var_name, att_name, result);
696 return result;
697 } catch (RuntimeError &e) {
698 e.add_context("getting the type of an attribute of variable '%s' in '%s'", var_name.c_str(), name().c_str());
699 throw;
700 }
701}
702
703
704void File::read_variable(const std::string &variable_name,
705 const std::vector<unsigned int> &start,
706 const std::vector<unsigned int> &count,
707 double *ip) const {
708 try {
709 m_impl->nc->get_vara_double(variable_name, start, count, ip);
710 } catch (RuntimeError &e) {
711 e.add_context("reading variable '%s' from '%s'", variable_name.c_str(), name().c_str());
712 throw;
713 }
714}
715
716
717void File::write_variable(const std::string &variable_name,
718 const std::vector<unsigned int> &start,
719 const std::vector<unsigned int> &count,
720 const double *op) const {
721 try {
722 m_impl->nc->put_vara_double(variable_name, start, count, op);
723 } catch (RuntimeError &e) {
724 e.add_context("writing variable '%s' to '%s'", variable_name.c_str(), name().c_str());
725 throw;
726 }
727}
728
729void File::write_text_variable(const std::string &variable_name,
730 const std::vector<unsigned int> &start,
731 const std::vector<unsigned int> &count,
732 const std::string &input) const {
733 try {
734 m_impl->nc->put_vara_text(variable_name, start, count, input);
735 } catch (RuntimeError &e) {
736 e.add_context("writing variable '%s' to '%s'", variable_name.c_str(), name().c_str());
737 throw;
738 }
739}
740
741
742void File::write_distributed_array(const std::string &variable_name,
743 const grid::DistributedGridInfo &grid,
744 unsigned int z_count,
745 bool time_dependent,
746 const double *input) const {
747 try {
748 unsigned int t_length = nrecords();
749 assert(t_length > 0);
750
751 m_impl->nc->write_darray(variable_name, grid, z_count, time_dependent, t_length - 1, input);
752 } catch (RuntimeError &e) {
753 e.add_context("writing distributed array '%s' to '%s'",
754 variable_name.c_str(), name().c_str());
755 throw;
756 }
757}
758
759unsigned int File::nvariables() const {
760 int n_vars = 0;
761
762 try {
763 m_impl->nc->inq_nvars(n_vars);
764 } catch (RuntimeError &e) {
765 e.add_context("getting the number of variables in '%s'", name().c_str());
766 throw;
767 }
768
769 return n_vars;
770}
771
772std::string File::variable_name(unsigned int id) const {
773 std::string result;
774 try {
775 m_impl->nc->inq_varname(id, result);
776 } catch (RuntimeError &e) {
777 e.add_context("getting the name of %d-th variable in '%s'", id, name().c_str());
778 throw;
779 }
780
781 return result;
782}
783
784void File::set_variable_was_written(const std::string &name) const {
786}
787
788bool File::get_variable_was_written(const std::string &name) const {
790}
791
792} // end of namespace pism
bool dimension_exists(const std::string &name) const
Checks if a dimension exists.
Definition File.cc:404
unsigned int nvariables() const
Definition File.cc:759
Impl * m_impl
Definition File.hh:153
void read_variable(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, double *ip) const
Definition File.cc:704
void define_dimension(const std::string &name, size_t length) const
Definition File.cc:537
std::string attribute_name(const std::string &var_name, unsigned int n) const
Definition File.cc:680
AxisType dimension_type(const std::string &name, units::System::Ptr unit_system) const
Get the "type" of a dimension.
Definition File.cc:460
void set_compression_level(int level) const
Definition File.cc:189
void open(const std::string &filename, io::Mode mode)
Definition File.cc:193
void set_variable_was_written(const std::string &name) const
Definition File.cc:784
void redef() const
Definition File.cc:255
VariableLookupData find_variable(const std::string &short_name, const std::string &std_name) const
Find a variable using its standard name and/or short name.
Definition File.cc:328
void enddef() const
Definition File.cc:265
unsigned int nrecords() const
Get the number of records. Uses the length of an unlimited dimension.
Definition File.cc:280
MPI_Comm com() const
Definition File.cc:185
std::string variable_name(unsigned int id) const
Definition File.cc:772
bool variable_exists(const std::string &short_name) const
Checks if a variable exists.
Definition File.cc:378
void write_variable(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const double *op) const
Definition File.cc:717
void sync() const
Definition File.cc:246
void close()
Definition File.cc:237
File(MPI_Comm com, const std::string &filename, io::Backend backend, io::Mode mode)
Definition File.cc:154
void define_variable(const std::string &name, io::Type nctype, const std::vector< std::string > &dims) const
Define a variable.
Definition File.cc:548
io::Type attribute_type(const std::string &var_name, const std::string &att_name) const
Definition File.cc:692
void write_text_variable(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const std::string &input) const
Definition File.cc:729
void remove_attribute(const std::string &variable_name, const std::string &att_name) const
Definition File.cc:228
std::string name() const
Definition File.cc:274
void write_attribute(const std::string &var_name, const std::string &att_name, io::Type nctype, const std::vector< double > &values) const
Write a multiple-valued double attribute.
Definition File.cc:595
void write_distributed_array(const std::string &variable_name, const grid::DistributedGridInfo &grid, unsigned int z_count, bool time_dependent, const double *input) const
Definition File.cc:742
std::vector< double > read_double_attribute(const std::string &var_name, const std::string &att_name) const
Get a double attribute.
Definition File.cc:622
bool get_variable_was_written(const std::string &name) const
Definition File.cc:788
unsigned int nattributes(const std::string &var_name) const
Definition File.cc:668
void append_history(const std::string &history) const
Append to the history global attribute.
Definition File.cc:583
unsigned int dimension_length(const std::string &name) const
Get the length of a dimension.
Definition File.cc:420
std::vector< std::string > dimensions(const std::string &variable_name) const
Definition File.cc:390
std::string read_text_attribute(const std::string &var_name, const std::string &att_name) const
Get a text attribute.
Definition File.cc:650
void add_context(const std::string &message)
Add a message providing some context. This way we can (sort of) get a stack trace even though C++ exc...
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
void open(const std::string &filename, io::Mode mode)
Definition NCFile.cc:60
std::string get_format() const
Definition NC_Serial.cc:874
std::shared_ptr< System > Ptr
Definition Units.hh:47
#define PISM_ERROR_LOCATION
#define n
Definition exactTestM.c:37
@ PISM_GUESS
Definition IO_Flags.hh:57
@ PISM_NETCDF3
Definition IO_Flags.hh:58
@ PISM_PNETCDF
Definition IO_Flags.hh:61
@ PISM_NETCDF4_PARALLEL
Definition IO_Flags.hh:60
@ PISM_NETCDF4_SERIAL
Definition IO_Flags.hh:59
@ PISM_READWRITE_CLOBBER
create a file for writing, overwrite if present
Definition IO_Flags.hh:73
@ PISM_READWRITE_MOVE
create a file for writing, move foo.nc to foo.nc~ if present
Definition IO_Flags.hh:75
@ PISM_READONLY
open an existing file for reading only
Definition IO_Flags.hh:69
@ PISM_READWRITE
open an existing file for reading and writing
Definition IO_Flags.hh:71
@ PISM_CHAR
Definition IO_Flags.hh:49
void move_if_exists(MPI_Comm com, const std::string &file_to_move, int rank_to_use=0)
Moves the file aside (file.nc -> file.nc~).
@ PISM_NOFILL
Definition IO_Flags.hh:83
void remove_if_exists(MPI_Comm com, const std::string &file_to_remove, int rank_to_use=0)
Check if a file is present are remove it.
bool are_convertible(const Unit &u1, const Unit &u2)
Definition Units.cc:247
AxisType
Definition IO_Flags.hh:34
@ UNKNOWN_AXIS
Definition IO_Flags.hh:34
@ T_AXIS
Definition IO_Flags.hh:34
@ X_AXIS
Definition IO_Flags.hh:34
@ EXP_ID_AXIS
Definition IO_Flags.hh:34
@ Z_AXIS
Definition IO_Flags.hh:34
@ Y_AXIS
Definition IO_Flags.hh:34
io::Backend string_to_backend(const std::string &backend)
Definition File.cc:56
static io::Backend choose_backend(MPI_Comm com, const std::string &filename)
Definition File.cc:88
void handle_fatal_errors(MPI_Comm com)
static std::string backend_to_string(io::Backend backend)
Definition File.cc:74
AxisType axis_type_from_string(const std::string &input)
Definition File.cc:436
static std::shared_ptr< io::NCFile > create_backend(MPI_Comm com, io::Backend backend)
Definition File.cc:117
bool set_member(const std::string &string, const std::set< std::string > &set)
std::shared_ptr< io::NCFile > nc
Definition File.cc:51
MPI_Comm com
Definition File.cc:50
std::set< std::string > written_variables
Definition File.cc:53
std::string name
Definition File.hh:49
int count
Definition test_cube.c:16