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
File.cc
Go to the documentation of this file.
1// Copyright (C) 2012--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 <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 units = read_text_attribute(dimension_name, "units");
471
472 // check if it has units compatible with "seconds":
473
474 units::Unit seconds(unit_system, "seconds");
475 if (units::are_convertible(units::Unit(unit_system, units), seconds)) {
476 return T_AXIS;
477 }
478
479 // check the standard_name attribute:
480 if (standard_name == "time") {
481 return T_AXIS;
482 }
483
484 if (standard_name == "projection_x_coordinate" or
485 standard_name == "grid_longitude") {
486 return X_AXIS;
487 }
488
489 if (standard_name == "projection_y_coordinate" or
490 standard_name == "grid_latitude") {
491 return Y_AXIS;
492 }
493
494 {
496 if (tmp != UNKNOWN_AXIS) {
497 return tmp;
498 }
499 }
500
501 // check the variable name:
502 if (member(dimension_name, {"x", "X", "rlon"}) or
503 dimension_name.find('x') == 0 or dimension_name.find('X') == 0) {
504 return X_AXIS;
505 }
506
507 if (member(dimension_name, {"y", "Y", "rlat"}) or
508 dimension_name.find('y') == 0 or dimension_name.find('Y') == 0) {
509 return Y_AXIS;
510 }
511
512 if (dimension_name == "z" or dimension_name == "Z" or
513 dimension_name.find('z') == 0 or dimension_name.find('Z') == 0) {
514 return Z_AXIS;
515 }
516
517 if (dimension_name == "t" or dimension_name == "T" or dimension_name == "time" or
518 dimension_name.find('t') == 0 or dimension_name.find('T') == 0) {
519 return T_AXIS;
520 }
521
522 // we have no clue:
523 return UNKNOWN_AXIS;
524 } catch (RuntimeError &e) {
525 e.add_context("getting the type of dimension '%s' in '%s'",
526 dimension_name.c_str(), name().c_str());
527 throw;
528 }
529 return UNKNOWN_AXIS; // LCOV_EXCL_LINE
530}
531
532void File::define_dimension(const std::string &dimension_name, size_t length) const {
533 try {
534 m_impl->nc->def_dim(dimension_name, length);
535 } catch (RuntimeError &e) {
536 e.add_context("defining dimension '%s' in '%s'", dimension_name.c_str(),
537 name().c_str());
538 throw;
539 }
540}
541
542//! \brief Define a variable.
543void File::define_variable(const std::string &variable_name, io::Type nctype,
544 const std::vector<std::string> &dims) const {
545 try {
546 m_impl->nc->def_var(variable_name, nctype, dims);
547
548 // FIXME: I need to write and tune chunk_dimensions that would be called below before we use
549 // this.
550 //
551 /*
552 // if it's not a spatial variable, we're done
553 if (dims.size() < 2) {
554 return;
555 }
556
557 std::vector<size_t> dim_lengths;
558 for (unsigned int k = 0; k < dims.size(); ++k) {
559 dim_lengths.push_back(this->dimension_length(dims[k]));
560 }
561
562 std::vector<size_t> chunk_dims = chunk_dimensions(nctype, dim_lengths);
563
564 m_impl->nc->def_var_chunking(name, chunk_dims);
565 */
566
567 } catch (RuntimeError &e) {
568 e.add_context("defining variable '%s' in '%s'", variable_name.c_str(),
569 name().c_str());
570 throw;
571 }
572}
573
574//! \brief Append to the history global attribute.
575/*!
576 * Use write_attribute("PISM_GLOBAL", "history", ...) to overwrite "history".
577 */
578void File::append_history(const std::string &history) const {
579 try {
580 std::string old_history = read_text_attribute("PISM_GLOBAL", "history");
581 redef();
582 write_attribute("PISM_GLOBAL", "history", history + old_history);
583 } catch (RuntimeError &e) {
584 e.add_context("appending to the history attribute in \"" + name() + "\"");
585 throw;
586 }
587}
588
589//! \brief Write a multiple-valued double attribute.
590void File::write_attribute(const std::string &var_name, const std::string &att_name, io::Type nctype,
591 const std::vector<double> &values) const {
592 try {
593 redef();
594 m_impl->nc->put_att_double(var_name, att_name, nctype, values);
595 } catch (RuntimeError &e) {
596 e.add_context("writing double attribute '%s:%s' in '%s'",
597 var_name.c_str(), att_name.c_str(), name().c_str());
598 throw;
599 }
600}
601
602//! \brief Write a text attribute.
603void File::write_attribute(const std::string &var_name, const std::string &att_name,
604 const std::string &value) const {
605 try {
606 redef();
607 // ensure that the string is null-terminated
608 m_impl->nc->put_att_text(var_name, att_name, value + "\0");
609 } catch (RuntimeError &e) {
610 e.add_context("writing text attribute '%s:%s' in '%s'",
611 var_name.c_str(), att_name.c_str(), name().c_str());
612 throw;
613 }
614}
615
616//! \brief Get a double attribute.
617std::vector<double> File::read_double_attribute(const std::string &var_name, const std::string &att_name) const {
618 try {
619 auto att_type = attribute_type(var_name, att_name);
620
621 // Give an understandable error message if a string attribute was found when
622 // a number (or a list of numbers) was expected. (We've seen datasets with
623 // "valid_min" stored as a string...)
624 if (att_type == io::PISM_CHAR) {
625 std::string tmp = read_text_attribute(var_name, att_name);
626
628 "attribute %s is a string '%s'; expected a number or a list of numbers",
629 att_name.c_str(), tmp.c_str());
630 }
631
632 // In this case att_type might be io::PISM_NAT (if an attribute does not
633 // exist), but read_double_attribute can handle that.
634 std::vector<double> result;
635 m_impl->nc->get_att_double(var_name, att_name, result);
636 return result;
637 } catch (RuntimeError &e) {
638 e.add_context("reading double attribute '%s:%s' from '%s'",
639 var_name.c_str(), att_name.c_str(), name().c_str());
640 throw;
641 }
642}
643
644//! \brief Get a text attribute.
645std::string File::read_text_attribute(const std::string &var_name, const std::string &att_name) const {
646 try {
647 auto att_type = attribute_type(var_name, att_name);
648 if (att_type != io::PISM_NAT and att_type != io::PISM_CHAR) {
649 // attribute exists and is not a string
651 "attribute %s is not a string", att_name.c_str());
652 }
653
654 std::string result;
655 m_impl->nc->get_att_text(var_name, att_name, result);
656 return result;
657 } catch (RuntimeError &e) {
658 e.add_context("reading text attribute '%s:%s' from %s", var_name.c_str(), att_name.c_str(), name().c_str());
659 throw;
660 }
661}
662
663unsigned int File::nattributes(const std::string &var_name) const {
664 try {
665 int result = 0;
666 m_impl->nc->inq_varnatts(var_name, result);
667 return result;
668 } catch (RuntimeError &e) {
669 e.add_context("getting the number of attributes of variable '%s' in '%s'", var_name.c_str(), name().c_str());
670 throw;
671 }
672}
673
674
675std::string File::attribute_name(const std::string &var_name, unsigned int n) const {
676 try {
677 std::string result;
678 m_impl->nc->inq_attname(var_name, n, result);
679 return result;
680 } catch (RuntimeError &e) {
681 e.add_context("getting the name of an attribute of variable '%s' in '%s'", var_name.c_str(), name().c_str());
682 throw;
683 }
684}
685
686
687io::Type File::attribute_type(const std::string &var_name, const std::string &att_name) const {
688 try {
689 io::Type result;
690 m_impl->nc->inq_atttype(var_name, att_name, result);
691 return result;
692 } catch (RuntimeError &e) {
693 e.add_context("getting the type of an attribute of variable '%s' in '%s'", var_name.c_str(), name().c_str());
694 throw;
695 }
696}
697
698
699void File::read_variable(const std::string &variable_name,
700 const std::vector<unsigned int> &start,
701 const std::vector<unsigned int> &count,
702 double *ip) const {
703 try {
704 m_impl->nc->get_vara_double(variable_name, start, count, ip);
705 } catch (RuntimeError &e) {
706 e.add_context("reading variable '%s' from '%s'", variable_name.c_str(), name().c_str());
707 throw;
708 }
709}
710
711
712void File::write_variable(const std::string &variable_name,
713 const std::vector<unsigned int> &start,
714 const std::vector<unsigned int> &count,
715 const double *op) const {
716 try {
717 m_impl->nc->put_vara_double(variable_name, start, count, op);
718 } catch (RuntimeError &e) {
719 e.add_context("writing variable '%s' to '%s'", variable_name.c_str(), name().c_str());
720 throw;
721 }
722}
723
724
725void File::write_distributed_array(const std::string &variable_name,
726 const Grid &grid,
727 unsigned int z_count,
728 bool time_dependent,
729 const double *input) const {
730 try {
731 unsigned int t_length = nrecords();
732 assert(t_length > 0);
733
734 m_impl->nc->write_darray(variable_name, grid, z_count, time_dependent, t_length - 1, input);
735 } catch (RuntimeError &e) {
736 e.add_context("writing distributed array '%s' to '%s'",
737 variable_name.c_str(), name().c_str());
738 throw;
739 }
740}
741
742unsigned int File::nvariables() const {
743 int n_vars = 0;
744
745 try {
746 m_impl->nc->inq_nvars(n_vars);
747 } catch (RuntimeError &e) {
748 e.add_context("getting the number of variables in '%s'", name().c_str());
749 throw;
750 }
751
752 return n_vars;
753}
754
755std::string File::variable_name(unsigned int id) const {
756 std::string result;
757 try {
758 m_impl->nc->inq_varname(id, result);
759 } catch (RuntimeError &e) {
760 e.add_context("getting the name of %d-th variable in '%s'", id, name().c_str());
761 throw;
762 }
763
764 return result;
765}
766
767void File::set_variable_was_written(const std::string &name) const {
769}
770
771bool File::get_variable_was_written(const std::string &name) const {
773}
774
775} // 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:742
Impl * m_impl
Definition File.hh:148
void write_distributed_array(const std::string &variable_name, const Grid &grid, unsigned int z_count, bool time_dependent, const double *input) const
Definition File.cc:725
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:699
void define_dimension(const std::string &name, size_t length) const
Definition File.cc:532
std::string attribute_name(const std::string &var_name, unsigned int n) const
Definition File.cc:675
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:767
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:755
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:712
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:543
io::Type attribute_type(const std::string &var_name, const std::string &att_name) const
Definition File.cc:687
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:590
std::vector< double > read_double_attribute(const std::string &var_name, const std::string &att_name) const
Get a double attribute.
Definition File.cc:617
bool get_variable_was_written(const std::string &name) const
Definition File.cc:771
unsigned int nattributes(const std::string &var_name) const
Definition File.cc:663
void append_history(const std::string &history) const
Append to the history global attribute.
Definition File.cc:578
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:645
Describes the PISM grid and the distribution of data across processors.
Definition Grid.hh:290
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:842
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:56
@ PISM_NETCDF3
Definition IO_Flags.hh:57
@ PISM_PNETCDF
Definition IO_Flags.hh:60
@ PISM_NETCDF4_PARALLEL
Definition IO_Flags.hh:59
@ PISM_NETCDF4_SERIAL
Definition IO_Flags.hh:58
@ PISM_READWRITE_CLOBBER
create a file for writing, overwrite if present
Definition IO_Flags.hh:72
@ PISM_READWRITE_MOVE
create a file for writing, move foo.nc to foo.nc~ if present
Definition IO_Flags.hh:74
@ PISM_READONLY
open an existing file for reading only
Definition IO_Flags.hh:68
@ PISM_READWRITE
open an existing file for reading and writing
Definition IO_Flags.hh:70
@ PISM_CHAR
Definition IO_Flags.hh:48
void move_if_exists(MPI_Comm com, const std::string &file_to_move, int rank_to_use)
Moves the file aside (file.nc -> file.nc~).
@ PISM_NOFILL
Definition IO_Flags.hh:82
void remove_if_exists(MPI_Comm com, const std::string &file_to_remove, int rank_to_use)
Check if a file is present are remove it.
bool are_convertible(const Unit &u1, const Unit &u2)
Definition Units.cc:242
AxisType
Definition IO_Flags.hh:33
@ UNKNOWN_AXIS
Definition IO_Flags.hh:33
@ T_AXIS
Definition IO_Flags.hh:33
@ X_AXIS
Definition IO_Flags.hh:33
@ Z_AXIS
Definition IO_Flags.hh:33
@ Y_AXIS
Definition IO_Flags.hh:33
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
bool member(const std::string &string, const std::set< std::string > &set)
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
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:47
int count
Definition test_cube.c:16