Source code for hydroflows.methods.wflow.wflow_update_factors
"""Downscale a climate change factor dataset to the resolution of a wflow model and add to settings file."""
from os.path import relpath
from pathlib import Path
import hydromt # noqa: F401
import xarray as xr
from hydromt_wflow import WflowModel
from hydroflows._typing import FileDirPath, OutputDirPath
from hydroflows.methods.utils.io import to_netcdf
from hydroflows.methods.wflow.wflow_utils import copy_wflow_model
from hydroflows.workflow.method import Method
from hydroflows.workflow.method_parameters import Parameters
__all__ = ["WflowUpdateChangeFactors", "Input", "Output", "Params"]
[docs]
class Output(Parameters):
"""output parameters.
this class represents the output data
generated by the :py:class:`WflowUpdateChangeFactors` method.
"""
wflow_change_factors: Path
"""
Path to the change factor dataset at wflow model resolution.
"""
wflow_out_toml: FileDirPath
"""
The path to the updated wflow settings toml.
"""
[docs]
class Params(Parameters):
"""Parameters for the :py:class:`WflowUpdateChangeFactors`.
Instances of this class are used in the :py:class:`WflowUpdateChangeFactors`
method to define the required settings.
"""
output_dir: OutputDirPath
"""Output location relative to the workflow root. The updated model will be stored in <output_dir>."""
copy_model: bool = False
"""Create full copy of model or create rel paths in model config."""
resample_method: str = "nearest"
"""Method of resampling the low(er) res dataset."""
[docs]
class WflowUpdateChangeFactors(Method):
"""Downscale a climate change factor dataset to the resolution of a wflow model and add to settings file.
Parameters
----------
change_factor_dataset : Path
Path to the to be downscaled dataset.
wflow_toml : Path
Path to the wflow settings toml that needs to be adjusted.
**params
Additional parameters to pass to the WflowDownscale instance.
See :py:class:`wflow_update_factors Params <hydroflows.methods.wflow.wflow_update_factors.Params>`.
See Also
--------
:py:class:`wflow_update_factors Input <~hydroflows.methods.wflow.wflow_update_factors.Input>`
:py:class:`wflow_update_factors Output <~hydroflows.methods.wflow.wflow_update_factors.Output>`
:py:class:`wflow_update_factors Params <~hydroflows.methods.wflow.wflow_update_factors.Params>`
"""
name: str = "wflow_update_factors"
_test_kwargs = {
"change_factor_dataset": Path("dataset.nc"),
"wflow_toml": Path("wflow_sbm.toml"),
"output_dir": Path("data"),
}
def __init__(
self,
change_factor_dataset: Path,
wflow_toml: Path,
output_dir: Path,
**params,
):
self.params: Params = Params(output_dir=output_dir, **params)
self.input: Input = Input(
change_factor_dataset=change_factor_dataset,
wflow_toml=wflow_toml,
)
fname = self.input.change_factor_dataset.stem
fsuffix = self.input.change_factor_dataset.suffix
if not self.params.copy_model and not self.params.output_dir.is_relative_to(
self.input.wflow_toml.parent
):
raise ValueError(
"Output directory must be relative to input directory when not copying model."
)
self.output: Output = Output(
wflow_change_factors=self.params.output_dir
/ f"{fname}_downscaled{fsuffix}",
wflow_out_toml=self.params.output_dir / "wflow_sbm.toml",
)
def _run(self):
"""Run the downscale dataset method."""
if self.params.copy_model:
copy_wflow_model(
src=self.input.wflow_toml.parent,
dest=self.output.wflow_out_toml.parent,
copy_forcing=True,
)
# Open input files
ds = xr.open_dataset(self.input.change_factor_dataset, lock=False)
w = WflowModel(root=self.input.wflow_toml.parent, mode="r+")
# squeeze
ds = ds.squeeze()
# Downscale the data
ds_downscaled = ds.raster.reproject_like(
w.grid,
method=self.params.resample_method,
)
# rename from month to time for wflow
if "month" in ds_downscaled.coords:
ds_downscaled = ds_downscaled.rename({"month": "time"})
# Update the config
redirect = ["input.path_forcing", "input.path_static"]
# Redirect paths to forcing and staticmaps
if not self.params.copy_model:
for item in redirect:
value = w.get_config(item)
full_path = Path(value)
if not full_path.is_absolute():
full_path = Path(self.input.wflow_toml.parent, full_path)
else:
continue
new_path = Path(relpath(full_path, self.output.wflow_out_toml.parent))
w.set_config(item, new_path.as_posix())
# Put the downscaled dataset in the toml
w.set_config("input.path_forcing_scale", self.output.wflow_change_factors.name)
# Write the config
w.write_config(
config_name=self.output.wflow_out_toml.name,
config_root=self.params.output_dir,
)
# write netcdf
to_netcdf(
ds_downscaled,
file_name=self.output.wflow_change_factors.name,
output_dir=self.params.output_dir,
)