21#include "pism/util/io/NC_Serial.hh"
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,
double *op)
const {
289 const std::vector<unsigned int> &start_input,
290 const std::vector<unsigned int> &count_input,
292 std::vector<unsigned int> start = start_input;
293 std::vector<unsigned int>
count = count_input;
295 const int start_tag = 1, count_tag = 2, data_tag = 3, chunk_size_tag = 4;
296 int stat = NC_NOERR, com_size, ndims =
static_cast<int>(start.size());
298 unsigned int local_chunk_size = 1, processor_0_chunk_size = 0;
301 MPI_Comm_size(
m_com, &com_size);
304 for (
int k = 0;
k < ndims; ++
k) {
305 local_chunk_size *=
count[
k];
310 MPI_Reduce(&local_chunk_size, &processor_0_chunk_size, 1, MPI_UNSIGNED, MPI_MAX, 0,
m_com);
314 std::vector<double> processor_0_buffer;
318 processor_0_buffer.resize(processor_0_chunk_size);
323 std::vector<size_t> nc_start(ndims), nc_count(ndims);
326 stat = nc_inq_varid(
m_file_id, variable_name.c_str(), &varid);
329 for (
int r = 0; r < com_size; ++r) {
334 MPI_Recv(start.data(), ndims, MPI_UNSIGNED, r, start_tag,
m_com, &mpi_stat);
335 MPI_Recv(
count.data(), ndims, MPI_UNSIGNED, r, count_tag,
m_com, &mpi_stat);
336 MPI_Recv(&local_chunk_size, 1, MPI_UNSIGNED, r, chunk_size_tag,
m_com, &mpi_stat);
341 for (
int k = 0;
k < ndims; ++
k) {
342 nc_start[
k] = start[
k];
346 stat = nc_get_vara_double(
m_file_id, varid, nc_start.data(), nc_count.data(),
347 processor_0_buffer.data());
351 MPI_Send(processor_0_buffer.data(), (
int)local_chunk_size, MPI_DOUBLE, r, data_tag,
m_com);
353 for (
unsigned int k = 0;
k < local_chunk_size; ++
k) {
354 ip[
k] = processor_0_buffer[
k];
360 MPI_Send(start.data(), ndims, MPI_UNSIGNED, 0, start_tag,
m_com);
361 MPI_Send(
count.data(), ndims, MPI_UNSIGNED, 0, count_tag,
m_com);
362 MPI_Send(&local_chunk_size, 1, MPI_UNSIGNED, 0, chunk_size_tag,
m_com);
364 MPI_Recv(ip, (
int)local_chunk_size, MPI_DOUBLE, 0, data_tag,
m_com, &mpi_stat);
369 const std::vector<unsigned int> &start_input,
370 const std::vector<unsigned int> &count_input,
371 const double *op)
const {
373 std::vector<unsigned int> start = start_input;
374 std::vector<unsigned int>
count = count_input;
375 const int start_tag = 1, count_tag = 2, data_tag = 3;
376 int stat = NC_NOERR, com_size = 0, ndims =
static_cast<int>(start.size());
377 int local_chunk_size = 1, processor_0_chunk_size = 0;
380 MPI_Comm_size(
m_com, &com_size);
383 for (
int k = 0;
k < ndims; ++
k) {
389 MPI_Reduce(&local_chunk_size, &processor_0_chunk_size, 1, MPI_INT, MPI_MAX, 0,
m_com);
393 std::vector<double> processor_0_buffer;
394 processor_0_buffer.resize(processor_0_chunk_size);
398 stat = nc_inq_varid(
m_file_id, variable_name.c_str(), &varid);
401 for (
int r = 0; r < com_size; ++r) {
406 MPI_Recv(start.data(), ndims, MPI_UNSIGNED, r, start_tag,
m_com, MPI_STATUS_IGNORE);
407 MPI_Recv(
count.data(), ndims, MPI_UNSIGNED, r, count_tag,
m_com, MPI_STATUS_IGNORE);
411 MPI_Probe(r, data_tag,
m_com, &mpi_stat);
412 MPI_Get_count(&mpi_stat, MPI_DOUBLE, &local_chunk_size);
414 MPI_Recv(processor_0_buffer.data(), local_chunk_size, MPI_DOUBLE, r, data_tag,
m_com,
417 for (
int k = 0;
k < local_chunk_size; ++
k) {
418 processor_0_buffer[
k] = op[
k];
428 std::vector<size_t> nc_start(ndims), nc_count(ndims);
429 for (
int k = 0;
k < ndims; ++
k) {
430 nc_start[
k] = start[
k];
434 stat = nc_put_vara_double(
m_file_id, varid, nc_start.data(), nc_count.data(),
435 processor_0_buffer.data());
439 MPI_Send(start.data(), ndims, MPI_UNSIGNED, 0, start_tag,
m_com);
440 MPI_Send(
count.data(), ndims, MPI_UNSIGNED, 0, count_tag,
m_com);
442 MPI_Send(
const_cast<double *
>(op), local_chunk_size, MPI_DOUBLE, 0, data_tag,
m_com);
448 const std::vector<unsigned int> &start,
449 const std::vector<unsigned int> &
count,
const char *data)
const {
453 std::vector<size_t> nc_start{};
454 nc_start.reserve(start.size());
455 for (
const auto &s : start) {
456 nc_start.push_back(s);
459 std::vector<size_t> nc_count{};
460 nc_count.reserve(
count.size());
461 for (
const auto &c :
count) {
462 nc_count.push_back(c);
465 stat = nc_put_vara_text(
m_file_id,
get_varid(variable_name), nc_start.data(), nc_count.data(),
470 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
484 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
487 MPI_Bcast(&result, 1, MPI_INT, 0,
m_com);
492 std::vector<std::string> &result)
const {
493 int stat, ndims, varid = -1;
494 std::vector<int> dimids;
497 stat = nc_inq_varid(
m_file_id, variable_name.c_str(), &varid);
499 if (stat == NC_NOERR) {
500 stat = nc_inq_varndims(
m_file_id, varid, &ndims);
504 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
507 MPI_Bcast(&ndims, 1, MPI_INT, 0,
m_com);
514 result.resize(ndims);
515 dimids.resize(ndims);
518 stat = nc_inq_vardimid(
m_file_id, varid, dimids.data());
521 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
526 for (
int k = 0;
k < ndims; ++
k) {
527 std::vector<char> name(NC_MAX_NAME + 1, 0);
530 stat = nc_inq_dimname(
m_file_id, dimids[
k], name.data());
533 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
537 MPI_Bcast(name.data(), name.size(), MPI_CHAR, 0,
m_com);
539 result[
k] = name.data();
553 if (varid >= NC_GLOBAL) {
554 stat = nc_inq_varnatts(
m_file_id, varid, &result);
561 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
564 MPI_Bcast(&result, 1, MPI_INT, 0,
m_com);
572 stat = nc_inq_varid(
m_file_id, variable_name.c_str(), &flag);
574 flag = (stat == NC_NOERR) ? 1 : 0;
577 MPI_Bcast(&flag, 1, MPI_INT, 0,
m_com);
579 exists = (flag == 1);
584 std::vector<char> varname(NC_MAX_NAME + 1, 0);
587 stat = nc_inq_varname(
m_file_id, j, varname.data());
592 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
593 MPI_Bcast(varname.data(), NC_MAX_NAME, MPI_CHAR, 0,
m_com);
597 result = varname.data();
605 std::vector<double> &result)
const {
606 int stat = NC_NOERR, len = 0;
614 if (varid >= NC_GLOBAL) {
615 stat = nc_inq_attlen(
m_file_id, varid, att_name.c_str(), &attlen);
620 if (stat == NC_NOERR) {
621 len =
static_cast<int>(attlen);
626 MPI_Bcast(&len, 1, MPI_INT, 0,
m_com);
637 stat = nc_get_att_double(
m_file_id, varid, att_name.c_str(), result.data());
639 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
644 MPI_Bcast(result.data(), len, MPI_DOUBLE, 0,
m_com);
648static int get_att_text(
int ncid,
int varid,
const std::string &att_name, std::string &result) {
652 stat = nc_inq_attlen(ncid, varid, att_name.c_str(), &attlen);
653 if (stat != NC_NOERR) {
658 std::vector<char> buffer(attlen + 1, 0);
659 stat = nc_get_att_text(ncid, varid, att_name.c_str(), buffer.data());
660 if (stat == NC_NOERR) {
661 result = buffer.data();
671static int get_att_string(
int ncid,
int varid,
const std::string &att_name, std::string &result) {
675 stat = nc_inq_attlen(ncid, varid, att_name.c_str(), &attlen);
676 if (stat != NC_NOERR) {
681 std::vector<char *> buffer(attlen + 1, 0);
682 stat = nc_get_att_string(ncid, varid, att_name.c_str(), buffer.data());
683 if (stat == NC_NOERR) {
684 std::vector<std::string> strings(attlen);
685 for (
size_t k = 0;
k < attlen; ++
k) {
686 strings[
k] = buffer[
k];
688 result =
join(strings,
",");
692 stat = nc_free_string(attlen, buffer.data());
703 std::string &result)
const {
711 if (varid >= NC_GLOBAL) {
712 nc_type nctype = NC_NAT;
713 stat = nc_inq_atttype(
m_file_id, varid, att_name.c_str(), &nctype);
715 if (stat == NC_NOERR) {
727 }
else if (stat == NC_ENOTATT) {
735 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
738 unsigned int len = result.size();
739 MPI_Bcast(&len, 1, MPI_UNSIGNED, 0,
m_com);
742 MPI_Bcast(&result[0], (
int)len, MPI_CHAR, 0,
m_com);
751 io::Type nctype,
const std::vector<double> &data)
const {
757 if (varid >= NC_GLOBAL) {
759 data.size(), data.data());
766 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
777 const std::string &value)
const {
783 if (varid >= NC_GLOBAL) {
784 stat = nc_put_att_text(
m_file_id, varid, att_name.c_str(), value.size(), value.c_str());
791 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
801 std::string &result)
const {
803 std::vector<char> name(NC_MAX_NAME + 1, 0);
808 if (varid >= NC_GLOBAL) {
809 stat = nc_inq_attname(
m_file_id, varid,
n, name.data());
816 MPI_Bcast(name.data(), NC_MAX_NAME, MPI_CHAR, 0,
m_com);
817 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
821 result = name.data();
835 if (varid >= NC_GLOBAL) {
837 nc_type nctype = NC_NAT;
838 stat = nc_inq_atttype(
m_file_id, varid, att_name.c_str(), &nctype);
839 if (stat == NC_ENOTATT) {
843 tmp =
static_cast<int>(nctype);
850 MPI_Bcast(&tmp, 1, MPI_INT, 0,
m_com);
852 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
864 stat = nc_set_fill(
m_file_id, fillmode, &old_modep);
868 MPI_Bcast(&old_modep, 1, MPI_INT, 0,
m_com);
869 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
878 int stat = nc_inq_format(
m_file_id, &format);
882 MPI_Bcast(&format, 1, MPI_INT, 0,
m_com);
885 case NC_FORMAT_CLASSIC:
886 case NC_FORMAT_64BIT_OFFSET:
888 case NC_FORMAT_64BIT_DATA:
890 case NC_FORMAT_NETCDF4:
891 case NC_FORMAT_NETCDF4_CLASSIC:
903 if (varid >= NC_GLOBAL) {
904 stat = nc_del_att(
m_file_id, varid, att_name.c_str());
909 MPI_Bcast(&stat, 1, MPI_INT, 0,
m_com);
921 if (variable_name ==
"PISM_GLOBAL") {
927 int stat = nc_inq_varid(
m_file_id, variable_name.c_str(), &varid);
929 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 put_vara_text_impl(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const char *data) const
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 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 get_var_double(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, double *ip) const
Get variable data.
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 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)