21 #include "pism/util/io/NC_Serial.hh"
26 #define MPI_INCLUDED 1
32 #include "pism/util/pism_utilities.hh"
33 #include "pism/util/error_handling.hh"
35 #include "pism/util/io/pism_type_conversion.hh"
42 if (return_code != NC_NOERR) {
49 if (return_code != NC_NOERR) {
50 fprintf(stderr,
"%s:%d: %s\n", where.
filename, where.
line_number, nc_strerror(return_code));
64 fprintf(stderr,
"NC_Serial::~NC_Serial: NetCDF file %s is still open\n",
83 stat = nc_open(fname.c_str(), open_mode, &
m_file_id);
88 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
98 stat = nc_create(fname.c_str(), NC_CLOBBER | NC_64BIT_OFFSET, &
m_file_id);
103 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
119 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
133 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
143 int header_size = 200 * 1024;
146 stat = nc__enddef(
m_file_id, header_size, 4, 0, 4);
150 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
164 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
176 stat = nc_def_dim(
m_file_id, name.c_str(), length, &dimid);
180 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
189 stat = nc_inq_dimid(
m_file_id, dimension_name.c_str(), &flag);
191 flag = (stat == NC_NOERR) ? 1 : 0;
194 MPI_Bcast(&flag, 1, MPI_INT, 0,
m_com);
196 exists = (flag == 1);
208 stat = nc_inq_dimid(
m_file_id, dimension_name.c_str(), &dimid);
210 if (stat == NC_NOERR) {
211 stat = nc_inq_dimlen(
m_file_id, dimid, &length);
212 result =
static_cast<unsigned int>(length);
217 MPI_Bcast(&result, 1, MPI_UNSIGNED, 0,
m_com);
218 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
226 std::vector<char> dimname(NC_MAX_NAME + 1, 0);
230 stat = nc_inq_unlimdim(
m_file_id, &dimid);
233 if (stat == NC_NOERR and dimid != -1) {
234 stat = nc_inq_dimname(
m_file_id, dimid, dimname.data());
243 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
244 MPI_Bcast(dimname.data(), NC_MAX_NAME, MPI_CHAR, 0,
m_com);
248 result = dimname.data();
253 const std::vector<std::string> &dims)
const {
257 std::vector<int> dimids;
260 for (
auto d : dims) {
262 stat = nc_inq_dimid(
m_file_id, d.c_str(), &dimid);
263 if (stat != NC_NOERR) {
266 dimids.push_back(dimid);
269 if (stat == NC_NOERR) {
271 static_cast<int>(dims.size()), dimids.data(), &varid);
276 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
282 const std::vector<unsigned int> &start,
283 const std::vector<unsigned int> &
count,
284 const std::vector<unsigned int> &imap,
double *op)
const {
289 const std::vector<unsigned int> &start,
290 const std::vector<unsigned int> &
count,
double *op)
const {
291 std::vector<unsigned int> dummy;
297 const std::vector<unsigned int> &start_input,
298 const std::vector<unsigned int> &count_input,
299 const std::vector<unsigned int> &imap_input,
double *ip,
300 bool transposed)
const {
301 std::vector<unsigned int> start = start_input;
302 std::vector<unsigned int>
count = count_input;
303 std::vector<unsigned int> imap = imap_input;
304 const int start_tag = 1, count_tag = 2, data_tag = 3, imap_tag = 4, chunk_size_tag = 5;
305 int stat = NC_NOERR, com_size, ndims =
static_cast<int>(start.size());
307 unsigned int local_chunk_size = 1, processor_0_chunk_size = 0;
309 if (not transposed) {
314 MPI_Comm_size(
m_com, &com_size);
317 for (
int k = 0;
k < ndims; ++
k) {
318 local_chunk_size *=
count[
k];
323 MPI_Reduce(&local_chunk_size, &processor_0_chunk_size, 1, MPI_UNSIGNED, MPI_MAX, 0,
m_com);
327 std::vector<double> processor_0_buffer;
331 processor_0_buffer.resize(processor_0_chunk_size);
336 std::vector<size_t> nc_start(ndims), nc_count(ndims);
337 std::vector<ptrdiff_t> nc_imap(ndims), nc_stride(ndims);
340 stat = nc_inq_varid(
m_file_id, variable_name.c_str(), &varid);
343 for (
int r = 0; r < com_size; ++r) {
348 MPI_Recv(start.data(), ndims, MPI_UNSIGNED, r, start_tag,
m_com, &mpi_stat);
349 MPI_Recv(
count.data(), ndims, MPI_UNSIGNED, r, count_tag,
m_com, &mpi_stat);
350 MPI_Recv(imap.data(), ndims, MPI_UNSIGNED, r, imap_tag,
m_com, &mpi_stat);
351 MPI_Recv(&local_chunk_size, 1, MPI_UNSIGNED, r, chunk_size_tag,
m_com, &mpi_stat);
356 for (
int k = 0;
k < ndims; ++
k) {
357 nc_start[
k] = start[
k];
359 nc_imap[
k] = imap[
k];
366 stat = nc_get_varm_double(
m_file_id, varid, nc_start.data(), nc_count.data(),
367 nc_stride.data(), nc_imap.data(), processor_0_buffer.data());
369 stat = nc_get_vara_double(
m_file_id, varid, nc_start.data(), nc_count.data(),
370 processor_0_buffer.data());
375 MPI_Send(processor_0_buffer.data(), (
int)local_chunk_size, MPI_DOUBLE, r, data_tag,
m_com);
377 for (
unsigned int k = 0;
k < local_chunk_size; ++
k) {
378 ip[
k] = processor_0_buffer[
k];
384 MPI_Send(start.data(), ndims, MPI_UNSIGNED, 0, start_tag,
m_com);
385 MPI_Send(
count.data(), ndims, MPI_UNSIGNED, 0, count_tag,
m_com);
386 MPI_Send(imap.data(), ndims, MPI_UNSIGNED, 0, imap_tag,
m_com);
387 MPI_Send(&local_chunk_size, 1, MPI_UNSIGNED, 0, chunk_size_tag,
m_com);
389 MPI_Recv(ip, (
int)local_chunk_size, MPI_DOUBLE, 0, data_tag,
m_com, &mpi_stat);
394 const std::vector<unsigned int> &start_input,
395 const std::vector<unsigned int> &count_input,
396 const double *op)
const {
398 std::vector<unsigned int> start = start_input;
399 std::vector<unsigned int>
count = count_input;
400 const int start_tag = 1, count_tag = 2, data_tag = 3, chunk_size_tag = 4;
401 int stat = NC_NOERR, com_size = 0, ndims =
static_cast<int>(start.size());
403 unsigned int local_chunk_size = 1, processor_0_chunk_size = 0;
406 MPI_Comm_size(
m_com, &com_size);
409 for (
int k = 0;
k < ndims; ++
k) {
410 local_chunk_size *=
count[
k];
415 MPI_Reduce(&local_chunk_size, &processor_0_chunk_size, 1, MPI_UNSIGNED, MPI_MAX, 0,
m_com);
419 std::vector<double> processor_0_buffer;
420 processor_0_buffer.resize(processor_0_chunk_size);
425 std::vector<size_t> nc_start(ndims), nc_count(ndims);
426 std::vector<ptrdiff_t> nc_stride(ndims);
429 stat = nc_inq_varid(
m_file_id, variable_name.c_str(), &varid);
432 for (
int r = 0; r < com_size; ++r) {
437 MPI_Recv(start.data(), ndims, MPI_UNSIGNED, r, start_tag,
m_com, &mpi_stat);
438 MPI_Recv(
count.data(), ndims, MPI_UNSIGNED, r, count_tag,
m_com, &mpi_stat);
439 MPI_Recv(&local_chunk_size, 1, MPI_UNSIGNED, r, chunk_size_tag,
m_com, &mpi_stat);
441 MPI_Recv(processor_0_buffer.data(), local_chunk_size, MPI_DOUBLE, r, data_tag,
m_com,
444 for (
unsigned int k = 0;
k < local_chunk_size; ++
k) {
445 processor_0_buffer[
k] = op[
k];
451 for (
int k = 0;
k < ndims; ++
k) {
452 nc_start[
k] = start[
k];
459 stat = nc_put_vara_double(
m_file_id, varid, nc_start.data(), nc_count.data(),
460 processor_0_buffer.data());
464 MPI_Send(start.data(), ndims, MPI_UNSIGNED, 0, start_tag,
m_com);
465 MPI_Send(
count.data(), ndims, MPI_UNSIGNED, 0, count_tag,
m_com);
466 MPI_Send(&local_chunk_size, 1, MPI_UNSIGNED, 0, chunk_size_tag,
m_com);
468 MPI_Send(
const_cast<double *
>(op), (
int)local_chunk_size, MPI_DOUBLE, 0, data_tag,
m_com);
481 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
484 MPI_Bcast(&result, 1, MPI_INT, 0,
m_com);
489 std::vector<std::string> &result)
const {
490 int stat, ndims, varid = -1;
491 std::vector<int> dimids;
494 stat = nc_inq_varid(
m_file_id, variable_name.c_str(), &varid);
496 if (stat == NC_NOERR) {
497 stat = nc_inq_varndims(
m_file_id, varid, &ndims);
501 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
504 MPI_Bcast(&ndims, 1, MPI_INT, 0,
m_com);
511 result.resize(ndims);
512 dimids.resize(ndims);
515 stat = nc_inq_vardimid(
m_file_id, varid, dimids.data());
518 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
523 for (
int k = 0;
k < ndims; ++
k) {
524 std::vector<char> name(NC_MAX_NAME + 1, 0);
527 stat = nc_inq_dimname(
m_file_id, dimids[
k], name.data());
530 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
534 MPI_Bcast(name.data(), name.size(), MPI_CHAR, 0,
m_com);
536 result[
k] = name.data();
550 if (varid >= NC_GLOBAL) {
551 stat = nc_inq_varnatts(
m_file_id, varid, &result);
558 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
561 MPI_Bcast(&result, 1, MPI_INT, 0,
m_com);
569 stat = nc_inq_varid(
m_file_id, variable_name.c_str(), &flag);
571 flag = (stat == NC_NOERR) ? 1 : 0;
574 MPI_Bcast(&flag, 1, MPI_INT, 0,
m_com);
576 exists = (flag == 1);
581 std::vector<char> varname(NC_MAX_NAME + 1, 0);
584 stat = nc_inq_varname(
m_file_id, j, varname.data());
589 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
590 MPI_Bcast(varname.data(), NC_MAX_NAME, MPI_CHAR, 0,
m_com);
594 result = varname.data();
602 std::vector<double> &result)
const {
603 int stat = NC_NOERR, len = 0;
611 if (varid >= NC_GLOBAL) {
612 stat = nc_inq_attlen(
m_file_id, varid, att_name.c_str(), &attlen);
617 if (stat == NC_NOERR) {
618 len =
static_cast<int>(attlen);
623 MPI_Bcast(&len, 1, MPI_INT, 0,
m_com);
634 stat = nc_get_att_double(
m_file_id, varid, att_name.c_str(), result.data());
636 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
641 MPI_Bcast(result.data(), len, MPI_DOUBLE, 0,
m_com);
645 static int get_att_text(
int ncid,
int varid,
const std::string &att_name, std::string &result) {
649 stat = nc_inq_attlen(ncid, varid, att_name.c_str(), &attlen);
650 if (stat != NC_NOERR) {
655 std::vector<char> buffer(attlen + 1, 0);
656 stat = nc_get_att_text(ncid, varid, att_name.c_str(), buffer.data());
657 if (stat == NC_NOERR) {
658 result = buffer.data();
668 static int get_att_string(
int ncid,
int varid,
const std::string &att_name, std::string &result) {
672 stat = nc_inq_attlen(ncid, varid, att_name.c_str(), &attlen);
673 if (stat != NC_NOERR) {
678 std::vector<char *> buffer(attlen + 1, 0);
679 stat = nc_get_att_string(ncid, varid, att_name.c_str(), buffer.data());
680 if (stat == NC_NOERR) {
681 std::vector<std::string> strings(attlen);
682 for (
size_t k = 0;
k < attlen; ++
k) {
683 strings[
k] = buffer[
k];
685 result =
join(strings,
",");
689 stat = nc_free_string(attlen, buffer.data());
700 std::string &result)
const {
708 if (varid >= NC_GLOBAL) {
709 nc_type nctype = NC_NAT;
710 stat = nc_inq_atttype(
m_file_id, varid, att_name.c_str(), &nctype);
712 if (stat == NC_NOERR) {
724 }
else if (stat == NC_ENOTATT) {
732 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
735 unsigned int len = result.size();
736 MPI_Bcast(&len, 1, MPI_UNSIGNED, 0,
m_com);
739 MPI_Bcast(&result[0], (
int)len, MPI_CHAR, 0,
m_com);
748 io::Type nctype,
const std::vector<double> &data)
const {
754 if (varid >= NC_GLOBAL) {
756 data.size(), data.data());
763 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
774 const std::string &value)
const {
780 if (varid >= NC_GLOBAL) {
781 stat = nc_put_att_text(
m_file_id, varid, att_name.c_str(), value.size(), value.c_str());
788 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
798 std::string &result)
const {
800 std::vector<char> name(NC_MAX_NAME + 1, 0);
805 if (varid >= NC_GLOBAL) {
806 stat = nc_inq_attname(
m_file_id, varid,
n, name.data());
813 MPI_Bcast(name.data(), NC_MAX_NAME, MPI_CHAR, 0,
m_com);
814 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
818 result = name.data();
832 if (varid >= NC_GLOBAL) {
834 nc_type nctype = NC_NAT;
835 stat = nc_inq_atttype(
m_file_id, varid, att_name.c_str(), &nctype);
836 if (stat == NC_ENOTATT) {
840 tmp =
static_cast<int>(nctype);
847 MPI_Bcast(&tmp, 1, MPI_INT, 0,
m_com);
849 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
861 stat = nc_set_fill(
m_file_id, fillmode, &old_modep);
865 MPI_Bcast(&old_modep, 1, MPI_INT, 0,
m_com);
866 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
875 int stat = nc_inq_format(
m_file_id, &format);
879 MPI_Bcast(&format, 1, MPI_INT, 0,
m_com);
882 case NC_FORMAT_CLASSIC:
883 case NC_FORMAT_64BIT_OFFSET:
885 case NC_FORMAT_64BIT_DATA:
887 case NC_FORMAT_NETCDF4:
888 case NC_FORMAT_NETCDF4_CLASSIC:
900 if (varid >= NC_GLOBAL) {
901 stat = nc_del_att(
m_file_id, varid, att_name.c_str());
906 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
918 if (variable_name ==
"PISM_GLOBAL") {
924 int stat = nc_inq_varid(
m_file_id, variable_name.c_str(), &varid);
926 if (stat == NC_NOERR) {
The PISM wrapper for a subset of the NetCDF C API.
void get_att_text_impl(const std::string &variable_name, const std::string &att_name, std::string &result) const
Gets a text attribute.
virtual void create_impl(const std::string &filename)
Create a NetCDF file.
void def_dim_impl(const std::string &name, size_t length) const
Define a dimension.
void inq_varname_impl(unsigned int j, std::string &result) const
void put_vara_double_impl(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const double *op) const
void set_fill_impl(int fillmode, int &old_modep) const
Sets the fill mode.
std::string get_format() const
void enddef_impl() const
Exit define mode.
void get_vara_double_impl(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, double *ip) const
void inq_vardimid_impl(const std::string &variable_name, std::vector< std::string > &result) const
Get dimensions a variable depends on.
void put_att_text_impl(const std::string &variable_name, const std::string &att_name, const std::string &value) const
Writes a text attribute.
void get_att_double_impl(const std::string &variable_name, const std::string &att_name, std::vector< double > &result) const
Gets a double attribute.
void get_varm_double_impl(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 put_att_double_impl(const std::string &variable_name, const std::string &att_name, io::Type xtype, const std::vector< double > &data) const
Writes a double attribute.
void open_impl(const std::string &filename, io::Mode mode)
void inq_varnatts_impl(const std::string &variable_name, int &result) const
Get the number of attributes of a variable.
void inq_varid_impl(const std::string &variable_name, bool &exists) const
Finds a variable and sets the "exists" flag.
void inq_attname_impl(const std::string &variable_name, unsigned int n, std::string &result) const
Gets the name of a numbered attribute.
virtual void def_var_impl(const std::string &name, io::Type nctype, const std::vector< std::string > &dims) const
Define a variable.
virtual void set_compression_level_impl(int level) const
void close_impl()
Close a NetCDF file.
void del_att_impl(const std::string &variable_name, const std::string &att_name) const
void inq_nvars_impl(int &result) const
Get the number of variables.
void get_var_double(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, bool transposed) const
Get variable data.
void inq_dimlen_impl(const std::string &dimension_name, unsigned int &result) const
Get a dimension length.
void redef_impl() const
Enter define mode.
void inq_dimid_impl(const std::string &dimension_name, bool &exists) const
int get_varid(const std::string &variable_name) const
void inq_unlimdim_impl(std::string &result) const
Get an unlimited dimension.
void inq_atttype_impl(const std::string &variable_name, const std::string &att_name, io::Type &result) const
Gets the type of an attribute.
#define PISM_ERROR_LOCATION
@ PISM_READONLY
open an existing file for reading only
static void check(const ErrorLocation &where, int return_code)
Prints an error message; for debugging.
static void check_and_abort(MPI_Comm com, const ErrorLocation &where, int return_code)
call MPI_Abort() if a NetCDF call failed
static void get_att_string(int ncid, int varid, const std::string &att_name, std::string &result)
static void get_att_text(int ncid, int varid, const std::string &att_name, std::string &result)
std::string join(const std::vector< std::string > &strings, const std::string &separator)
Concatenate strings, inserting separator between elements.
static pism::io::Type nc_type_to_pism_type(int input)
static nc_type pism_type_to_nc_type(pism::io::Type input)