Reading existing MetaSWAP input#

iMOD Python currently has no support for reading entire MetaSWAP models, however reading individual .inp files into a pandas DataFrame is possible.

This is especially handy for reusing previously made lookup tables, e.g. LanduseOptions (luse_svat.inp) or AnnualGrowthFactors (fact_svat.inp).

We’ll start with the usual imports:

import os

import pandas as pd
import xarray as xr

import imod

Creating an example file#

For this example we’ll first have to create a file which we are going to read. You might already have such a file at hand from an existing model. In that case you can skip this step.

vegetation_index = [1, 2, 3]
names = ["grassland", "maize", "potatoes"]

landuse_index = [1, 2, 3]
coords = {"landuse_index": landuse_index}

landuse_names = xr.DataArray(data=names, coords=coords, dims=("landuse_index",))
vegetation_index_da = xr.DataArray(
    data=vegetation_index, coords=coords, dims=("landuse_index",)
)

# Because there are a lot of parameters to define, we'll create a DataArray of
# ones (``lu``) to more easily broadcast all the different parameters.

lu = xr.ones_like(vegetation_index_da, dtype=float)

landuse_options = imod.msw.LanduseOptions(
    landuse_name=landuse_names,
    vegetation_index=vegetation_index_da,
    jarvis_o2_stress=xr.ones_like(lu),
    jarvis_drought_stress=xr.ones_like(lu),
    feddes_p1=xr.full_like(lu, 99.0),
    feddes_p2=xr.full_like(lu, 99.0),
    feddes_p3h=lu * [-2.0, -4.0, -3.0],
    feddes_p3l=lu * [-8.0, -5.0, -5.0],
    feddes_p4=lu * [-80.0, -100.0, -100.0],
    feddes_t3h=xr.full_like(lu, 5.0),
    feddes_t3l=xr.full_like(lu, 1.0),
    threshold_sprinkling=lu * [-8.0, -5.0, -5.0],
    fraction_evaporated_sprinkling=xr.full_like(lu, 0.05),
    gift=xr.full_like(lu, 20.0),
    gift_duration=xr.full_like(lu, 0.25),
    rotational_period=lu * [10, 7, 7],
    start_sprinkling_season=lu * [120, 180, 150],
    end_sprinkling_season=lu * [230, 230, 240],
    interception_option=xr.ones_like(lu, dtype=int),
    interception_capacity_per_LAI=xr.zeros_like(lu),
    interception_intercept=xr.ones_like(lu),
)

Just to create an example file, we’ll write landuse_options into a luse_svat.inp file in a temporary directory

directory = imod.util.temporary_directory()
os.makedirs(directory)

landuse_options.write(directory, None, None, None, None)

Reading the .inp file#

We’ll construct the path to the luse_svat.inp file first

input_file = directory / "luse_svat.inp"

iMOD Python has a fixed_format_parser to parse MetaSWAP’s .inp files. This requires the file path and a metadata_dict, which is stored in the package. You can access it by calling <pkg>._metadata_dict. This function returns stores your data in a dictionary.

from imod.msw.fixed_format import fixed_format_parser

# Store the pkg in this variable for brevity
pkg = imod.msw.LanduseOptions
parsed = fixed_format_parser(input_file, pkg._metadata_dict)

parsed
{'landuse_index': [1, 2, 3], 'landuse_name': ['grassland           ', 'maize               ', 'potatoes            '], 'vegetation_index': [1, 2, 3], 'jarvis_o2_stress': [1.0, 1.0, 1.0], 'jarvis_drought_stress': [1.0, 1.0, 1.0], 'feddes_p1': [99.0, 99.0, 99.0], 'feddes_p2': [99.0, 99.0, 99.0], 'feddes_p3h': [-2.0, -4.0, -3.0], 'feddes_p3l': [-8.0, -5.0, -5.0], 'feddes_p4': [-80.0, -100.0, -100.0], 'feddes_t3h': [5.0, 5.0, 5.0], 'feddes_t3l': [1.0, 1.0, 1.0], 'threshold_sprinkling': [-8.0, -5.0, -5.0], 'fraction_evaporated_sprinkling': [0.05, 0.05, 0.05], 'gift': [20.0, 20.0, 20.0], 'gift_duration': [0.25, 0.25, 0.25], 'rotational_period': [10.0, 7.0, 7.0], 'start_sprinkling_season': [120.0, 180.0, 150.0], 'end_sprinkling_season': [230.0, 230.0, 240.0], 'albedo': ['        ', '        ', '        '], 'rsc': ['        ', '        ', '        '], 'rsw': ['        ', '        ', '        '], 'rsoil': ['        ', '        ', '        '], 'kdif': ['        ', '        ', '        '], 'kdir': ['        ', '        ', '        '], 'interception_option': [1, 1, 1], 'interception_capacity_per_LAI_Rutter': [0.0, 0.0, 0.0], 'interception_intercept': [1.0, 1.0, 1.0], 'interception_capacity_per_LAI_VonHoyningen': [0.0, 0.0, 0.0], 'pfree': ['        ', '        ', '        '], 'pstem': ['        ', '        ', '        '], 'scanopy': ['        ', '        ', '        '], 'avprec': ['        ', '        ', '        '], 'avevap': ['        ', '        ', '        '], 'saltmax': ['        ', '        ', '        '], 'saltslope': ['        ', '        ', '        ']}

You can easily convert this to a pandas DataFrame as follows:

df = pd.DataFrame(parsed)

df
landuse_index landuse_name vegetation_index jarvis_o2_stress jarvis_drought_stress feddes_p1 feddes_p2 feddes_p3h feddes_p3l feddes_p4 feddes_t3h feddes_t3l threshold_sprinkling fraction_evaporated_sprinkling gift gift_duration rotational_period start_sprinkling_season end_sprinkling_season albedo rsc rsw rsoil kdif kdir interception_option interception_capacity_per_LAI_Rutter interception_intercept interception_capacity_per_LAI_VonHoyningen pfree pstem scanopy avprec avevap saltmax saltslope
0 1 grassland 1 1.0 1.0 99.0 99.0 -2.0 -8.0 -80.0 5.0 1.0 -8.0 0.05 20.0 0.25 10.0 120.0 230.0 1 0.0 1.0 0.0
1 2 maize 2 1.0 1.0 99.0 99.0 -4.0 -5.0 -100.0 5.0 1.0 -5.0 0.05 20.0 0.25 7.0 180.0 230.0 1 0.0 1.0 0.0
2 3 potatoes 3 1.0 1.0 99.0 99.0 -3.0 -5.0 -100.0 5.0 1.0 -5.0 0.05 20.0 0.25 7.0 150.0 240.0 1 0.0 1.0 0.0


We can set landuse_index as the index:

df = df.set_index("landuse_index")

df
landuse_name vegetation_index jarvis_o2_stress jarvis_drought_stress feddes_p1 feddes_p2 feddes_p3h feddes_p3l feddes_p4 feddes_t3h feddes_t3l threshold_sprinkling fraction_evaporated_sprinkling gift gift_duration rotational_period start_sprinkling_season end_sprinkling_season albedo rsc rsw rsoil kdif kdir interception_option interception_capacity_per_LAI_Rutter interception_intercept interception_capacity_per_LAI_VonHoyningen pfree pstem scanopy avprec avevap saltmax saltslope
landuse_index
1 grassland 1 1.0 1.0 99.0 99.0 -2.0 -8.0 -80.0 5.0 1.0 -8.0 0.05 20.0 0.25 10.0 120.0 230.0 1 0.0 1.0 0.0
2 maize 2 1.0 1.0 99.0 99.0 -4.0 -5.0 -100.0 5.0 1.0 -5.0 0.05 20.0 0.25 7.0 180.0 230.0 1 0.0 1.0 0.0
3 potatoes 3 1.0 1.0 99.0 99.0 -3.0 -5.0 -100.0 5.0 1.0 -5.0 0.05 20.0 0.25 7.0 150.0 240.0 1 0.0 1.0 0.0


This DataFrame can consequently be converted to a xarray Dataset

ds = xr.Dataset.from_dataframe(df)

ds
<xarray.Dataset> Size: 864B
Dimensions:                                     (landuse_index: 3)
Coordinates:
  * landuse_index                               (landuse_index) int64 24B 1 2 3
Data variables: (12/35)
    landuse_name                                (landuse_index) object 24B 'g...
    vegetation_index                            (landuse_index) int64 24B 1 2 3
    jarvis_o2_stress                            (landuse_index) float64 24B 1...
    jarvis_drought_stress                       (landuse_index) float64 24B 1...
    feddes_p1                                   (landuse_index) float64 24B 9...
    feddes_p2                                   (landuse_index) float64 24B 9...
    ...                                          ...
    pstem                                       (landuse_index) object 24B ' ...
    scanopy                                     (landuse_index) object 24B ' ...
    avprec                                      (landuse_index) object 24B ' ...
    avevap                                      (landuse_index) object 24B ' ...
    saltmax                                     (landuse_index) object 24B ' ...
    saltslope                                   (landuse_index) object 24B ' ...


Not all variables contain data, these are variables which are not supported by iMOD Python, for example this parameter:

ds["albedo"]
<xarray.DataArray 'albedo' (landuse_index: 3)> Size: 24B
array(['        ', '        ', '        '], dtype=object)
Coordinates:
  * landuse_index  (landuse_index) int64 24B 1 2 3


We use some basic xarray plotting functionality to get a general idea of data for each landuse index

xticks = ds.coords["landuse_index"]

ds["feddes_p3h"].plot.step(where="mid", xticks=xticks)
read metaswap file
[<matplotlib.lines.Line2D object at 0x000001A35067A4D0>]

It is better to plot ordinal data on a bar chart. So in this case, we can use matplotlib’s bar function.

import matplotlib.pyplot as plt

plt.bar(xticks, ds["feddes_p3h"].values)
plt.xticks(xticks)
plt.xlabel("landuse_index")
plt.ylabel("feddes_p3h")
read metaswap file
Text(30.972222222222214, 0.5, 'feddes_p3h')

Total running time of the script: (0 minutes 0.297 seconds)

Gallery generated by Sphinx-Gallery