PnetCDF(3f)
PnetCDF(3f) β LIBRARY FUNCTIONS π
okay bestie, this is the PnetCDF manual for Fortran, and it's giving "parallel netCDF but make it MPI". Let's go. β¨
β¨ NAME β¨
PnetCDF β Parallel library for accessing files in Network Common Data Form (CDF, CDF-2 and CDF-5 formats).
π« SYNOPSIS π«
include "pnetcdf.inc"
π₯οΈ Most Systems
mpif77 ... -lpnetcdf
π CRAY PVP Systems
f90 -dp -i64 ... -lnetcdf
Complete documentation for the PnetCDF libraries can be found at the PnetCDF website: http://cucis.ece.northwestern.edu/projects/PnetCDF/.
π¦ LIBRARY VERSION π¦
This document describes PnetCDF APIs for the FORTRAN programming language.
character*80 nfmpi_inq_libvers(void)
(Corresponds to nf_inq_libvers() in netCDF)
Returns a string identifying the version of the PnetCDF library, and when it was built, like: "1.15.0 of 2026-07-01".
The RCS ident(1) command will find a string like "$Id: @(#) PnetCDF library version 1.15.0 of 2026-07-01 $" in the library. The SCCS what(1) command will find a string like "PnetCDF library version 1.15.0 of 2026-07-01".
π₯ RETURN VALUES π₯
All PnetCDF functions (except nfmpi_inq_libvers() and nfmpi_strerror()) return an integer status.
If this returned status value is not equal to NF_NOERR (zero), it indicates that an error occurred. The possible status values are defined in pnetcdf.inc.
character*80 nfmpi_strerror(integer status)
(Corresponds to nf_strerror() in netCDF)
Returns a string textual translation of the status value, like "Attribute or variable name contains illegal characters" or "No such file or directory".
π FILE OPERATIONS π
π nfmpi_create π
integer function nfmpi_create(integer comm, character*(*) path, integer cmode, integer info, integer ncid)
(Corresponds to nf_create() in netCDF)
Creates a new netCDF dataset at path collectively by a group of MPI processes specified by comm, returning a netCDF ID in ncid. The argument cmode may include the bitwise-or of the following flags: NF_NOCLOBBER to protect existing datasets (default is NF_CLOBBER, silently blows them away), NF_64BIT_OFFSET to create a file in the 64-bit offset format (CDF-2), as opposed to classic format, the default, or NF_64BIT_DATA to create a file in the 64-bit data format (CDF-5). Use either NF_64BIT_OFFSET or NF_64BIT_DATA. The 64-bit offset format allows the creation of very large files with far fewer restrictions than netCDF classic format, but can only be read by the netCDF library version 3.6 or greater. Users are cautioned that files that use the 64-bit offset format will not be recognized by netCDF applications linked to an earlier version of the netCDF library than 3.6. Applications linked to version 3.6 or later will be able to transparently access either the classic format or 64-bit offset format. The 64-bit data format allows the creation of very large array variables. CDF-5 files currently will not be recognized by netCDF 3 or 4 library.
The argument cmode must be consistent among all MPI processes that collectively create the file. The argument info is an MPI info object. Users can use it to supply the file access hints further performance improvement. The hints include existing MPI-IO hints as well as hints defined and used in PnetCDF.
When a netCDF dataset is created, it is opened in NF_WRITE mode. When this function returns, the new netCDF dataset is in define mode.
π nfmpi_open π
integer function nfmpi_open(integer comm, character*(*) path, integer mode, integer info, integer ncid)
(Corresponds to nf_open() in netCDF)
Opens an existing netCDF dataset at path collectively by a group of MPI processes specified by comm, returning a netCDF ID in ncid. The type of access is described by the mode parameter, which may include the bitwise-or of the following flags: NF_WRITE for read-write access (default read-only).
The argument mode must be consistent among all MPI processes that collectively open the file. The argument info is an MPI info object. Users can use it to supply the file access hints further performance improvement. The hints include existing MPI-IO hints as well as hints defined and used in PnetCDF.
π nfmpi_redef π
integer function nfmpi_redef(integer ncid)
(Corresponds to nf_redef() in netCDF)
Puts an open netCDF dataset into define mode, so dimensions, variables, and attributes can be added or renamed and attributes can be deleted.
β
nfmpi_enddef β
integer function nfmpi_enddef(integer ncid)
(Corresponds to nf_enddef() in netCDF)
Takes an open netCDF dataset out of define mode. The changes made to the netCDF dataset while it was in define mode are checked and committed to disk if no problems occurred. After a successful call, variable data can be read or written to the dataset.
πΎ nfmpi_sync πΎ
integer function nfmpi_sync(integer ncid)
(Corresponds to nf_sync() in netCDF)
Data written by PnetCDF APIs may be cached by local file system on each compute node. This API flushes cached data by calling MPI_File_sync.
π nfmpi_abort π
integer function nfmpi_abort(integer ncid)
(Corresponds to nf_abort() in netCDF)
You don't need to call this function. This function is called automatically by nfmpi_close() if the netCDF was in define mode and something goes wrong with the commit. If the netCDF dataset isn't in define mode, then this function is equivalent to nfmpi_close(). If it is called after nfmpi_redef(), but before nfmpi_enddef(), the new definitions are not committed and the dataset is closed. If it is called after nfmpi_create() but before nfmpi_enddef(), the dataset disappears.
π nfmpi_close π
integer function nfmpi_close(integer ncid)
(Corresponds to nf_close() in netCDF)
Closes an open netCDF dataset. If the dataset is in define mode, nfmpi_enddef() will be called before closing. After a dataset is closed, its ID may be reassigned to another dataset.
π Inq squad: nfmpi_inq, nfmpi_inq_ndims, nfmpi_inq_nvars, nfmpi_inq_natts, nfmpi_inq_unlimdim, nfmpi_inq_format π
integer function nfmpi_inq(integer ncid, integer ndims, integer nvars, integer natts, integer unlimdimid)
(Corresponds to nf_inq() in netCDF)
integer function nfmpi_inq_ndims(integer ncid, integer ndims)
(Corresponds to nf_inq_ndims() in netCDF)
integer function nfmpi_inq_nvars(integer ncid, integer nvars)
(Corresponds to nf_inq_nvars() in netCDF)
integer function nfmpi_inq_natts(integer ncid, integer natts)
(Corresponds to nf_inq_natts() in netCDF)
integer function nfmpi_inq_unlimdim(integer ncid, integer unlimdimid)
(Corresponds to nf_inq_unlimdim() in netCDF)
integer function nfmpi_inq_format(integer ncid, integer formatn)
(Corresponds to nf_inq_format() in netCDF)
Use these functions to find out what is in a netCDF dataset. Upon successful return, ndims will contain the number of dimensions defined for this netCDF dataset, nvars will contain the number of variables, natts will contain the number of attributes, and unlimdimid will contain the dimension ID of the unlimited dimension if one exists, or 0 otherwise. formatn will contain the version number of the dataset format, one of NF_FORMAT_CLASSIC, NF_FORMAT_64BIT, or NF_FORMAT_64BIT_DATA.
π§± nfmpi_def_dim π§±
integer function nfmpi_def_dim(integer ncid, character*(*) name, integer(kind=MPI_OFFSET) len, integer dimid)
(Corresponds to nf_def_dim() in netCDF)
Adds a new dimension to an open netCDF dataset, which must be in define mode. name is the dimension name. dimid will contain the dimension ID of the newly created dimension.
π DIMENSIONS π
π·οΈ nfmpi_inq_dimid π·οΈ
integer function nfmpi_inq_dimid(integer ncid, character*(*) name, integer dimid)
(Corresponds to nf_inq_dimid() in netCDF)
Given a dimension name, returns the ID of a netCDF dimension in dimid.
π nfmpi_inq_dim π
integer function nfmpi_inq_dim(integer ncid, integer dimid, character*(*) name, integer(kind=MPI_OFFSET) len)
(Corresponds to nf_inq_dim() in netCDF)
π·οΈ nfmpi_inq_dimname π·οΈ
integer function nfmpi_inq_dimname(integer ncid, integer dimid, character*(*) name)
(Corresponds to nf_inq_dimname() in netCDF)
π nfmpi_inq_dimlen π
integer function nfmpi_inq_dimlen(integer ncid, integer dimid, integer(kind=MPI_OFFSET) len)
(Corresponds to nf_inq_dimlen() in netCDF)
Use these functions to find out about a dimension.
name should be big enough (NF_MAX_NAME) to hold the dimension name as the name will be copied into your storage. The length return parameter, len will contain the size of the dimension. For the unlimited dimension, the returned length is the current maximum value used for writing into any of the variables which use the dimension.
βοΈ nfmpi_rename_dim βοΈ
integer function nfmpi_rename_dim(integer ncid, integer dimid, character*(*) name)
(Corresponds to nf_rename_dim() in netCDF)
Renames an existing dimension in an open netCDF dataset. If the new name is longer than the old name, the netCDF dataset must be in define mode. You cannot rename a dimension to have the same name as another dimension.
β¨ VARIABLES β¨
okay bestie, this section is literally the whole point of a netCDF file β variables are the actual data containers, and you're gonna be obsessed. π
nfmpi_def_varβ the one that makes a brand new variable happen β¨
integer function nfmpi_def_var(integer ncid, character*(*) name, integer
xtype, integer ndims, integer dimids(1), integer varid)
(Corresponds to nf_def_var() in netCDF)
Adds a new variable to a netCDF dataset. Heads up bestie β the netCDF must be in define mode or this is not happening. varid gets set to the netCDF variable ID. ndims is the number of dimensions for the variable, name is the name of the netCDF variable, and xtype is the external, netCDF type of the variable β it should be one of NF_BYTE NF_CHAR, NF_SHORT, NF_INT, NF_FLOAT, or NF_DOUBLE for CDF-1 and CDF-2 file formats. CDF-5 defines additional external types: NF_UBYTE, NF_USHORT, NF_UINT, NF_INT64, and NF_UINT64. The dimids argument is a vector of ndims dimension IDs corresponding to the variable dimensions.
nfmpi_inq_varidβ name in, ID out π
integer function nfmpi_inq_varid(integer ncid, character*(*) name, inteβ
ger varid)
(Corresponds to nf_inq_varid() in netCDF)
Returns the ID of a netCDF variable in varid given its name.
nfmpi_inq_varβ the full gossip dump on a variable π
integer function nfmpi_inq_var(integer ncid, integer varid, characβ
ter*(*) name, integer xtype, integer ndims, integer dimids(1),
integer natts)
(Corresponds to nf_inq_var() in netCDF)
nfmpi_inq_varnameβ just the name, nothing more πΈ
integer function nfmpi_inq_varname(integer ncid, integer varid, characβ
ter*(*) name)
(Corresponds to nf_inq_varname() in netCDF)
nfmpi_inq_vartypeβ what type is this queen tho π
integer function nfmpi_inq_vartype(integer ncid, integer varid, integer
xtype)
(Corresponds to nf_inq_vartype() in netCDF)
nfmpi_inq_varndimsβ how many dims she's serving β¨
integer function nfmpi_inq_varndims(integer ncid, integer varid, integer
ndims)
(Corresponds to nf_inq_varndims() in netCDF)
nfmpi_inq_vardimidβ the dim IDs, in order π
integer function nfmpi_inq_vardimid(integer ncid, integer varid, integer
dimids(1))
(Corresponds to nf_inq_vardimid() in netCDF)
nfmpi_inq_varnattsβ counting attributes, we love a tally π₯
integer function nfmpi_inq_varnatts(integer ncid, integer varid, integer
natts)
(Corresponds to nf_inq_varnatts() in netCDF)
So the whole lil' nfmpi_inq_var crew β nfmpi_inq_var, nfmpi_inq_varname, nfmpi_inq_vartype, nfmpi_inq_varndims, nfmpi_inq_vardimid, and nfmpi_inq_varnatts β Returns information about a netCDF variable, given its ID. π«Ά
nfmpi_rename_varβ glow-up era, new name who dis π
integer function nfmpi_rename_var(integer ncid, integer varid, characβ
ter*(*) name)
(Corresponds to nf_rename_var() in netCDF)
Changes the name of a netCDF variable. Real talk: if the new name is longer than the old name, the netCDF must be in define mode. And no, you literally cannot rename a variable to have the name of any existing variable. It's giving "find a different name bestie" π
π₯ WRITING AND READING WHOLE VARIABLES π₯
This is where you actually move the data, bestie. Whole variables, all the values, all at once. Iconic. β¨
The put squad (writing) π
nfmpi_put_var_text
integer function nfmpi_put_var_text(integer ncid, integer varid, characβ
ter*(*) out)
(Corresponds to nf_put_var_text() in netCDF)
nfmpi_put_var_int1
integer function nfmpi_put_var_int1(integer ncid, integer varid, inteβ
ger*1 out(1))
(Corresponds to nf_put_var_int1() in netCDF)
nfmpi_put_var_int2
integer function nfmpi_put_var_int2(integer ncid, integer varid, inteβ
ger*2 out(1))
(Corresponds to nf_put_var_int2() in netCDF)
nfmpi_put_var_int
integer function nfmpi_put_var_int(integer ncid, integer varid, integer
out(1))
(Corresponds to nf_put_var_int() in netCDF)
nfmpi_put_var_real
integer function nfmpi_put_var_real(integer ncid, integer varid, real
out(1))
(Corresponds to nf_put_var_real() in netCDF)
nfmpi_put_var_double
integer function nfmpi_put_var_double(integer ncid, integer varid, douβ
bleprecision out(1))
(Corresponds to nf_put_var_double() in netCDF)
Writes an entire netCDF variable (i.e. all the values). The netCDF dataset must be open and in data mode. The type of the data is specified in the function name, and it is converted to the external type of the specified variable, if possible, otherwise an NF_ERANGE error is returned.
β οΈ no cap: rounding is not performed during the conversion, and floating point numbers are truncated when converted to integers. So don't come crying when your3.9shows up as3, bestie π
The get squad (reading) π¦
nfmpi_get_var_text
integer function nfmpi_get_var_text(integer ncid, integer varid, characβ
ter*(*) in)
(Corresponds to nf_get_var_text() in netCDF)
nfmpi_get_var_int1
integer function nfmpi_get_var_int1(integer ncid, integer varid, inteβ
ger*1 in(1))
(Corresponds to nf_get_var_int1() in netCDF)
nfmpi_get_var_int2
integer function nfmpi_get_var_int2(integer ncid, integer varid, inteβ
ger*2 in(1))
(Corresponds to nf_get_var_int2() in netCDF)
nfmpi_get_var_int
integer function nfmpi_get_var_int(integer ncid, integer varid, integer
in(1))
(Corresponds to nf_get_var_int() in netCDF)
nfmpi_get_var_real
integer function nfmpi_get_var_real(integer ncid, integer varid, real
in(1))
(Corresponds to nf_get_var_real() in netCDF)
nfmpi_get_var_double
integer function nfmpi_get_var_double(integer ncid, integer varid, douβ
bleprecision in(1))
(Corresponds to nf_get_var_double() in netCDF)
Reads an entire netCDF variable (i.e. all the values). The netCDF dataset must be open and in data mode. The data is converted from the external type of the specified variable, if necessary, to the type specified in the function name. If conversion is not possible, an NF_ERANGE error is returned. π
πΈ WRITING AND READING ONE DATUM πΈ
Sometimes you don't need the whole variable β you just need that one lil' value, and bestie that's exactly what these are for. So precise. So main character. π
Put a single value β¨
nfmpi_put_var1_text
integer function nfmpi_put_var1_text(integer ncid, integer varid, inteβ
ger(kind=MPI_OFFSET) index(1), character*1 *out)
(Corresponds to nf_put_var1_text() in netCDF)
nfmpi_put_var1_int1
integer function nfmpi_put_var1_int1(integer ncid, integer varid, inteβ
ger(kind=MPI_OFFSET) index(1), integer*1 *out)
(Corresponds to nf_put_var1_int1() in netCDF)
nfmpi_put_var1_int2
integer function nfmpi_put_var1_int2(integer ncid, integer varid, inteβ
ger(kind=MPI_OFFSET) index(1), integer*2 *out)
(Corresponds to nf_put_var1_int2() in netCDF)
nfmpi_put_var1_int
integer function nfmpi_put_var1_int(integer ncid, integer varid, inteβ
ger(kind=MPI_OFFSET) index(1), integer *out)
(Corresponds to nf_put_var1_int() in netCDF)
nfmpi_put_var1_real
integer function nfmpi_put_var1_real(integer ncid, integer varid, inteβ
ger(kind=MPI_OFFSET) index(1), real *out)
(Corresponds to nf_put_var1_real() in netCDF)
nfmpi_put_var1_double
integer function nfmpi_put_var1_double(integer ncid, integer varid, inβ
teger(kind=MPI_OFFSET) index(1), doubleprecision *out)
(Corresponds to nf_put_var1_double() in netCDF)
Puts a single data value into a variable at the position index of an open netCDF dataset that is in data mode. The type of the data is specified in the function name, and it is converted to the external type of the specified variable, if possible, otherwise an NF_ERANGE error is returned. π
Get a single value π
nfmpi_get_var1_text
integer function nfmpi_get_var1_text(integer ncid, integer varid, inteβ
ger(kind=MPI_OFFSET) index(1), character*1 in)
(Corresponds to nf_get_var1_text() in netCDF)
nfmpi_get_var1_int1
integer function nfmpi_get_var1_int1(integer ncid, integer varid, inteβ
ger(kind=MPI_OFFSET) index(1), integer*1 in)
(Corresponds to nf_get_var1_int1() in netCDF)
nfmpi_get_var1_int2
integer function nfmpi_get_var1_int2(integer ncid, integer varid, inteβ
ger(kind=MPI_OFFSET) index(1), integer*2 in)
(Corresponds to nf_get_var1_int2() in netCDF)
nfmpi_get_var1_int
integer function nfmpi_get_var1_int(integer ncid, integer varid, inteβ
ger(kind=MPI_OFFSET) index(1), integer in)
(Corresponds to nf_get_var1_int() in netCDF)
nfmpi_get_var1_real
integer function nfmpi_get_var1_real(integer ncid, integer varid, inteβ
ger(kind=MPI_OFFSET) index(1), real in)
(Corresponds to nf_get_var1_real() in netCDF)
nfmpi_get_var1_double
integer function nfmpi_get_var1_double(integer ncid, integer varid, inβ
teger(kind=MPI_OFFSET) index(1), doubleprecision in)
(Corresponds to nf_get_var1_double() in netCDF)
Gets a single data value from a variable at the position index of an open netCDF dataset that is in data mode. The data is converted from the external type of the specified variable, if necessary, to the type specified in the function name. If conversion is not possible, an NF_ERANGE error is returned. π«Ά
π«Ά WRITING AND READING AN ARRAY π«Ά
ok bestie so this is the moment where we stop doing one lil datum at a time and start doing the whole section of a variable. like, a whole vibe of data at once. say hi to the put crew first π
integer function nfmpi_put_vara_text(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), character*(*) out)
(Corresponds to nf_put_vara_text() in netCDF)
integer function nfmpi_put_vara_int1(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer*1 out(1))
(Corresponds to nf_put_vara_int1() in netCDF)
integer function nfmpi_put_vara_int2(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer*2 out(1))
(Corresponds to nf_put_vara_int2() in netCDF)
integer function nfmpi_put_vara_int(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer out(1))
(Corresponds to nf_put_vara_int() in netCDF)
integer function nfmpi_put_vara_real(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), real out(1))
(Corresponds to nf_put_vara_real() in netCDF)
integer function nfmpi_put_vara_double(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), doubleprecision out(1))
(Corresponds to nf_put_vara_double() in netCDF)
what do they even do tho π
β they write an array section of values into a netCDF variable of an open netCDF dataset, and that dataset must be in data mode. (yes that matters, go check nfmpi_enddef() if you're in define mode, iykyk). the array section is specified by the start and count vectors, which give the starting index and count of values along each dimension of the specified variable. the type of the data is specified in the function name, and it gets converted to the external type of the specified variable, if possible β otherwise an NF_ERANGE error is returned. no cap. π¨
okay now the get crew, the ones that read it all back for you π
integer function nfmpi_get_vara_text(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), character*(*) in)
(Corresponds to nf_get_vara_text() in netCDF)
integer function nfmpi_get_vara_int1(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer*1 in(1))
(Corresponds to nf_get_vara_int1() in netCDF)
integer function nfmpi_get_vara_int2(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer*2 in(1))
(Corresponds to nf_get_vara_int2() in netCDF)
integer function nfmpi_get_vara_int(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer in(1))
(Corresponds to nf_get_vara_int() in netCDF)
integer function nfmpi_get_vara_real(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), real in(1))
(Corresponds to nf_get_vara_real() in netCDF)
integer function nfmpi_get_vara_double(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), doubleprecision in(1))
(Corresponds to nf_get_vara_double() in netCDF)
and these ones read an array section of values from a netCDF variable of an open netCDF dataset, which again must be in data mode β. the array section is specified by the start and count vectors, which give the starting index and count of values along each dimension of the specified variable. the data is converted from the external type of the specified variable, if necessary, to the type specified in the function name. if conversion is not possible, an NF_ERANGE error is returned. so likeβ¦ if it can't convert, it's not gonna fake it for you. periodt. π
π¦ WRITING AND READING A SLICED ARRAY π¦
so vara = a solid block. vars = a strided slice, i.e. you get to skip. sampling vibes only, bestie. put side first, as always πΈ
integer function nfmpi_put_vars_text(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), character*(*) out)
(Corresponds to nf_put_vars_text() in netCDF)
integer function nfmpi_put_vars_int1(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer*1 out(1))
(Corresponds to nf_put_vars_int1() in netCDF)
integer function nfmpi_put_vars_int2(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer*2 out(1))
(Corresponds to nf_put_vars_int2() in netCDF)
integer function nfmpi_put_vars_int(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer out(1))
(Corresponds to nf_put_vars_int() in netCDF)
integer function nfmpi_put_vars_real(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), real out(1))
(Corresponds to nf_put_vars_real() in netCDF)
integer function nfmpi_put_vars_double(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), doubleprecision out(1))
(Corresponds to nf_put_vars_double() in netCDF)
these functions are used for strided output, which is like the array section output described above, except that the sampling stride (the interval between accessed values) is specified for each dimension. for an explanation of the sampling stride vector, see COMMON ARGUMENTS DESCRIPTIONS below π (yes, keep scrolling, it's there).
and now the read side, the get-vars girlies π
integer function nfmpi_get_vars_text(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), character*(*) in)
(Corresponds to nf_get_vars_text() in netCDF)
integer function nfmpi_get_vars_int1(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer*1 in(1))
(Corresponds to nf_get_vars_int1() in netCDF)
integer function nfmpi_get_vars_int2(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer*2 in(1))
(Corresponds to nf_get_vars_int2() in netCDF)
integer function nfmpi_get_vars_int(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer in(1))
(Corresponds to nf_get_vars_int() in netCDF)
integer function nfmpi_get_vars_real(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), real in(1))
(Corresponds to nf_get_vars_real() in netCDF)
integer function nfmpi_get_vars_double(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), doubleprecision in(1))
(Corresponds to nf_get_vars_double() in netCDF)
these functions are used for strided input, which is like the array section input described above, except that the sampling stride (the interval between accessed values) is specified for each dimension. for an explanation of the sampling stride vector, see COMMON ARGUMENTS DESCRIPTIONS below π.
fr fr:start,countandstrideare allinteger(kind=MPI_OFFSET), and they're all arrays indexed per dimension. don't come for me, that's just what it is. π«Ά
β¨ WRITING AND READING A MAPPED ARRAY β¨
okay bestie, this is the final boss of the read/write saga π€ this is strided I/O but with a glow-up: you also hand over an index mapping vector that tells the library how your data is actually laid out in memory. mapped output is strided output plus that extra imap magic, periodt. π
The write (output) squad goes like this:
integer function nfmpi_put_varm_text(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer(kind=MPI_OFFSET) imap(1), character*(*) out)
(Corresponds to nf_put_varm_text() in netCDF)
integer function nfmpi_put_varm_int1(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer(kind=MPI_OFFSET) imap(1), integer*1 out(1))
(Corresponds to nf_put_varm_int1() in netCDF)
integer function nfmpi_put_varm_int2(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer(kind=MPI_OFFSET) imap(1), integer*2 out(1))
(Corresponds to nf_put_varm_int2() in netCDF)
integer function nfmpi_put_varm_int(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer(kind=MPI_OFFSET) imap(1), integer out(1))
(Corresponds to nf_put_varm_int() in netCDF)
integer function nfmpi_put_varm_real(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer(kind=MPI_OFFSET) imap(1), real out(1))
(Corresponds to nf_put_varm_real() in netCDF)
integer function nfmpi_put_varm_double(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer(kind=MPI_OFFSET) imap(1), doubleprecision out(1))
(Corresponds to nf_put_varm_double() in netCDF)
These ones are the mapped output girlies π« and no, they're not just strided output with a new outfit β they're literally strided output like the one we talked about above, except there's an extra index mapping vector in the mix that spells out the in-memory arrangement of the data values. Wanna know what that index mapping vector is actually doing? bestie, run don't walk to COMMON ARGUMENTS DESCRIPTIONS below, it's all explained there. π«Ά
And now the read (input) side, because you can't just write into the void forever:
integer function nfmpi_get_varm_text(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer(kind=MPI_OFFSET) imap(1), character*(*) in)
(Corresponds to nf_get_varm_text() in netCDF)
integer function nfmpi_get_varm_int1(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer(kind=MPI_OFFSET) imap(1), integer*1 in(1))
(Corresponds to nf_get_varm_int1() in netCDF)
integer function nfmpi_get_varm_int2(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer(kind=MPI_OFFSET) imap(1), integer*2 in(1))
(Corresponds to nf_get_varm_int2() in netCDF)
integer function nfmpi_get_varm_int(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer(kind=MPI_OFFSET) imap(1), integer in(1))
(Corresponds to nf_get_varm_int() in netCDF)
integer function nfmpi_get_varm_real(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer(kind=MPI_OFFSET) imap(1), real in(1))
(Corresponds to nf_get_varm_real() in netCDF)
integer function nfmpi_get_varm_double(integer ncid, integer varid, integer(kind=MPI_OFFSET) start(1), integer(kind=MPI_OFFSET) count(1), integer(kind=MPI_OFFSET) stride(1), integer(kind=MPI_OFFSET) imap(1), doubleprecision in(1))
(Corresponds to nf_get_varm_double() in netCDF)
These are the mapped input... okay no, mapped input functions π¦ and same deal as the output ones: it's strided input just like above, except there's that extra index mapping vector riding along to specify the in-memory arrangement of the data values. The whole index mapping vector situation is decoded for you in COMMON ARGUMENTS DESCRIPTIONS right down below. iykyk π
β¨ ATTRIBUTES β¨
ok so THIS is where your files and variables get their whole personality π β attributes are the lil metadata besties that ride along with a dataset or a specific variable, and this family of calls is how you write them, read them, copy them, rename them, and straight-up delete them. let's go π
integer function nfmpi_put_att_text(integer ncid, integer varid, character*(*) name, integer xtype, integer(kind=MPI_OFFSET) len, character*(*) out)
(Corresponds to nf_put_att_text() in netCDF)
integer function nfmpi_put_att_int1(integer ncid, integer varid, character*(*) name, integer xtype, integer(kind=MPI_OFFSET) len, integer*1 out(1))
(Corresponds to nf_put_att_int1() in netCDF)
integer function nfmpi_put_att_int2(integer ncid, integer varid, character*(*) name, integer xtype, integer(kind=MPI_OFFSET) len, integer*2 out(1))
(Corresponds to nf_put_att_int2() in netCDF)
integer function nfmpi_put_att_int(integer ncid, integer varid, character*(*) name, integer xtype, integer(kind=MPI_OFFSET) len, integer out(1))
(Corresponds to nf_put_att_int() in netCDF)
integer function nfmpi_put_att_real(integer ncid, integer varid, character*(*) name, integer xtype, integer(kind=MPI_OFFSET) len, real out(1))
(Corresponds to nf_put_att_real() in netCDF)
integer function nfmpi_put_att_double(integer ncid, integer varid, character*(*) name, integer xtype, integer(kind=MPI_OFFSET) len, doubleprecision out(1))
(Corresponds to nf_put_att_double() in netCDF)
integer function nfmpi_put_att(integer ncid, integer varid, character*(*) name, integer xtype, integer(kind=MPI_OFFSET) len, void *ip)
(Corresponds to nf_put_att() in netCDF)
integer function nfmpi_get_att(integer ncid, integer varid, character*(*) name, void * ip)
(Corresponds to nf_get_att() in netCDF)
Here's the tea π« β unlike variables, attributes do NOT get separate functions for defining vs. writing values. One call does both. This whole family of functions either defines a brand new attribute with a value, or changes the value of an existing one. If the attribute is new, or if the space needed to store the attribute value is bigger than before, your netCDF dataset has to be in define mode. (Sorry bestie, that's the rule.)
The len parameter is the number of values from out to transfer. It's usually one β except for nfmpi_put_att_text(), where it'll usually be len_trim(out).
Now for these functions, the type part of the function name tells you the in-memory type of the value, while the xtype argument is the external type used for storing it. Those two live in different worlds, so if a conversion between them isn't possible, you get an NF_ERANGE error π. And when that happens, the value gets represented with the appropriate fill-value for the associated external type.
integer function nfmpi_inq_attname(integer ncid, integer varid, integer attnum, character*(*) name)
(Corresponds to nf_inq_attname() in netCDF)
This one gets the name of an attribute, given its variable ID and attribute number. Honestly so useful for generic applications that need to grab the names of all the attributes hanging off a variable β because every other attribute function accesses attributes by name, not by number. And here's the thing: an attribute's number is lowkey more fickle than its name, since the number can change when other attributes of the same variable get deleted π. Attributes for each variable are numbered from 1 (the first attribute) to nvatts, where nvatts is the number of attributes for the variable, as returned from a call to nfmpi_inq_varnatts().
integer function nfmpi_inq_att(integer ncid, integer varid, character*(*) name, integer xtype, integer(kind=MPI_OFFSET) len)
(Corresponds to nf_inq_att() in netCDF)
integer function nfmpi_inq_attid(integer ncid, integer varid, character*(*) name, integer attnum)
(Corresponds to nf_inq_attid() in netCDF)
integer function nfmpi_inq_atttype(integer ncid, integer varid, character*(*) name, integer xtype)
(Corresponds to nf_inq_atttype() in netCDF)
integer function nfmpi_inq_attlen(integer ncid, integer varid, character*(*) name, integer(kind=MPI_OFFSET) len)
(Corresponds to nf_inq_attlen() in netCDF)
These functions hand you the deets about a netCDF attribute, given its variable ID and name. What you get back is the external type in xtype π¦ and the number of elements in the attribute as len. chef's kiss, all the info.
integer function nfmpi_copy_att(integer ncid, integer varid_in, character*(*) name, integer ncid_out, integer varid_out)
(Corresponds to nf_copy_att() in netCDF)
Copies an attribute from one netCDF dataset to another, and ngl it can ALSO copy an attribute from one variable to another within the same netCDF π. Let's break it down:
ncid_inis the netCDF ID of an input netCDF dataset from which the attribute will be copied.varid_inis the ID of the variable in the input netCDF dataset from which the attribute will be copied, orNF_GLOBALfor a global attribute.nameis the name of the attribute in the input netCDF dataset to be copied.ncid_outis the netCDF ID of the output netCDF dataset to which the attribute will be copied. And yes, it is perfectly permissible for the input and output netCDF ID's to be the same. π«Άvarid_outis the ID of the variable in the output netCDF dataset to which the attribute will be copied, orNF_GLOBALto copy to a global attribute.
The output netCDF dataset should be in define mode if the attribute to be copied doesn't already exist for the target variable, or if it would cause an existing target attribute to grow π± β so yeah, watch out for that.
fr fr, keep an eye on that define-mode requirement, bestie β it's the difference between a slay copy and an error.
integer function nfmpi_rename_att(integer ncid, integer varid, character*(*) name, character*(*) newname)
(Corresponds to nf_rename_att() in netCDF)
Changes the name of an attribute. If the new name is longer than the original name, the netCDF must be in define mode. Also β and this is important β you cannot rename an attribute to have the same name as another attribute of the same variable π«. So no duplicate-name shenanigans, okay?
nameis the original attribute name.newnameis the new name to be assigned to the specified attribute.
And one more time for the people in the back: if the new name is longer than the old name, the netCDF dataset must be in define mode.
integer function nfmpi_del_att(integer ncid, integer varid, character*(*) name)
(Corresponds to nf_del_att() in netCDF)
Deletes an attribute from a netCDF dataset πβ¨. The dataset must be in define mode. That's the whole vibe β goodbye attribute, you had a good run.
integer function nfmpi_get_att_text(integer ncid, integer varid, character*(*) name, character*(*) in)
(Corresponds to nf_get_att_text() in netCDF)
integer function nfmpi_get_att_int1(integer ncid, integer varid, character*(*) name, integer*1 in(1))
(Corresponds to nf_get_att_int1() in netCDF)
integer function nfmpi_get_att_int2(integer ncid, integer varid, character*(*) name, integer*2 in(1))
(Corresponds to nf_get_att_int2() in netCDF)
integer function nfmpi_get_att_int(integer ncid, integer varid, character*(*) name, integer in(1))
(Corresponds to nf_get_att_int() in netCDF)
integer function nfmpi_get_att_real(integer ncid, integer varid, character*(*) name, real in(1))
(Corresponds to nf_get_att_real() in netCDF)
integer function nfmpi_get_att_double(integer ncid, integer varid, character*(*) name, doubleprecision in(1))
(Corresponds to nf_get_att_double() in netCDF)
Gets the value(s) of a netCDF attribute, given its variable ID and name π. It converts from the external type to the type specified in the function name β if possible β otherwise it returns an NF_ERANGE error. Rude, but fair.
β οΈ Heads up bestie: ALL elements of the vector of attribute values get returned, so you have to allocate enough space to hold all of them. Not enough and it's giving chaos. If you don't know how much space to reserve, call nfmpi_inq_attlen() first to find out the length of the attribute. do it, trust π
β¨ COMMON ARGUMENT DESCRIPTIONS β¨
ok so before we get into the actual function list, bestie, we gotta learn the shared vocabulary. these are the arguments that keep showing up over and over in the "FUNCTION DESCRIPTIONS" section, so like... learn them once, slay forever π
integer ncidβ this is the netCDF ID, and it comes straight from a previous, successful call tonfmpi_open()ornfmpi_create(). it's basically your backstage pass πcharacter*(*) nameβ the name of a dimension, variable, or attribute. dimension/variable/attribute names can be any sequence of alphanumeric characters, plus underscore'_', period'.'and hyphen'-', and they have to begin with a letter or an underscore. (but heads up: names starting with an underscore are reserved for system use, so don't touch those π) Case is significant in netCDF names βFooandfooare NOT the same thing, okay?? and a zero-length name is not allowed, periodt.
The maximum allowable number of characters is NF_MAX_NAME.
integer xtypeβ says what the external data type of a netCDF variable or attribute is, and it's one of these:NF_BYTE,NF_CHAR,NF_SHORT,NF_INT,NF_FLOAT, orNF_DOUBLEfor CDF-1 and CDF-2 file formats. In order those mean: 8-bit integers, characters, 16-bit integers, 32-bit integers, 32-bit IEEE floating point numbers, and 64-bit IEEE floating-point numbers. yes they're alphabetical-ish and yes you will memorise them π
CDF-5 defines additional external types: NF_UBYTE, NF_USHORT, NF_UINT, NF_INT64, and NF_UINT64. more types, more iconic β¨
integer dimids(1)β a vector of dimension ID's that defines the shape of a netCDF variable. the size of the vector has to be greater than or equal to the rank (i.e. the number of dimensions) of the variable (ndims). and it shall be ordered by the speed with which a dimension varies:dimids(1)is the dimension ID of the most rapidly varying dimension anddimids(ndims)is the dimension ID of the most slowly varying dimension. the maximum possible number of dimensions for a variable is given by the symbolic constantNF_MAX_VAR_DIMS.integer dimidβ the ID of a netCDF dimension. netCDF dimension ID's are allocated sequentially from the positive integers beginning with 1. so first one's 1, not 0. classic π¦integer ndimsβ either the total number of dimensions in a netCDF dataset, or the rank (i.e. the number of dimensions) of a netCDF variable. the value shall not be negative and shall not be greater than the symbolic constantNF_MAX_VAR_DIMS.integer varidβ the ID of a netCDF variable, or (for the attribute-access functions) the symbolic constantNF_GLOBAL, which is used to reference global attributes. netCDF variable ID's are allocated sequentially from the positive integers beginning with 1. same energy asdimid, we love consistency πinteger nattsβ the number of global attributes in a netCDF dataset for thenfmpi_inquire()function, or the number of attributes associated with a netCDF variable for thenfmpi_varinq()function.integer(kind=MPI_OFFSET) index(1)β specifies the coordinates of the netCDF data value to be accessed. the indices start at 1, so like, for example, the first data value of a two-dimensional variable is(1,1). the size of the vector shall be at least the rank of the associated netCDF variable, and its elements shall correspond, in order, to the variable's dimensions.integer(kind=MPI_OFFSET) start(1)β specifies the starting point for accessing a netCDF variable's data values, in terms of the indicial coordinates of the corner of the array section. indices start at 1, so the first data value of a variable is(1, 1, ..., 1). the size of the vector shall be at least the rank of the associated netCDF variable and its elements shall correspond, in order, to the variable's dimensions.integer(kind=MPI_OFFSET) count(1)β specifies the number of indices selected along each dimension of the array section. so to access a single value, for example, specifycountas(1, 1, ..., 1). note that for strided I/O this argument must be adjusted to be compatible with thestrideandstartarguments, so that the interaction of the three doesn't attempt to access an invalid data co-ordinate β οΈ the elements of thecountvector correspond, in order, to the variable's dimensions.integer(kind=MPI_OFFSET) stride(1)β specifies the sampling interval along each dimension of the netCDF variable. the elements of thestridevector correspond, in order, to the netCDF variable's dimensions (stride(1)gives the sampling interval along the most rapidly varying dimension of the netCDF variable). sampling intervals are specified in type-independent units of elements β a value of1selects consecutive elements of the netCDF variable along the corresponding dimension, a value of2selects every other element, etc. cherry-picking but make it β¨arraysβ¨integer(kind=MPI_OFFSET) imap(1)β specifies the mapping between the dimensions of a netCDF variable and the in-memory structure of the internal data array. the elements of the index mapping vector correspond, in order, to the netCDF variable's dimensions (imap(1)gives the distance between elements of the internal array corresponding to the most rapidly varying dimension of the netCDF variable). distances between elements are specified in type-independent units of elements β the distance between internal elements that occupy adjacent memory locations is1, and not the element's byte-length as in netCDF 2. okay that last bit is important, do not come for me about bytes π«Ά
πΈ VARIABLE PREFILLING πΈ
okay so this is a whole saga, buckle up. Prior to version 1.6.1, PnetCDF does not support data filling. The default fill mode in PnetCDF is NF_NOFILL. This is contrary to the netCDF library, whose default is NF_FILL. When fill mode is enabled, PnetCDF sets the values of all newly-defined variables of finite length (i.e. those that do not have an unlimited, dimension) to the type-dependent fill-value associated with each variable. This is done when nfmpi_enddef() is called. The fill-value for a variable may be changed from the default value by defining the attribute _FillValue for the variable. This attribute must have the same type as the variable and be of length one.
Variables with an unlimited dimension are not prefilled in PnetCDF. This is also contrary to netCDF, which does prefill record variables π In PnetCDF, filling a record variable must be done by calling nfmpi_fill_var_rec(). Note this fills only one record of a variable. one. single. record.
The fill mode for the entire file can be set by nfmpi_set_fill(). Per-variable fill mode setting is also available through nfmpi_def_var_fill(). In PnetCDF, changing fill mode must be done in define mode. In netCDF, it is true only for fixed-size variables. For record variables, changing fill mode can be made at any time in NetCDF. so like, check which library you're in before you go changing things mid-flight, bestie π
π ENVIRONMENT VARIABLES π
PNETCDF_SAFE_MODEβ set to1to enable metadata consistency check. Warning messages will be printed to stdout if any inconsistency is detected. it's giving "your vibe check but for metadata" π
π MAILING-LISTS π
A mailing list is available for discussion of the PnetCDF interface and announcements about PnetCDF bugs, fixes, and enhancements. To subscribe or unsubscribe to the PnetCDF mailing list, visit https://lists.mcs.anl.gov/mailman/listinfo/parallel-netcdf. come thru, the group chat is open π«
π SEE ALSO π
ncmpidump(1), ncmpigen(1), ncmpidiff(1), ncvalidator(1), pnetcdf(3f).
π DATE π
July 1, 2026
PnetCDF User's Guide, published by Northwestern University and Argonne National Laboratory. This document is adopted from the netCDF User's Guide, developed at the Unidata Program Center, University Corporation for Atmospheric Research, located in Boulder, Colorado.
PnetCDF home page at https://parallel-netcdf.github.io
aaaand that's the whole page, bestie!! π you made it to the end and honestly? iconic. this was PnetCDF 1.15.0 and the print date on the tin is 2026-11-02 β so go forth, write your parallel netCDF files, and remember: indices start at 1, names are case-sensitive, and you are the main character of this HPC cluster π π¦β¨
π¦ where this page comes from
- ubuntu stonking: libpnetcdf-dev 1.15.0-3build1 Β· Northwestern
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms