Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: external forcings converter #647

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
559ddac
Initial setup of ext_old_to_new tool
arthurvd Jun 6, 2024
1bb5532
converter can now convert e02_dflowfm\f006_external_forcing\c011_extr…
FlorisBuwaldaDeltares Jul 4, 2024
2ab564f
modified tests to no longer use local directories
FlorisBuwaldaDeltares Jul 4, 2024
1fb7583
added extrapolate_slr case
FlorisBuwaldaDeltares Jul 4, 2024
851975d
Added some exception handling, now validate Meteo quantity before mak…
FlorisBuwaldaDeltares Jul 4, 2024
f8dfbce
added basinsquares test, fixed rainschematic.ext as an uncommented li…
FlorisBuwaldaDeltares Jul 4, 2024
34704fa
restore rainschematic.ext as otherwise unit tests get broken
FlorisBuwaldaDeltares Jul 8, 2024
c1033df
autoformat: isort & black
FlorisBuwaldaDeltares Jul 8, 2024
fdb2981
chore!: Refactored ext old converter to prepare for more other quanti…
arthurvd Jul 24, 2024
096d194
Merge branch 'main' into feature/621_extforce_converter
arthurvd Jul 29, 2024
9266e7b
Remove non-existing structure file reference in a test MDU
arthurvd Jul 29, 2024
314fbc8
Remove obsolete keywords from example windcase.mdu
arthurvd Jul 29, 2024
9dd1d70
New feature `exclude_unset` in ModelSaveSettings
arthurvd Nov 11, 2024
e2720ad
Combine power of LegacyFMModel and ResearchFMModel
arthurvd Nov 11, 2024
26e6d9b
Work-in-progress making converter tool more flexible for repeated runs
arthurvd Nov 11, 2024
2fb8c8b
Merge branch 'main' into feature/621_extforce_converter
arthurvd Nov 11, 2024
037cbc3
feat: initial condition converter from old external forcing file
MAfarrag Dec 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .flake8

This file was deleted.

17 changes: 14 additions & 3 deletions hydrolib/core/basemodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,18 +513,23 @@ class ModelSaveSettings:

_os_path_style = get_path_style_for_current_operating_system()

def __init__(self, path_style: Optional[PathStyle] = None) -> None:
def __init__(
self, path_style: Optional[PathStyle] = None, exclude_unset: bool = False
) -> None:
"""Initializes a new instance of the ModelSaveSettings class.

Args:
path_style (Optional[PathStyle], optional): Which file path style to use when saving the model. Defaults to the path style that matches the current operating system.
exclude_unset (bool, optional): Whether or not to exclude unset values when saving the model. Defaults to False.
"""

if path_style is None:
path_style = self._os_path_style

self._path_style = path_style

self._exclude_unset = exclude_unset

@property
def path_style(self) -> PathStyle:
"""Gets the path style setting.
Expand Down Expand Up @@ -1006,6 +1011,7 @@ def save(
filepath: Optional[Path] = None,
recurse: bool = False,
path_style: Optional[str] = None,
exclude_unset: bool = False,
) -> None:
"""Save the model to disk.

Expand Down Expand Up @@ -1039,6 +1045,9 @@ def save(
With which file path style to save the model. File references will
be written with the specified path style. Defaults to the path style
used by the current operating system. Options: 'unix', 'windows'.
exclude_unset (bool, optional):
Whether or not to exclude unset values when saving the model.
Defaults to False.

Raises:
ValueError: When an unsupported path style is passed.
Expand All @@ -1047,7 +1056,9 @@ def save(
self.filepath = filepath

path_style = path_style_validator.validate(path_style)
save_settings = ModelSaveSettings(path_style=path_style)
save_settings = ModelSaveSettings(
path_style=path_style, exclude_unset=exclude_unset
)

# Handle save
with file_load_context() as context:
Expand Down Expand Up @@ -1282,7 +1293,7 @@ def _save(self, save_settings: ModelSaveSettings) -> None:
Args:
save_settings (ModelSaveSettings): The model save settings.
"""
self._serialize(self.dict(), save_settings)
self._serialize(self.dict(exclude_unset=True), save_settings)

def _serialize(self, data: dict, save_settings: ModelSaveSettings) -> None:
"""Serializes the data to file. Should not be called directly, only through `_save`.
Expand Down
66 changes: 50 additions & 16 deletions hydrolib/core/dflowfm/ext/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@
validator_set_default_disk_only_file_model_when_none,
)
from hydrolib.core.dflowfm.bc.models import ForcingBase, ForcingData, ForcingModel
from hydrolib.core.dflowfm.ini.models import (
INIBasedModel,
INIGeneral,
INIModel,
INISerializerConfig,
)
from hydrolib.core.dflowfm.common.models import Operand
from hydrolib.core.dflowfm.ini.models import INIBasedModel, INIGeneral, INIModel
from hydrolib.core.dflowfm.ini.serializer import INISerializerConfig
from hydrolib.core.dflowfm.ini.util import (
LocationValidationConfiguration,
Expand Down Expand Up @@ -101,7 +97,7 @@ def _get_identifier(self, data: dict) -> Optional[str]:
return data.get("nodeid")

@property
def forcing(self) -> ForcingBase:
def forcing(self) -> Union[ForcingBase, None]:
"""Retrieves the corresponding forcing data for this boundary.

Returns:
Expand Down Expand Up @@ -195,13 +191,25 @@ class MeteoForcingFileType(StrEnum):
bcascii = "bcAscii"
"""str: Space-uniform time series in <*.bc> file."""

netcdf = "netcdf"
"""str: NetCDF, either with gridded data, or multiple station time series."""

uniform = "uniform"
"""str: Space-uniform time series in <*.tim> file."""

allowedvaluestext = "Possible values: bcAscii, netcdf, uniform."
unimagdir = "uniMagDir"
"""str: Space-uniform wind magnitude+direction in <*.tim> file."""

meteogridequi = "meteoGridEqui"
"""str: Space- and time-varying wind and pressure on an equidistant grid in <*.amu/v/p> files."""

spiderweb = "spiderweb"
"""str: Space- and time-varying cyclone wind and pressure in <*.spw> files."""

meteogridcurvi = "meteoGridCurvi"
"""str: Space- and time-varying wind and pressure on a curvilinear grid in <*.grd+*.amu/v/p> files."""

netcdf = "netcdf"
"""str: NetCDF, either with gridded data, or multiple station time series."""

allowedvaluestext = "Possible values: bcAscii, uniform, uniMagDir, meteoGridEqui, spiderweb, meteoGridCurvi, netcdf."


class MeteoInterpolationMethod(StrEnum):
Expand All @@ -212,8 +220,9 @@ class MeteoInterpolationMethod(StrEnum):

nearestnb = "nearestNb"
"""str: Nearest-neighbour interpolation, only with station-data in forcingFileType=netcdf"""

allowedvaluestext = "Possible values: nearestNb (only with station data in forcingFileType=netcdf ). "
linearSpaceTime = "linearSpaceTime"
"""str: Linear interpolation in space and time."""
allowedvaluestext = "Possible values: nearestNb, linearSpaceTime."


class Meteo(INIBasedModel):
Expand All @@ -236,6 +245,10 @@ class Comments(INIBasedModel.Comments):
forcingfiletype: Optional[str] = Field(
"Type of forcingFile.", alias="forcingFileType"
)
forcingVariableName: Optional[str] = Field(
"Variable name used in forcingfile associated with this forcing. See UM Section C.5.3",
alias="forcingVariableName",
)
targetmaskfile: Optional[str] = Field(
"Name of <*.pol> file to be used as mask. Grid parts inside any polygon will receive the meteo forcing.",
alias="targetMaskFile",
Expand All @@ -247,6 +260,18 @@ class Comments(INIBasedModel.Comments):
interpolationmethod: Optional[str] = Field(
"Type of (spatial) interpolation.", alias="interpolationMethod"
)
operand: Optional[str] = Field(
"How this data is combined with previous data for the same quantity (if any).",
alias="operand",
)
extrapolationAllowed: Optional[str] = Field(
"Optionally allow nearest neighbour extrapolation in space (0: no, 1: yes). Default off.",
alias="extrapolationAllowed",
)
extrapolationSearchRadius: Optional[str] = Field(
"Maximum search radius for nearest neighbor extrapolation in space.",
alias="extrapolationSearchRadius",
)

comments: Comments = Comments()

Expand All @@ -266,12 +291,21 @@ def _get_unknown_keyword_error_manager(cls) -> Optional[UnknownKeywordErrorManag
forcingfile: Union[TimModel, ForcingModel, DiskOnlyFileModel] = Field(
alias="forcingFile"
)
forcingVariableName: Optional[str] = Field(alias="forcingVariableName")
forcingfiletype: MeteoForcingFileType = Field(alias="forcingFileType")
targetmaskfile: Optional[PolyFile] = Field(None, alias="targetMaskFile")
targetmaskinvert: Optional[bool] = Field(None, alias="targetMaskInvert")
interpolationmethod: Optional[MeteoInterpolationMethod] = Field(
alias="interpolationMethod"
)
operand: Optional[Operand] = Field(Operand.override.value, alias="operand")
extrapolationAllowed: Optional[bool] = Field(alias="extrapolationAllowed")
extrapolationSearchRadius: Optional[float] = Field(
alias="extrapolationSearchRadius"
)
averagingType: Optional[int] = Field(alias="averagingType")
averagingNumMin: Optional[float] = Field(alias="averagingNumMin")
averagingPercentile: Optional[float] = Field(alias="averagingPercentile")

def is_intermediate_link(self) -> bool:
return True
Expand Down Expand Up @@ -306,9 +340,9 @@ class ExtModel(INIModel):
"""

general: ExtGeneral = ExtGeneral()
boundary: List[Boundary] = []
lateral: List[Lateral] = []
meteo: List[Meteo] = []
boundary: List[Boundary] = Field(default_factory=list)
lateral: List[Lateral] = Field(default_factory=list)
meteo: List[Meteo] = Field(default_factory=list)
serializer_config: INISerializerConfig = INISerializerConfig(
section_indent=0, property_indent=0
)
Expand Down
Loading
Loading