|
Extension: Json and NetCDF utilities
#include "dg/file/file.h"
|
MPI NetCDF-4 file based on serial NetCDF. More...
Public Types | |
| using | Hyperslab = MPINcHyperslab |
Public Member Functions | |
| MPINcFile (MPI_Comm comm=MPI_COMM_WORLD) | |
| Construct a File Handle not associated to any file. | |
| MPINcFile (const std::filesystem::path &filename, enum NcFileMode mode=nc_nowrite, MPI_Comm comm=MPI_COMM_WORLD) | |
| Open/Create a netCDF file. | |
| MPINcFile (const MPINcFile &rhs)=delete | |
| There can only be exactly one file handle per physical file. | |
| MPINcFile & | operator= (const MPINcFile &rhs)=delete |
| There can only be exactly one file handle per physical file. | |
| MPINcFile (MPINcFile &&rhs)=default | |
| Swap resources between two file handles. | |
| MPINcFile & | operator= (MPINcFile &&rhs) |
| Swap resources between two file handles. | |
| ~MPINcFile ()=default | |
| Close open nc file and release all resources. | |
| void | open (const std::filesystem::path &filename, enum NcFileMode mode=nc_nowrite) |
| Open/Create a netCDF file. | |
| bool | is_open () const |
| void | close () |
| Explicitly close a file. | |
| void | sync () |
| Call nc_sync. | |
| int | get_ncid () const noexcept |
Get the ncid of the underlying NetCDF C-API. | |
| int | get_format () const |
| Check the binary file format of the netCDF file. | |
| MPI_Comm | communicator () const |
| Return MPI communicator set in constructor. | |
| void | def_grp (std::string name) |
Define a group named name in the current group. | |
| void | def_grp_p (std::filesystem::path path) |
Define a group named path and all required intermediary groups. | |
| bool | grp_is_defined (std::filesystem::path path) const |
| Check for existence of the group given by path. | |
| void | set_grp (std::filesystem::path path="") |
Change group to path. | |
| void | rename_grp (std::string old_name, std::string new_name) |
rename a subgroup in the current group from old_name to new_name | |
| int | get_grpid () const noexcept |
| Get the NetCDF-C ID of the current group. | |
| std::filesystem::path | get_current_path () const |
| Get the absolute path of the current group. | |
| std::list< std::filesystem::path > | get_grps () const |
| Get all subgroups in the current group as absolute paths. | |
| std::list< std::filesystem::path > | get_grps_r () const |
| Get all subgroups recursively in the current group as absolute paths. | |
| void | def_dim (std::string name, size_t size) |
Define a dimension named name of size size. | |
| void | rename_dim (std::string old_name, std::string new_name) |
Rename a dimension from old_name to new_name. | |
| size_t | get_dim_size (std::string name) const |
Get the size of the dimension named name. | |
| std::vector< size_t > | get_dims_shape (const std::vector< std::string > &dims) const |
Get the size of each dimension in dims. | |
| std::vector< std::string > | get_dims (bool include_parents=true) const |
| Get all visible dimension names in the current group. | |
| std::vector< std::string > | get_unlim_dims () const |
| Get all visible unlimited dimension names in the current group. | |
| bool | dim_is_defined (std::string name) const |
| void | put_att (const std::pair< std::string, nc_att_t > &att, std::string id="") |
| Put an individual attribute. | |
| template<class S , class T > | |
| void | put_att (const std::tuple< S, nc_type, T > &att, std::string id="") |
| Put an individual attribute of preset type to variable id. | |
| template<class Attributes = std::map<std::string, nc_att_t>> | |
| void | put_atts (const Attributes &atts, std::string id="") |
| Write a collection of attributes to a NetCDF variable or file. | |
| template<class T > | |
| T | get_att_as (std::string att_name, std::string id="") const |
Get an attribute named att_name of the group or variable id. | |
| template<class T > | |
| std::vector< T > | get_att_vec_as (std::string att_name, std::string id="") const |
Short for get_att_as<std::vector<T>>( id, att_name); | |
| template<class T > | |
| std::map< std::string, T > | get_atts_as (std::string id="") const |
| Read all NetCDF attributes of a certain type. | |
| std::map< std::string, nc_att_t > | get_atts (std::string id="") const |
| void | del_att (std::string att_name, std::string id="") |
Remove an attribute named att_name from variable id. | |
| bool | att_is_defined (std::string att_name, std::string id="") const |
| void | rename_att (std::string old_att_name, std::string new_att_name, std::string id="") |
Rename an attribute of the variable id. | |
| template<class T , class Attributes = std::map<std::string, nc_att_t>> | |
| void | def_var_as (std::string name, const std::vector< std::string > &dim_names, const Attributes &atts={}) |
| Define a variable with given type, dimensions and (optionally) attributes. | |
| template<class Attributes = std::map<std::string, nc_att_t>> | |
| void | def_var (std::string name, nc_type xtype, const std::vector< std::string > &dim_names, const Attributes &atts={}) |
| Define a variable with given type, dimensions and (optionally) attributes. | |
| template<class ContainerType , typename = std::enable_if_t< dg::is_vector_v<ContainerType, dg::SharedVectorTag> or dg::is_vector_v<ContainerType, dg::MPIVectorTag>>> | |
| void | put_var (std::string name, const MPINcHyperslab &slab, const ContainerType &data) |
| Write data to a variable. | |
| template<class ContainerType , class Attributes = std::map<std::string, nc_att_t>, typename = std::enable_if_t< dg::is_vector_v<ContainerType, dg::SharedVectorTag> or dg::is_vector_v<ContainerType, dg::MPIVectorTag>>> | |
| void | defput_var (std::string name, const std::vector< std::string > &dim_names, const Attributes &atts, const MPINcHyperslab &slab, const ContainerType &data) |
| Define and put a variable in one go. | |
| template<class T , typename = std::enable_if_t<dg::is_scalar_v<T>>> | |
| void | put_var (std::string name, const std::vector< size_t > &start, T data) |
| Write a single data point. | |
| template<class T , class Attributes = std::map<std::string, nc_att_t>> | |
| void | def_dimvar_as (std::string name, size_t size, const Attributes &atts) |
| Define a dimension and dimension variable in one go. | |
| template<class ContainerType , class Attributes = std::map<std::string, nc_att_t>> | |
| void | defput_dim (std::string name, const Attributes &atts, const MPI_Vector< ContainerType > &abscissas) |
| Define a dimension and define and write to a dimension variable in one go. | |
| template<class ContainerType , typename = std::enable_if_t< dg::is_vector_v<ContainerType, dg::SharedVectorTag> or dg::is_vector_v<ContainerType, dg::MPIVectorTag>>> | |
| void | get_var (std::string name, const MPINcHyperslab &slab, ContainerType &data) const |
Read hyperslab slab from variable named name into container data. | |
| template<class T , typename = std::enable_if_t<dg::is_scalar_v<T>>> | |
| void | get_var (std::string name, const std::vector< size_t > &start, T &data) const |
Read scalar from position start from variable named name. | |
| template<class ContainerType , typename = std::enable_if_t< dg::is_vector_v<ContainerType, dg::SharedVectorTag> or dg::is_vector_v<ContainerType, dg::MPIVectorTag>>> | |
| ContainerType | get_var_as (std::string name, const MPINcHyperslab &slab) const |
| Convenience shortcut (vector version) | |
| template<class T , std::enable_if_t< dg::is_scalar_v< T >, bool > = true> | |
| T | get_var_as (std::string name, const std::vector< size_t > &start={}) const |
| Convenience shortcut (scalar version) | |
| bool | var_is_defined (std::string name) const |
| nc_type | get_var_type (std::string name) const |
| std::vector< std::string > | get_var_dims (std::string name) const |
Get the dimension names associated to variable name. | |
| std::list< std::string > | get_var_names () const |
| Get a list of variable names in the current group. | |
MPI NetCDF-4 file based on serial NetCDF.
by funneling all file operations through the rank 0 of the given communicator. In general, only the rank 0 actually opens, reads and writes to the file on disk with the exception of the nc_nowrite file mode where all ranks open the file. When metadata like attributes, groups and dimensions are read all ranks receive the same information (by MPI_Bcast i.e. there is MPI communication, or a parallel read without communication for nc_nowrite) and all ranks should call the write members with the same information even if only the rank 0 actually uses it.
When variables are read and written all ranks write/read a different chunk of the data except for scalar variables which are broadcast to all ranks on read. If nc_nowrite the reads are parallel and involve no MPI communication, otherwise all data is communicated to/from rank 0.
See here an example of its use
comm given in the constructor must participate in all member function calls. No exceptions!. Even if e.g. the data to write only lies distributed only on a subgroup of ranks. If an error occurs all participating ranks will throw!
|
inline |
Construct a File Handle not associated to any file.
| comm | All ranks in comm must participate in all subsequent member function calls |
|
inline |
Open/Create a netCDF file.
Call nc_open / nc_create depending on the value of mode
| filename | Name or path including the name of the netCDF file to open or create. The path may be either absolute or relative to the execution path of the program i.e. relative to std::filesystem::current_path() |
| mode | see dg::file::NcFileMode for possible values dg::file::nc_nowrite, dg::file::nc_write, dg::file::nc_clobber, dg::file::nc_noclobber. |
| comm | All ranks in comm must participate in all subsequent member function calls |
|
delete |
There can only be exactly one file handle per physical file.
The reason is that the destructor releases all resources and thus a copy of the file that is subsequently destroyed leaves the original in an invalid state
|
default |
Swap resources between two file handles.
|
default |
Close open nc file and release all resources.
std::cerr if something goes wrong
|
inline |
Check for existence of the attribute named att_name in variable id
|
inline |
Explicitly close a file.
Closing a file triggers all buffers to be written and memory to be released. After closing a new file can be associated to this handle again.
MPI_Barrier so that file.open with nc_nowrite can be called directly afterwards (the HDF-5 file-lock needs to be released)
|
inline |
Return MPI communicator set in constructor.
|
inline |
Define a dimension named name of size size.
| name | of the dimension. Cannot be the same name as a dimension name already existing in the current group |
| size | Size of the dimension to create. Use NC_UNLIMITED to create an unlimited dimension |
def_var cannot currently use a dimension that is hidden in such a way even though the NetCDF-C API would allow to do it using the dimension ID. In contrast, get_var_dims may return dimension names that are actually hidden. It is therefore highly recommended to use unique names for all dimensions in the file. Furthermore, notice that while a dimension is visible in subgroups, its associated dimension variable is not.
|
inline |
Define a dimension and dimension variable in one go.
Short for
| name | Name of the dimension and associated dimension variable |
| size | Size of the dimension to create. Use NC_UNLIMITED to create an unlimited dimension |
| atts | Suggested attribute is "axis" : "T" which enable paraview to recognize the dimension as the time axis |
def_var cannot currently use a dimension that is hidden in such a way even though the NetCDF-C API would allow to do it using the dimension ID. In contrast, get_var_dims may return dimension names that are actually hidden. It is therefore highly recommended to use unique names for all dimensions in the file. Furthermore, notice that while a dimension is visible in subgroups, its associated dimension variable is not.
|
inline |
Define a group named name in the current group.
Groups can be thought of as directories in a NetCDF-4 file and we therefore use std::filesystem::path and use bash equivalent operations to manipulate them
Think of this as the bash command mkdir name
| name | of the new group |
|
inline |
Define a group named path and all required intermediary groups.
Groups can be thought of as directories in a NetCDF-4 file and we therefore use std::filesystem::path and use bash equivalent operations to manipulate them
Think of this as the bash command mkdir -p path
| path | of the new group. Can be absolute or relative to the current group |
|
inline |
Define a variable with given type, dimensions and (optionally) attributes.
| name | Name of the variable to define |
| xtype | NetCDF typeid |
| dim_names | Names of visible dimensions in the current group Can be empty which makes the defined variable a scalar w/o dimensions. |
dg::evaluate function, which produces vectors where the first dimension of the given grid varies fastest. Thus, when defining variable dimensions the dimension name of the first grid dimension needs to come last. def_var cannot currently use a dimension that is hidden in such a way even though the NetCDF-C API would allow to do it using the dimension ID. In contrast, get_var_dims may return dimension names that are actually hidden. It is therefore highly recommended to use unique names for all dimensions in the file. Furthermore, notice that while a dimension is visible in subgroups, its associated dimension variable is not. | atts | Attributes to put for the variable |
|
inline |
Define a variable with given type, dimensions and (optionally) attributes.
| name | Name of the variable to define |
| dim_names | Names of visible dimensions in the current group. Can be empty which makes the defined variable a scalar w/o dimensions. |
dg::evaluate function, which produces vectors where the first dimension of the given grid varies fastest. Thus, when defining variable dimensions the dimension name of the first grid dimension needs to come last. def_var cannot currently use a dimension that is hidden in such a way even though the NetCDF-C API would allow to do it using the dimension ID. In contrast, get_var_dims may return dimension names that are actually hidden. It is therefore highly recommended to use unique names for all dimensions in the file. Furthermore, notice that while a dimension is visible in subgroups, its associated dimension variable is not. | T | set the type of the variable |
| atts | Attributes to put for the variable |
|
inline |
Define a dimension and define and write to a dimension variable in one go.
| name | Name of the dimension and associated dimension variable |
| atts | Suggested attributes is for example "axis" : "X" which enable paraview to recognize the dimension as the x axis and "long_name" : "X-coordinate in Cartesian coordinates" |
| abscissas | values to write to the dimension variable (the dimension size is inferred from abscissas.size() and the type is inferred from ContainerType |
| ContainerType | May be anything that dg::get_tensor_category recognises as a dg::SharedVectorTag. In defput* members the value type determines the NetCDF type of the variable to define |
put* and get* members it is possible for data to have a different value type from the defined value type of the variable that is being written/read, the NetCDF C-API simply converts it to the requested type. For example a variable declared as NC_DOUBLE can be read as/written from integer or float and vice versa. MPI_Reduce with abscissas.size() and abscissas.communicator() to get the size of the dimension in MPI.
|
inline |
Define and put a variable in one go.
Very convenient to "just write" a variable to a file:
Short for
|
inline |
Remove an attribute named att_name from variable id.
| att_name | Attribute to delete |
| id | Variable name in the current group or empty string, in which case the attributes refer to the current group |
|
inline |
Check for existence of the dimension named name
|
inline |
Get an attribute named att_name of the group or variable id.
| T | Any type in dg::file::nc_att_t or nc_att_t in which case the type specific nc attribute getters are called or std::vector<type> in which case the general nc_get_att is called |
| att_name | Name of the attribute |
| id | Variable name in the current group or empty string, in which case the attribute refers to the current group |
T
|
inline |
Short for get_att_as<std::vector<T>>( id, att_name);
|
inline |
Short for get_atts_as<nc_att_t>( id)
|
inline |
Read all NetCDF attributes of a certain type.
| id | Variable name in the current group or empty string, in which case the attributes refer to the current group |
| T | can be a primitive type like int or double or a vector thereof std::vector<int> or a dg::file::nc_att_t in which case attributes of heterogeneous types are captured |
|
inline |
Get the absolute path of the current group.
|
inline |
Get the size of the dimension named name.
|
inline |
Get all visible dimension names in the current group.
The visible dimensions are all the dimensions in the current group and all its parent group.
def_var cannot currently use a dimension that is hidden in such a way even though the NetCDF-C API would allow to do it using the dimension ID. In contrast, get_var_dims may return dimension names that are actually hidden. It is therefore highly recommended to use unique names for all dimensions in the file. Furthermore, notice that while a dimension is visible in subgroups, its associated dimension variable is not. | include_parents | per default the parent groups will be included in the search for dimensions, if false they are excluded |
|
inline |
Get the size of each dimension in dims.
|
inline |
Check the binary file format of the netCDF file.
useful if an unkown file is opened. A wrapper around nc_inq_format
|
inlinenoexcept |
Get the NetCDF-C ID of the current group.
In MPI all ranks get a grpid but only rank 0 can actually use it, except for nc_nowrite when every rank can use it
|
inline |
Get all subgroups in the current group as absolute paths.
Groups can be thought of as directories in a NetCDF-4 file and we therefore use std::filesystem::path and use bash equivalent operations to manipulate them
|
inline |
Get all subgroups recursively in the current group as absolute paths.
Think of this as ls -R
Groups can be thought of as directories in a NetCDF-4 file and we therefore use std::filesystem::path and use bash equivalent operations to manipulate them
|
inlinenoexcept |
Get the ncid of the underlying NetCDF C-API.
In case you want to call a NetCDF C-function yourself for whatever reason ... just don't use it for something nasty, like closing the file or whatever In MPI all ranks get an ncid but only rank 0 can actually use it, except for nc_nowrite when every rank can use it
|
inline |
Get all visible unlimited dimension names in the current group.
def_var cannot currently use a dimension that is hidden in such a way even though the NetCDF-C API would allow to do it using the dimension ID. In contrast, get_var_dims may return dimension names that are actually hidden. It is therefore highly recommended to use unique names for all dimensions in the file. Furthermore, notice that while a dimension is visible in subgroups, its associated dimension variable is not.
|
inline |
Read hyperslab slab from variable named name into container data.
| name | of previously defined variable |
| slab | Hyperslab to read |
| data | Result on output (will be resized to fit hyperslab) |
| ContainerType | May be anything that dg::get_tensor_category recognises as a dg::SharedVectorTag. In defput* members the value type determines the NetCDF type of the variable to define |
put* and get* members it is possible for data to have a different value type from the defined value type of the variable that is being written/read, the NetCDF C-API simply converts it to the requested type. For example a variable declared as NC_DOUBLE can be read as/written from integer or float and vice versa. MPINcHyperslab must be at least a subgroup of communicator() ContainerType in MPI can have either a dg::SharedVectorTag or dg::MPIVectorTag In case it is dg::MPIVectorTag its communicator will be set to slab.communicator()
|
inline |
Read scalar from position start from variable named name.
| name | of previously defined variable |
| start | coordinate to take scalar from (can be empty/is ignored for 0d variable) |
| data | Result on output |
|
inline |
Convenience shortcut (vector version)
Short for
|
inline |
Convenience shortcut (scalar version)
Short for
|
inline |
Get the dimension names associated to variable name.
| name | of the variable |
def_var cannot currently use a dimension that is hidden in such a way even though the NetCDF-C API would allow to do it using the dimension ID. In contrast, get_var_dims may return dimension names that are actually hidden. It is therefore highly recommended to use unique names for all dimensions in the file. Furthermore, notice that while a dimension is visible in subgroups, its associated dimension variable is not.
|
inline |
Get a list of variable names in the current group.
We use std::list here because of how easy it is to sort or filter elemenets. For example
|
inline |
Get the NetCDF typeid of the variable named name
|
inline |
Check for existence of the group given by path.
Groups can be thought of as directories in a NetCDF-4 file and we therefore use std::filesystem::path and use bash equivalent operations to manipulate them
| path | Absolute or relative path to the current group |
|
inline |
Check if a file is associated (i.e. it is open)
All MPI ranks agree if a file is open
|
inline |
Open/Create a netCDF file.
Call nc_open / nc_create depending on the value of mode
| filename | Name or path including the name of the netCDF file to open or create. The path may be either absolute or relative to the execution path of the program i.e. relative to std::filesystem::current_path() |
| mode | see dg::file::NcFileMode for possible values dg::file::nc_nowrite, dg::file::nc_write, dg::file::nc_clobber, dg::file::nc_noclobber. |
std::fstream opening fails if a file is already associated (is_open()). close() it before opening a new file!mode == nc_nowrite all ranks in comm open the file and the read member functions involve no communication MPI_Barrier so that all ranks see the existence of a possibly new file There can only be exactly one file handle per physical file.
The reason is that the destructor releases all resources and thus a copy of the file that is subsequently destroyed leaves the original in an invalid state
Swap resources between two file handles.
*this and rhs must the same
|
inline |
Put an individual attribute.
| att | Attribute consisting of name and value |
| id | Variable name in the current group or empty string, in which case the attribute refers to the current group |
att_is_defined for existence if this is a concern
|
inline |
Put an individual attribute of preset type to variable id.
| S | std::string or const char* |
| T | Cannot be an nc_att_t |
| att | Attribute consisting of name, type and value |
| id | Variable name in the current group or empty string, in which case the attribute refers to the current group |
att_is_defined for existence if this is a concern
|
inline |
Write a collection of attributes to a NetCDF variable or file.
Example code
| Attributes | Any Iterable whose values can be used in put_att i.e. either a std::pair or std::tuple |
| atts | An iterable containing all the attributes for the variable or file. atts can be empty in which case no attribute is written. |
| id | Variable name in the current group or empty string, in which case the attributes refer to the current group |
att_is_defined for existence if this is a concern
|
inline |
Write data to a variable.
| name | Name of the variable to write data to. Must be visible in the current group |
| slab | Define where the data is written. The dimension of the slab slab.ndim() must match the number of dimensions of the variable |
| data | to write. Size must be at least that of the slab |
| ContainerType | May be anything that dg::get_tensor_category recognises as a dg::SharedVectorTag. In defput* members the value type determines the NetCDF type of the variable to define |
put* and get* members it is possible for data to have a different value type from the defined value type of the variable that is being written/read, the NetCDF C-API simply converts it to the requested type. For example a variable declared as NC_DOUBLE can be read as/written from integer or float and vice versa. ContainerType in MPI can have either a dg::SharedVectorTag or dg::MPIVectorTag (It is the communicator of the slab that counts, the data communicator if present is ignored)
|
inline |
Write a single data point.
| name | Name of the variable to write data to. Must be visible in the current group |
| start | The coordinates (one for each dimension) to which to write data to |
| data | to write |
| T | must be convertible to the datatype of the variable name |
|
inline |
Rename an attribute of the variable id.
| old_att_name | Name of the attribute to change |
| new_att_name | New mane of the attribute |
| id | Variable name in the current group or empty string, in which case the attributes refer to the current group |
|
inline |
Rename a dimension from old_name to new_name.
|
inline |
rename a subgroup in the current group from old_name to new_name
Groups can be thought of as directories in a NetCDF-4 file and we therefore use std::filesystem::path and use bash equivalent operations to manipulate them
|
inline |
Change group to path.
All subsequent calls to atts, dims and vars are made to that group
ncid to the required grpid Groups can be thought of as directories in a NetCDF-4 file and we therefore use std::filesystem::path and use bash equivalent operations to manipulate them
| path | can be absolute or relative to the current group. Empty string or "/" goes back to root group. "." is the current group and returns immediately. |
|
inline |
Call nc_sync.
|
inline |
Check if variable named name is defined in the current group