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"
32#include "pism/pism_config.hh"
34#if (Pism_USE_PARALLEL_NETCDF4==1)
35#include "pism/util/io/NC4_Par.hh"
38#if (Pism_USE_PNETCDF==1)
39#include "pism/util/io/PNCFile.hh"
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"
51 std::shared_ptr<io::NCFile>
nc;
57 std::map<std::string, io::Backend> backends =
65 if (backends.find(backend) != backends.end()) {
66 return backends[backend];
70 "unknown or unsupported I/O backend: %s",
75 std::map<io::Backend, std::string> backends =
84 return backends[backend];
101#if (Pism_USE_PARALLEL_NETCDF4==1)
102 if (format ==
"netcdf4") {
107#if (Pism_USE_PNETCDF==1)
108 if (format !=
"netcdf4") {
119 MPI_Comm_size(com, &size);
124 return std::make_shared<io::NC_Serial>(com);
127 return std::make_shared<io::NC4_Serial>(com);
130#if (Pism_USE_PARALLEL_NETCDF4 == 1)
131 return std::make_shared<io::NC4_Par>(com);
137#if (Pism_USE_PNETCDF == 1)
138 return std::make_shared<io::PNCFile>(com);
150 "unknown or unsupported I/O backend: %s",
151 backend_name.c_str());
157 if (filename.empty()) {
159 "cannot open file: provided file name is empty");
169 this->
open(filename, mode);
190 m_impl->
nc->set_compression_level(level);
223 e.
add_context(
"opening or creating \"" + filename +
"\"");
291 e.
add_context(
"getting the number of records in file \"" +
name() +
"\"");
299unsigned int File::nrecords(
const std::string &variable_name,
const std::string &std_name,
304 if (not var.exists) {
316 e.
add_context(
"getting the number of records of variable '%s' ('%s') in '%s'",
299unsigned int File::nrecords(
const std::string &variable_name,
const std::string &std_name, {
…}
333 if (not std_name.empty()) {
337 for (
int j = 0; j < n_variables; ++j) {
341 if (attribute.empty()) {
345 if (attribute == std_name) {
348 result.
name = var_name;
351 "have the same standard_name (%s)",
352 name().c_str(), result.
name.c_str(),
353 var_name.c_str(), attribute.c_str());
363 result.
name = short_name;
370 e.
add_context(
"searching for variable '%s' ('%s') in '%s'", short_name.c_str(), std_name.c_str(),
name().c_str());
392 std::vector<std::string> result;
407 m_impl->
nc->inq_dimid(dimension_name, exists);
410 e.
add_context(
"searching for dimension '%s' in '%s'", dimension_name.c_str(),
423 unsigned int result = 0;
424 m_impl->
nc->inq_dimlen(dimension_name, result);
430 e.
add_context(
"getting the length of dimension '%s' in '%s'", dimension_name.c_str(),
437 if (input ==
"T" or input ==
"t") {
441 if (input ==
"X" or input ==
"x") {
445 if (input ==
"Y" or input ==
"y") {
449 if (input ==
"Z" or input ==
"z") {
480 if (standard_name ==
"time") {
484 if (standard_name ==
"projection_x_coordinate" or
485 standard_name ==
"grid_longitude") {
489 if (standard_name ==
"projection_y_coordinate" or
490 standard_name ==
"grid_latitude") {
502 if (
member(dimension_name, {
"x",
"X",
"rlon"}) or
503 dimension_name.find(
'x') == 0 or dimension_name.find(
'X') == 0) {
507 if (
member(dimension_name, {
"y",
"Y",
"rlat"}) or
508 dimension_name.find(
'y') == 0 or dimension_name.find(
'Y') == 0) {
512 if (dimension_name ==
"z" or dimension_name ==
"Z" or
513 dimension_name.find(
'z') == 0 or dimension_name.find(
'Z') == 0) {
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) {
525 e.
add_context(
"getting the type of dimension '%s' in '%s'",
526 dimension_name.c_str(),
name().c_str());
534 m_impl->
nc->def_dim(dimension_name, length);
536 e.
add_context(
"defining dimension '%s' in '%s'", dimension_name.c_str(),
544 const std::vector<std::string> &dims)
const {
584 e.
add_context(
"appending to the history attribute in \"" +
name() +
"\"");
591 const std::vector<double> &values)
const {
594 m_impl->
nc->put_att_double(var_name, att_name, nctype, values);
596 e.
add_context(
"writing double attribute '%s:%s' in '%s'",
597 var_name.c_str(), att_name.c_str(),
name().c_str());
604 const std::string &value)
const {
608 m_impl->
nc->put_att_text(var_name, att_name, value +
"\0");
610 e.
add_context(
"writing text attribute '%s:%s' in '%s'",
611 var_name.c_str(), att_name.c_str(),
name().c_str());
628 "attribute %s is a string '%s'; expected a number or a list of numbers",
629 att_name.c_str(), tmp.c_str());
634 std::vector<double> result;
635 m_impl->
nc->get_att_double(var_name, att_name, result);
638 e.
add_context(
"reading double attribute '%s:%s' from '%s'",
639 var_name.c_str(), att_name.c_str(),
name().c_str());
651 "attribute %s is not a string", att_name.c_str());
655 m_impl->
nc->get_att_text(var_name, att_name, result);
658 e.
add_context(
"reading text attribute '%s:%s' from %s", var_name.c_str(), att_name.c_str(),
name().c_str());
666 m_impl->
nc->inq_varnatts(var_name, result);
669 e.
add_context(
"getting the number of attributes of variable '%s' in '%s'", var_name.c_str(),
name().c_str());
678 m_impl->
nc->inq_attname(var_name,
n, result);
681 e.
add_context(
"getting the name of an attribute of variable '%s' in '%s'", var_name.c_str(),
name().c_str());
690 m_impl->
nc->inq_atttype(var_name, att_name, result);
693 e.
add_context(
"getting the type of an attribute of variable '%s' in '%s'", var_name.c_str(),
name().c_str());
700 const std::vector<unsigned int> &start,
701 const std::vector<unsigned int> &
count,
713 const std::vector<unsigned int> &start,
714 const std::vector<unsigned int> &
count,
715 const double *op)
const {
727 unsigned int z_count,
729 const double *input)
const {
732 assert(t_length > 0);
736 e.
add_context(
"writing distributed array '%s' to '%s'",
748 e.
add_context(
"getting the number of variables in '%s'",
name().c_str());
758 m_impl->
nc->inq_varname(
id, result);
760 e.
add_context(
"getting the name of %d-th variable in '%s'",
id,
name().c_str());
bool dimension_exists(const std::string &name) const
Checks if a dimension exists.
unsigned int nvariables() const
void write_distributed_array(const std::string &variable_name, const Grid &grid, unsigned int z_count, bool time_dependent, const double *input) const
void read_variable(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, double *ip) const
void define_dimension(const std::string &name, size_t length) const
std::string attribute_name(const std::string &var_name, unsigned int n) const
AxisType dimension_type(const std::string &name, units::System::Ptr unit_system) const
Get the "type" of a dimension.
void set_compression_level(int level) const
void open(const std::string &filename, io::Mode mode)
void set_variable_was_written(const std::string &name) const
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.
unsigned int nrecords() const
Get the number of records. Uses the length of an unlimited dimension.
std::string variable_name(unsigned int id) const
bool variable_exists(const std::string &short_name) const
Checks if a variable exists.
void write_variable(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const double *op) const
File(MPI_Comm com, const std::string &filename, io::Backend backend, io::Mode mode)
void define_variable(const std::string &name, io::Type nctype, const std::vector< std::string > &dims) const
Define a variable.
io::Type attribute_type(const std::string &var_name, const std::string &att_name) const
void remove_attribute(const std::string &variable_name, const std::string &att_name) const
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.
std::vector< double > read_double_attribute(const std::string &var_name, const std::string &att_name) const
Get a double attribute.
bool get_variable_was_written(const std::string &name) const
unsigned int nattributes(const std::string &var_name) const
void append_history(const std::string &history) const
Append to the history global attribute.
unsigned int dimension_length(const std::string &name) const
Get the length of a dimension.
std::vector< std::string > dimensions(const std::string &variable_name) const
std::string read_text_attribute(const std::string &var_name, const std::string &att_name) const
Get a text attribute.
Describes the PISM grid and the distribution of data across processors.
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)
std::string get_format() const
std::shared_ptr< System > Ptr
#define PISM_ERROR_LOCATION
@ PISM_READWRITE_CLOBBER
create a file for writing, overwrite if present
@ PISM_READWRITE_MOVE
create a file for writing, move foo.nc to foo.nc~ if present
@ PISM_READONLY
open an existing file for reading only
@ PISM_READWRITE
open an existing file for reading and writing
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~).
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)
io::Backend string_to_backend(const std::string &backend)
static io::Backend choose_backend(MPI_Comm com, const std::string &filename)
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)
AxisType axis_type_from_string(const std::string &input)
static std::shared_ptr< io::NCFile > create_backend(MPI_Comm com, io::Backend backend)
std::shared_ptr< io::NCFile > nc
std::set< std::string > written_variables