22 using std::shared_ptr;
27 #include "pism/util/IceGrid.hh"
28 #include "pism/util/pism_utilities.hh"
29 #include "pism/util/VariableMetadata.hh"
30 #include "pism/util/ConfigInterface.hh"
31 #include "pism/util/Time.hh"
35 #include "pism/pism_config.hh"
37 #if (Pism_USE_PARALLEL_NETCDF4==1)
41 #if (Pism_USE_PNETCDF==1)
49 #include "pism/util/error_handling.hh"
50 #include "pism/util/io/io_helpers.hh"
61 std::map<std::string, IO_Backend> backends =
73 if (backends.find(backend) != backends.end()) {
74 return backends[backend];
78 "unknown or unsupported I/O backend: %s",
83 std::map<IO_Backend, std::string> backends =
96 return backends[backend];
113 #if (Pism_USE_PARALLEL_NETCDF4==1)
114 if (format ==
"netcdf4") {
119 #if (Pism_USE_PNETCDF==1)
120 if (format !=
"netcdf4") {
134 MPI_Comm_size(com, &size);
142 #if (Pism_USE_PARALLEL_NETCDF4==1)
149 #if (Pism_USE_PNETCDF==1)
159 #if (Pism_USE_PIO==1)
163 "To use ParallelIO you have to pass iosysid to File");
179 "unknown or unsupported I/O backend: %s",
180 backend_name.c_str());
189 "cannot open file: provided file name is empty");
201 this->
open(filename, mode);
226 m_impl->
nc->set_compression_level(level);
335 unsigned int File::nrecords(
const std::string &name,
const std::string &std_name,
340 if (not var.exists) {
352 e.
add_context(
"getting the number of records of variable '%s' ('%s') in '%s'",
353 name.c_str(), std_name.c_str(),
filename().c_str());
369 if (not std_name.empty()) {
373 for (
int j = 0; j < n_variables; ++j) {
377 if (attribute.empty()) {
381 if (attribute == std_name) {
388 "have the same standard_name (%s)",
390 name.c_str(), attribute.c_str());
400 result.
name = short_name;
409 e.
add_context(
"searching for variable '%s' ('%s') in '%s'", short_name.c_str(), std_name.c_str(),
filename().c_str());
420 m_impl->
nc->inq_varid(name, exists);
430 std::vector<std::string> result;
445 m_impl->
nc->inq_dimid(name, exists);
460 unsigned int result = 0;
461 m_impl->
nc->inq_dimlen(name, result);
467 e.
add_context(
"getting the length of dimension '%s' in '%s'", name.c_str(),
filename().c_str());
496 if (standard_name ==
"time") {
500 if (standard_name ==
"projection_x_coordinate") {
504 if (standard_name ==
"projection_y_coordinate") {
509 if (axis ==
"T" or axis ==
"t") {
513 if (axis ==
"X" or axis ==
"x") {
517 if (axis ==
"Y" or axis ==
"y") {
521 if (axis ==
"Z" or axis ==
"z") {
526 if (name ==
"x" or name ==
"X" or
527 name.find(
'x') == 0 or name.find(
'X') == 0) {
531 if (name ==
"y" or name ==
"Y" or
532 name.find(
'y') == 0 or name.find(
'Y') == 0) {
536 if (name ==
"z" or name ==
"Z" or
537 name.find(
'z') == 0 or name.find(
'Z') == 0) {
541 if (name ==
"t" or name ==
"T" or name ==
"time" or
542 name.find(
't') == 0 or name.find(
'T') == 0) {
549 e.
add_context(
"getting the type of dimension '%s' in '%s'",
568 m_impl->
nc->def_var(name, nctype, dims);
604 std::vector<double> result(length);
632 const std::vector<double> &values)
const {
635 m_impl->
nc->put_att_double(var_name, att_name, nctype, values);
637 e.
add_context(
"writing double attribute '%s:%s' in '%s'",
638 var_name.c_str(), att_name.c_str(),
filename().c_str());
645 const std::string &value)
const {
649 m_impl->
nc->put_att_text(var_name, att_name, value +
"\0");
651 e.
add_context(
"writing text attribute '%s:%s' in '%s'",
652 var_name.c_str(), att_name.c_str(),
filename().c_str());
669 "attribute %s is a string '%s'; expected a number or a list of numbers",
670 att_name.c_str(), tmp.c_str());
675 std::vector<double> result;
676 m_impl->
nc->get_att_double(var_name, att_name, result);
679 e.
add_context(
"reading double attribute '%s:%s' from '%s'",
680 var_name.c_str(), att_name.c_str(),
filename().c_str());
692 "attribute %s is not a string", att_name.c_str());
696 m_impl->
nc->get_att_text(var_name, att_name, result);
699 e.
add_context(
"reading text attribute '%s:%s' from %s", var_name.c_str(), att_name.c_str(),
filename().c_str());
707 m_impl->
nc->inq_varnatts(var_name, result);
710 e.
add_context(
"getting the number of attributes of variable '%s' in '%s'", var_name.c_str(),
filename().c_str());
719 m_impl->
nc->inq_attname(var_name,
n, result);
722 e.
add_context(
"getting the name of an attribute of variable '%s' in '%s'", var_name.c_str(),
filename().c_str());
731 m_impl->
nc->inq_atttype(var_name, att_name, result);
734 e.
add_context(
"getting the type of an attribute of variable '%s' in '%s'", var_name.c_str(),
filename().c_str());
741 const std::vector<unsigned int> &start,
742 const std::vector<unsigned int> &
count,
754 const std::vector<unsigned int> &start,
755 const std::vector<unsigned int> &
count,
756 const double *op)
const {
768 unsigned int z_count,
770 const double *input)
const {
773 assert(t_length > 0);
777 e.
add_context(
"writing distributed array '%s' to '%s'",
785 const std::vector<unsigned int> &start,
786 const std::vector<unsigned int> &
count,
787 const std::vector<unsigned int> &imap,
double *ip)
const {
812 m_impl->
nc->inq_varname(
id, result);
bool find_dimension(const std::string &name) const
Checks if a dimension exists.
unsigned int nvariables() 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 read_variable_transposed(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const std::vector< unsigned int > &imap, 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 define_variable(const std::string &name, IO_Type nctype, const std::vector< std::string > &dims) const
Define a variable.
File(MPI_Comm com, const std::string &filename, IO_Backend backend, IO_Mode mode, int iosysid=-1)
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
std::string filename() const
void write_variable(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const double *op) const
void remove_attribute(const std::string &variable_name, const std::string &att_name) const
std::vector< double > read_double_attribute(const std::string &var_name, const std::string &att_name) const
Get a double attribute.
void open(const std::string &filename, IO_Mode mode)
IO_Backend backend() const
unsigned int nattributes(const std::string &var_name) const
void append_history(const std::string &history) const
Append to the history global attribute.
void write_distributed_array(const std::string &variable_name, const IceGrid &grid, unsigned int z_count, bool time_dependent, const double *input) 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.
unsigned int dimension_length(const std::string &name) const
Get the length of a dimension.
std::vector< double > read_dimension(const std::string &name) const
Get dimension data (a coordinate variable).
IO_Type attribute_type(const std::string &var_name, const std::string &att_name) const
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
std::shared_ptr< NCFile > Ptr
void open(const std::string &filename, IO_Mode mode)
std::string get_format() const
PISM's PnetCDF I/O wrapper.
std::shared_ptr< System > Ptr
#define PISM_ERROR_LOCATION
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)
static IO_Backend choose_backend(MPI_Comm com, const std::string &filename)
static std::string backend_to_string(IO_Backend backend)
IO_Backend string_to_backend(const std::string &backend)
static io::NCFile::Ptr create_backend(MPI_Comm com, IO_Backend backend, int iosysid)
void handle_fatal_errors(MPI_Comm com)
@ 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_READWRITE
open an existing file for reading and writing
@ PISM_READONLY
open an existing file for reading only
bool found_using_standard_name