26 #include "pism/util/io/File.hh"
27 #include "pism/util/Grid.hh"
28 #include "pism/util/io/NC_Serial.hh"
29 #include "pism/util/io/NC4_Serial.hh"
31 #include "pism/pism_config.hh"
33 #if (Pism_USE_PARALLEL_NETCDF4==1)
34 #include "pism/util/io/NC4_Par.hh"
37 #if (Pism_USE_PNETCDF==1)
38 #include "pism/util/io/PNCFile.hh"
42 #include "pism/util/io/ParallelIO.hh"
45 #include "pism/util/error_handling.hh"
46 #include "pism/util/io/io_helpers.hh"
47 #include "pism/util/io/IO_Flags.hh"
58 std::map<std::string, io::Backend> backends =
70 if (backends.find(backend) != backends.end()) {
71 return backends[backend];
75 "unknown or unsupported I/O backend: %s",
80 std::map<io::Backend, std::string> backends =
93 return backends[backend];
110 #if (Pism_USE_PARALLEL_NETCDF4==1)
111 if (format ==
"netcdf4") {
116 #if (Pism_USE_PNETCDF==1)
117 if (format !=
"netcdf4") {
131 MPI_Comm_size(com, &size);
139 #if (Pism_USE_PARALLEL_NETCDF4==1)
146 #if (Pism_USE_PNETCDF==1)
156 #if (Pism_USE_PIO==1)
160 "To use ParallelIO you have to pass iosysid to File");
176 "unknown or unsupported I/O backend: %s",
177 backend_name.c_str());
186 "cannot open file: provided file name is empty");
198 this->
open(filename, mode);
223 m_impl->
nc->set_compression_level(level);
332 unsigned int File::nrecords(
const std::string &name,
const std::string &std_name,
337 if (not var.exists) {
349 e.
add_context(
"getting the number of records of variable '%s' ('%s') in '%s'",
350 name.c_str(), std_name.c_str(),
filename().c_str());
366 if (not std_name.empty()) {
370 for (
int j = 0; j < n_variables; ++j) {
374 if (attribute.empty()) {
378 if (attribute == std_name) {
385 "have the same standard_name (%s)",
387 name.c_str(), attribute.c_str());
397 result.
name = short_name;
406 e.
add_context(
"searching for variable '%s' ('%s') in '%s'", short_name.c_str(), std_name.c_str(),
filename().c_str());
417 m_impl->
nc->inq_varid(name, exists);
427 std::vector<std::string> result;
442 m_impl->
nc->inq_dimid(name, exists);
457 unsigned int result = 0;
458 m_impl->
nc->inq_dimlen(name, result);
464 e.
add_context(
"getting the length of dimension '%s' in '%s'", name.c_str(),
filename().c_str());
470 if (input ==
"T" or input ==
"t") {
474 if (input ==
"X" or input ==
"x") {
478 if (input ==
"Y" or input ==
"y") {
482 if (input ==
"Z" or input ==
"z") {
513 if (standard_name ==
"time") {
517 if (standard_name ==
"projection_x_coordinate") {
521 if (standard_name ==
"projection_y_coordinate") {
533 if (name ==
"x" or name ==
"X" or
534 name.find(
'x') == 0 or name.find(
'X') == 0) {
538 if (name ==
"y" or name ==
"Y" or
539 name.find(
'y') == 0 or name.find(
'Y') == 0) {
543 if (name ==
"z" or name ==
"Z" or
544 name.find(
'z') == 0 or name.find(
'Z') == 0) {
548 if (name ==
"t" or name ==
"T" or name ==
"time" or
549 name.find(
't') == 0 or name.find(
'T') == 0) {
556 e.
add_context(
"getting the type of dimension '%s' in '%s'",
575 m_impl->
nc->def_var(name, nctype, dims);
611 std::vector<double> result(length);
639 const std::vector<double> &values)
const {
642 m_impl->
nc->put_att_double(var_name, att_name, nctype, values);
644 e.
add_context(
"writing double attribute '%s:%s' in '%s'",
645 var_name.c_str(), att_name.c_str(),
filename().c_str());
652 const std::string &value)
const {
656 m_impl->
nc->put_att_text(var_name, att_name, value +
"\0");
658 e.
add_context(
"writing text attribute '%s:%s' in '%s'",
659 var_name.c_str(), att_name.c_str(),
filename().c_str());
676 "attribute %s is a string '%s'; expected a number or a list of numbers",
677 att_name.c_str(), tmp.c_str());
682 std::vector<double> result;
683 m_impl->
nc->get_att_double(var_name, att_name, result);
686 e.
add_context(
"reading double attribute '%s:%s' from '%s'",
687 var_name.c_str(), att_name.c_str(),
filename().c_str());
699 "attribute %s is not a string", att_name.c_str());
703 m_impl->
nc->get_att_text(var_name, att_name, result);
706 e.
add_context(
"reading text attribute '%s:%s' from %s", var_name.c_str(), att_name.c_str(),
filename().c_str());
714 m_impl->
nc->inq_varnatts(var_name, result);
717 e.
add_context(
"getting the number of attributes of variable '%s' in '%s'", var_name.c_str(),
filename().c_str());
726 m_impl->
nc->inq_attname(var_name,
n, result);
729 e.
add_context(
"getting the name of an attribute of variable '%s' in '%s'", var_name.c_str(),
filename().c_str());
738 m_impl->
nc->inq_atttype(var_name, att_name, result);
741 e.
add_context(
"getting the type of an attribute of variable '%s' in '%s'", var_name.c_str(),
filename().c_str());
748 const std::vector<unsigned int> &start,
749 const std::vector<unsigned int> &
count,
761 const std::vector<unsigned int> &start,
762 const std::vector<unsigned int> &
count,
763 const double *op)
const {
775 unsigned int z_count,
777 const double *input)
const {
780 assert(t_length > 0);
784 e.
add_context(
"writing distributed array '%s' to '%s'",
792 const std::vector<unsigned int> &start,
793 const std::vector<unsigned int> &
count,
794 const std::vector<unsigned int> &imap,
double *ip)
const {
819 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 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 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
io::Backend backend() 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)
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 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.
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< double > read_dimension(const std::string &name) const
Get dimension data (a coordinate variable).
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.
File(MPI_Comm com, const std::string &filename, io::Backend backend, io::Mode mode, int iosysid=-1)
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
@ 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)
static io::NCFile::Ptr create_backend(MPI_Comm com, io::Backend backend, int iosysid)
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)
bool found_using_standard_name