imod.idf - IDF file I/O¶
Functions for reading and writing iMOD Data Files (IDFs) to xarray
objects.
The primary functions to use are imod.idf.open()
and
imod.idf.save()
, though lower level functions are also available.
-
imod.idf.
open
(path, use_cftime=False, pattern=None)[source]¶ Open one or more IDF files as an xarray.DataArray.
In accordance with xarray’s design,
open
loads the data of IDF files lazily. This means the data of the IDFs are not loaded into memory until the data is needed. This allows for easier handling of large datasets, and more efficient computations.- Parameters
path (str, Path or list) – This can be a single file, ‘head_l1.idf’, a glob pattern expansion, ‘head_l*.idf’, or a list of files, [‘head_l1.idf’, ‘head_l2.idf’]. Note that each file needs to be of the same name (part before the first underscore) but have a different layer and/or timestamp, such that they can be combined in a single xarray.DataArray.
use_cftime (bool, optional) –
Use
cftime.DatetimeProlepticGregorian
instead of np.datetime64[ns] for the time axis.Dates are normally encoded as
np.datetime64[ns]
; however, if dates fall before 1678 or after 2261, they are automatically encoded ascftime.DatetimeProlepticGregorian
objects rather thannp.datetime64[ns]
.pattern (str, regex pattern, optional) – If the filenames do match default naming conventions of {name}_{time}_l{layer}, a custom pattern can be defined here either as a string, or as a compiled regular expression pattern. See the examples below.
- Returns
A float xarray.DataArray of the values in the IDF file(s). All metadata needed for writing the file to IDF or other formats using imod.rasterio are included in the xarray.DataArray.attrs.
- Return type
xarray.DataArray
Examples
Open an IDF file:
>>> da = imod.idf.open("example.idf")
Open an IDF file, relying on default naming conventions to identify layer:
>>> da = imod.idf.open("example_l1.idf")
Open an IDF file, relying on default naming conventions to identify layer and time:
>>> head = imod.idf.open("head_20010101_l1.idf")
Open multiple IDF files, in this case files for the year 2001 for all layers, again relying on default conventions for naming:
>>> head = imod.idf.open("head_2001*_l*.idf")
The same, this time explicitly specifying
name
,time
, andlayer
:>>> head = imod.idf.open("head_2001*_l*.idf", pattern="{name}_{time}_l{layer}")
The format string pattern will only work on tidy paths, where variables are separated by underscores. You can also pass a compiled regex pattern. Make sure to include the
re.IGNORECASE
flag since all paths are lowered.>>> import re >>> pattern = re.compile(r"(?P<name>[\w]+)L(?P<layer>[\d+]*)", re.IGNORECASE) >>> head = imod.idf.open("headL11", pattern=pattern)
However, this requires constructing regular expressions, which is generally a fiddly process. Regex notation is also impossible to remember. The website https://regex101.com is a nice help. Alternatively, the most pragmatic solution may be to just rename your files.
-
imod.idf.
open_dataset
(globpath, use_cftime=False, pattern=None)[source]¶ Open a set of IDFs to a dict of xarray.DataArrays.
Compared to imod.idf.open, this function lets you open multiple parameters at once (for example kh values and starting heads of a model), which will each be a separate entry in a dictionary, with as key the parameter name, and as value the xarray.DataArray.
- Parameters
globpath (str or Path) – A glob pattern expansion such as
'model/**/*.idf'
, which recursively finds all IDF files under the model directory. Note that files with the same name (part before the first underscore) wil be combined into a single xarray.DataArray.use_cftime (bool, optional) –
Use
cftime.DatetimeProlepticGregorian
instead of np.datetime64[ns] for the time axis.Dates are normally encoded as
np.datetime64[ns]
; however, if dates fall before 1679 or after 2262, they are automatically encoded ascftime.DatetimeProlepticGregorian
objects rather thannp.datetime64[ns]
.pattern (str, regex pattern, optional) – If the filenames do match default naming conventions of {name}_{time}_l{layer}, a custom pattern can be defined here either as a string, or as a compiled regular expression pattern. Please refer to the examples for
imod.idf.open
.
- Returns
Dictionary of str (parameter name) to xarray.DataArray. All metadata needed for writing the file to IDF or other formats using imod.rasterio are included in the xarray.DataArray.attrs.
- Return type
dictionary
-
imod.idf.
open_subdomains
(path, use_cftime=False)[source]¶ Combine IDF files of multiple subdomains.
- Parameters
path (str, Path or list) –
use_cftime (bool, optional) –
pattern (str, regex pattern, optional) –
- Returns
- Return type
xarray.DataArray
-
imod.idf.
read
(path, pattern=None)[source]¶ Read a single IDF file to a numpy.ndarray
- Parameters
path (str or Path) – Path to the IDF file to be read
pattern (str, regex pattern, optional) – If the filenames do match default naming conventions of {name}_{time}_l{layer}, a custom pattern can be defined here either as a string, or as a compiled regular expression pattern. Please refer to the examples for
imod.idf.open
.
- Returns
numpy.ndarray – A float numpy.ndarray with shape (nrow, ncol) of the values in the IDF file. On opening all nodata values are changed to NaN in the numpy.ndarray.
dict – A dict with all metadata.
-
imod.idf.
save
(path, a, nodata=1e+20, pattern=None, dtype=<class 'numpy.float32'>)[source]¶ Write a xarray.DataArray to one or more IDF files
If the DataArray only has
y
andx
dimensions, a single IDF file is written, like theimod.idf.write
function. This function is more general and also supportstime
andlayer
dimensions. It will split these up, give them their own filename according to the conventions inimod.util.compose
, and write them each.- Parameters
path (str or Path) – Path to the IDF file to be written. This function decides on the actual filename(s) using conventions.
a (xarray.DataArray) – DataArray to be written. It needs to have dimensions (‘y’, ‘x’), and optionally
layer
andtime
.nodata (float, optional) – Nodata value in the saved IDF files. Xarray uses nan values to represent nodata, but these tend to work unreliably in iMOD(FLOW). Defaults to a value of 1.0e20.
pattern (str) – Format string which defines how to create the filenames. See examples.
Example
Consider a DataArray
da
that has dimensions ‘layer’, ‘y’ and ‘x’, with the ‘layer’ dimension consisting of layer 1 and 2:save('path/to/head', da)
This writes the following two IDF files: ‘path/to/head_l1.idf’ and ‘path/to/head_l2.idf’.
It is possible to generate custom filenames using a format string. The default filenames would be generated by the following format string:
save(“example”, pattern=”{name}_l{layer}{extension}”)
If you desire zero-padded numbers that show up neatly sorted in a file manager, you may specify:
save(“example”, pattern=”{name}_l{layer:02d}{extension}”)
In this case, a 0 will be padded for single digit numbers (‘1’ will become ‘01’).
To get a date with dashes, use the following pattern:
“{name}_{time:%Y-%m-%d}_l{layer}{extension}”
-
imod.idf.
write
(path, a, nodata=1e+20, dtype=<class 'numpy.float32'>)[source]¶ Write a 2D xarray.DataArray to a IDF file
- Parameters
path (str or Path) – Path to the IDF file to be written
a (xarray.DataArray) – DataArray to be written. It needs to have exactly a.dims == (‘y’, ‘x’).
nodata (float, optional) – Nodata value in the saved IDF files. Xarray uses nan values to represent nodata, but these tend to work unreliably in iMOD(FLOW). Defaults to a value of 1.0e20.