From 59637453413496dc7f44f4a200a2bae0fe8d8d84 Mon Sep 17 00:00:00 2001 From: Tim van den Aardweg <71257004+tim-vd-aardweg@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:12:52 +0200 Subject: [PATCH 1/4] feat: Add/move more mdu keywords (#654) refs: #648 --- hydrolib/core/dflowfm/mdu/models.py | 57 +++++++++- hydrolib/core/dflowfm/research/models.py | 104 +++++++----------- .../c063_rain_tim/rainschematic.mdu | 6 - .../c069_rain_bc/rainschematic.mdu | 6 - .../fm/moergestels_broek.mdu | 4 +- ...keywords_from_dia_file_2024.03_release.mdu | 3 +- .../data/reference/fm/special_3d_settings.mdu | 14 ++- tests/dflowfm/test_research.py | 10 +- 8 files changed, 117 insertions(+), 87 deletions(-) diff --git a/hydrolib/core/dflowfm/mdu/models.py b/hydrolib/core/dflowfm/mdu/models.py index e6d620ed9..49bd2aeb8 100644 --- a/hydrolib/core/dflowfm/mdu/models.py +++ b/hydrolib/core/dflowfm/mdu/models.py @@ -62,6 +62,9 @@ class Comments(INIBasedModel.Comments): "Whether or not (1/0) to resolve file names (e.g. inside the *.ext file) relative to their direct parent, instead of to the toplevel MDU working dir", alias="pathsRelativeToParent", ) + guiversion: Optional[str] = Field( + "DeltaShell FM suite version.", alias="guiVersion" + ) comments: Comments = Comments() _header: Literal["General"] = "General" @@ -71,6 +74,7 @@ class Comments(INIBasedModel.Comments): fileversion: str = Field("1.09", alias="fileVersion") autostart: Optional[AutoStartOption] = Field(AutoStartOption.no, alias="autoStart") pathsrelativetoparent: bool = Field(False, alias="pathsRelativeToParent") + guiversion: Optional[str] = Field(None, alias="guiVersion") class Numerics(INIBasedModel): @@ -305,6 +309,14 @@ class Comments(INIBasedModel.Comments): fixedweirtalud: Optional[str] = Field( "Uniform talud slope of fixed weirs.", alias="fixedWeirTalud" ) + lateral_fixedweir_umin: Optional[str] = Field( + "Minimal velocity threshold for weir losses in iterative lateral 1d2d weir coupling.", + alias="lateral_fixedweir_umin", + ) + jasfer3d: Optional[str] = Field( + "Corrections for spherical coordinates (0: no, 1: yes).", + alias="jasfer3D", + ) comments: Comments = Comments() @@ -368,6 +380,8 @@ class Comments(INIBasedModel.Comments): velocitywarn: float = Field(0.0, alias="velocityWarn") adveccorrection1d2d: int = Field(0, alias="advecCorrection1D2D") fixedweirtalud: float = Field(4.0, alias="fixedWeirTalud") + lateral_fixedweir_umin: float = Field(0.0, alias="lateral_fixedweir_umin") + jasfer3d: bool = Field(False, alias="jasfer3D") class VolumeTables(INIBasedModel): @@ -382,7 +396,7 @@ class VolumeTables(INIBasedModel): class Comments(INIBasedModel.Comments): usevolumetables: Optional[str] = Field( - "Use volume tables for 1D grid cells (1: yes, 0 = no).", + "Use 1D volume tables (0: no, 1: yes).", alias="useVolumeTables", ) increment: Optional[str] = Field( @@ -804,6 +818,9 @@ class Comments(INIBasedModel.Comments): "Update interval for time dependent roughness parameters [s].", alias="updateRoughnessInterval", ) + dtfacmax: Optional[str] = Field( + "Max timestep increase factor in successive time steps.", alias="Dtfacmax" + ) comments: Comments = Comments() @@ -823,6 +840,7 @@ class Comments(INIBasedModel.Comments): startdatetime: Optional[str] = Field(None, alias="startDateTime") stopdatetime: Optional[str] = Field(None, alias="stopDateTime") updateroughnessinterval: float = Field(86400.0, alias="updateRoughnessInterval") + dtfacmax: float = Field(1.1, alias="Dtfacmax") @validator("startdatetime", "stopdatetime") def _validate_datetime(cls, value, field): @@ -1306,6 +1324,16 @@ class Comments(INIBasedModel.Comments): "Write air density rates to map file (1: yes, 0: no)", alias="wrimap_airdensity", ) + wrimap_calibration: Optional[str] = Field( + "Write roughness calibration factors to map file.", + alias="wrimap_calibration", + ) + wrimap_salinity: Optional[str] = Field( + "Write salinity to map file.", alias="wrimap_salinity" + ) + wrimap_temperature: Optional[str] = Field( + "Write temperature to map file.", alias="wrimap_temperature" + ) writek_cdwind: Optional[str] = Field( "Write wind friction coefficients to tek file (1: yes, 0: no).", alias="writek_CdWind", @@ -1402,7 +1430,7 @@ class Comments(INIBasedModel.Comments): ) wrimap_every_dt: Optional[str] = Field( "Write output to map file every computational timestep, between start and stop time from MapInterval, (1: yes, 0: no).", - alias="wrimap_input_dt", + alias="wrimap_every_dt", ) wrimap_input_roughness: Optional[str] = Field( "Write chezy input roughness on flow links to map file, (1: yes, 0: no).", @@ -1473,6 +1501,18 @@ class Comments(INIBasedModel.Comments): "Write chezy roughness on flow links to map file, (1: yes, 0: no)", alias="wrimap_chezy_on_flow_links", ) + writepart_domain: Optional[str] = Field( + "Write partition domain info. for postprocessing (0: no, 1: yes).", + alias="writepart_domain", + ) + velocitydirectionclassesinterval: Optional[str] = Field( + "Class map's step size of class values for velocity direction.", + alias="VelocityDirectionClassesInterval", + ) + velocitymagnitudeclasses: Optional[str] = Field( + "Class map's list of class values for velocity magnitudes.", + alias="VelocityMagnitudeClasses", + ) comments: Comments = Comments() @@ -1594,6 +1634,9 @@ class Comments(INIBasedModel.Comments): wrimap_wind: bool = Field(True, alias="wrimap_wind") wrimap_windstress: bool = Field(False, alias="wrimap_windstress") wrimap_airdensity: bool = Field(False, alias="wrimap_airdensity") + wrimap_calibration: bool = Field(True, alias="wrimap_calibration") + wrimap_salinity: bool = Field(True, alias="wrimap_salinity") + wrimap_temperature: bool = Field(True, alias="wrimap_temperature") writek_cdwind: bool = Field(False, alias="writek_CdWind") wrimap_heat_fluxes: bool = Field(False, alias="wrimap_heat_fluxes") wrimap_wet_waterdepth_threshold: float = Field( @@ -1637,7 +1680,7 @@ class Comments(INIBasedModel.Comments): statsinterval: List[float] = Field([-60.0], alias="statsInterval") timingsinterval: List[float] = Field([0.0], alias="timingsInterval") richardsononoutput: bool = Field(False, alias="richardsonOnOutput") - wrimap_every_dt: bool = Field(False, alias="wrimap_input_dt") + wrimap_every_dt: bool = Field(False, alias="wrimap_every_dt") wrimap_input_roughness: bool = Field(False, alias="wrimap_input_roughness") wrimap_flowarea_au: bool = Field(False, alias="wrimap_flowarea_au") wrihis_airdensity: bool = Field(False, alias="wrihis_airdensity") @@ -1661,6 +1704,13 @@ class Comments(INIBasedModel.Comments): wrimap_volume1: bool = Field(False, alias="wrimap_volume1") wrimap_ancillary_variables: bool = Field(False, alias="wrimap_ancillary_variables") wrimap_chezy_on_flow_links: bool = Field(False, alias="wrimap_chezy_on_flow_links") + writepart_domain: bool = Field(True, alias="writepart_domain") + velocitydirectionclassesinterval: float = Field( + 0.0, alias="VelocityDirectionClassesInterval" + ) + velocitymagnitudeclasses: List[float] = Field( + [0.0], alias="VelocityMagnitudeClasses" + ) _split_to_list = get_split_string_on_delimiter_validator( "waterlevelclasses", @@ -1675,6 +1725,7 @@ class Comments(INIBasedModel.Comments): "waqinterval", "statsinterval", "timingsinterval", + "velocitymagnitudeclasses", ) def is_intermediate_link(self) -> bool: diff --git a/hydrolib/core/dflowfm/research/models.py b/hydrolib/core/dflowfm/research/models.py index 597031664..10c990365 100644 --- a/hydrolib/core/dflowfm/research/models.py +++ b/hydrolib/core/dflowfm/research/models.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Optional from pydantic.v1 import Field @@ -19,7 +19,6 @@ Waves, Wind, ) -from hydrolib.core.dflowfm.ini.util import get_split_string_on_delimiter_validator class ResearchGeneral(General): @@ -137,6 +136,10 @@ class Comments(Geometry.Comments): "Extrapolation of bed level at boundaries according to the slope: 0 = no extrapolation (default); 1 = extrapolate.", alias="extrbl", ) + research_keepzlay1bedvol: Optional[str] = Field( + "Correct volumes when keepzlayeringatbed=1 (0: too large bedcell volumes, 1: correct bedcell volumes).", + alias="keepzlay1bedvol", + ) comments: Comments = Comments() @@ -171,6 +174,7 @@ class Comments(Geometry.Comments): None, alias="groundlayerthickness" ) research_extrbl: Optional[bool] = Field(None, alias="extrbl") + research_keepzlay1bedvol: Optional[bool] = Field(None, alias="keepzlay1bedvol") class ResearchNumerics(Numerics): @@ -218,13 +222,9 @@ class Comments(Numerics.Comments): alias="structurelayersactive", ) research_corioadamsbashfordfac: Optional[str] = Field( - "0.5 0=No, 0.5d0=AdamsBashford, only for Newcorio=1.", + "Adams-Bashford factor in Coriolis term (0: No/explicit, 0.5d0=Adams-Bashford), only for Newcorio=1.", alias="corioadamsbashfordfac", ) - research_vertadvtypsal: Optional[str] = Field( - "Vertical advection type for salinity (0: none, 1: upwind explicit, 2: central explicit, 3: upwind implicit, 4: central implicit, 5: central implicit but upwind for neg. stratif., 6: higher order explicit, no Forester).", - alias="vertadvtypsal", - ) research_baorgfracmin: Optional[str] = Field( "Cell area = max(orgcellarea*Baorgfracmin, cutcell area)", alias="baorgfracmin", @@ -263,17 +263,13 @@ class Comments(Numerics.Comments): alias="logprofatubndin", ) research_horadvtypzlayer: Optional[str] = Field( - "Horizontal advection treatment of z-layers (1: default, 2: sigma-like).", + "Vertical treatment of horizontal advection in z-layers (0: default, 1: N/A, 2: sigma-like).", alias="horadvtypzlayer", ) research_chkdifd: Optional[str] = Field( "Check diffusion terms if depth < chkdifd, only if jatransportautotimestepdiff==1.", alias="chkdifd", ) - research_lateral_fixedweir_umin: Optional[str] = Field( - "Minimal velocity treshold for weir losses in iterative lateral 1d2d weir coupling.", - alias="lateral_fixedweir_umin", - ) research_fixedweirfrictscheme: Optional[str] = Field( "Fixed weir friction scheme (0: friction based on hu, 1: friction based on subgrid weir friction scheme).", alias="fixedweirfrictscheme", @@ -289,7 +285,7 @@ class Comments(Numerics.Comments): "Exp for including (1-CFL) in sethu.", alias="cfexphu" ) research_drop3d: Optional[str] = Field( - "Apply droplosses in 3D if z upwind below bob + 2/3 hu*drop3D.", + "Waterdepth factor, apply droplosses in 3D if z upwind below bob + 2/3 hu*drop3D.", alias="drop3d", ) research_zlayercenterbedvel: Optional[str] = Field( @@ -301,7 +297,8 @@ class Comments(Numerics.Comments): alias="cffacver", ) research_eddyviscositybedfacmax: Optional[str] = Field( - "Limit eddy viscosity at bed.", alias="eddyviscositybedfacmax" + "Limit eddy viscosity at bed (factor 0.0-1.0 of first layer above).", + alias="eddyviscositybedfacmax", ) research_epseps: Optional[str] = Field( "EPS=max(EPS, EpsEPS), default=1d-32, (or TAU).", alias="epseps" @@ -316,7 +313,7 @@ class Comments(Numerics.Comments): ) research_testfixedweirs: Optional[str] = Field( "Test for fixed weir algoritms (0 = Sieben2010, 1 = Sieben2007 ).", - alias="testFixedWeirs", + alias="testfixedweirs", ) research_jposhchk: Optional[str] = Field( "Check for positive waterdepth (0: no, 1: 0.7dts, just redo, 2: 1.0dts, close all links, 3: 0.7dts, close all links, 4: 1.0dts, reduce au, 5: 0.7dts, reduce au, 6: 1.0dts, close outflowing links, 7: 0.7*dts, close outflowing link.", @@ -371,14 +368,22 @@ class Comments(Numerics.Comments): "Factor for including (1-CFL) in sethu (0d0: no, 1d0: yes).", alias="cffachu", ) - research_jasfer3d: Optional[str] = Field( - "Corrections for spherical coordinates.", - alias="jasfer3d", - ) research_vertadvtypmom3onbnd: Optional[str] = Field( - "vert. adv. u1 bnd UpwimpL: 0=follow javau , 1 = on bnd, 2= on and near bnd.", + "Vert. adv. u1 bnd UpwimpL: 0=follow javau , 1 = on bnd, 2= on and near bnd.", alias="vertadvtypmom3onbnd", ) + research_noderivedtypes: Optional[str] = Field( + "0=use der. types. , 1 = less, 2 = lesser, 5 = also dealloc der. types.", + alias="noderivedtypes", + ) + research_jadelvappos: Optional[str] = Field( + "Only positive forced evaporation fluxes(0: no, 1: yes).", + alias="jadelvappos", + ) + research_jarhoxu: Optional[str] = Field( + "Include density gradient in advection term (0: no(strongly advised), 1: yes, 2: Also in barotropic and baroclinic pressure term, 3,4: Also in vertical advection).", + alias="jarhoxu", + ) comments: Comments = Comments() @@ -397,7 +402,6 @@ class Comments(Numerics.Comments): research_corioadamsbashfordfac: Optional[float] = Field( None, alias="corioadamsbashfordfac" ) - research_vertadvtypsal: Optional[int] = Field(None, alias="vertadvtypsal") research_baorgfracmin: Optional[float] = Field(None, alias="baorgfracmin") research_epstke: Optional[float] = Field(None, alias="epstke") research_jadrhodz: Optional[int] = Field(None, alias="jadrhodz") @@ -410,9 +414,6 @@ class Comments(Numerics.Comments): research_logprofatubndin: Optional[int] = Field(None, alias="logprofatubndin") research_horadvtypzlayer: Optional[int] = Field(None, alias="horadvtypzlayer") research_chkdifd: Optional[float] = Field(None, alias="chkdifd") - research_lateral_fixedweir_umin: Optional[float] = Field( - None, alias="lateral_fixedweir_umin" - ) research_fixedweirfrictscheme: Optional[int] = Field( None, alias="fixedweirfrictscheme" ) @@ -420,7 +421,9 @@ class Comments(Numerics.Comments): research_zwsbtol: Optional[float] = Field(None, alias="zwsbtol") research_cfexphu: Optional[float] = Field(None, alias="cfexphu") research_drop3d: Optional[float] = Field(None, alias="drop3d") - research_zlayercenterbedvel: Optional[int] = Field(None, alias="zlayercenterbedvel") + research_zlayercenterbedvel: Optional[bool] = Field( + None, alias="zlayercenterbedvel" + ) research_cffacver: Optional[float] = Field(None, alias="cffacver") research_eddyviscositybedfacmax: Optional[float] = Field( None, alias="eddyviscositybedfacmax" @@ -432,13 +435,13 @@ class Comments(Numerics.Comments): research_lateral_fixedweir_minimal_1d2d_embankment: Optional[float] = Field( None, alias="lateral_fixedweir_minimal_1d2d_embankment" ) - research_testfixedweirs: Optional[int] = Field(None, alias="testFixedWeirs") + research_testfixedweirs: Optional[int] = Field(None, alias="testfixedweirs") research_jposhchk: Optional[int] = Field(None, alias="jposhchk") research_cfconhormom: Optional[float] = Field(None, alias="cfconhormom") research_cffachormom: Optional[float] = Field(None, alias="cffachormom") research_trsh_u1lb: Optional[float] = Field(None, alias="trsh_u1lb") research_corioconstant: Optional[int] = Field(None, alias="corioconstant") - research_jaupwindsrc: Optional[int] = Field(None, alias="jaupwindsrc") + research_jaupwindsrc: Optional[bool] = Field(None, alias="jaupwindsrc") research_locsaltlev: Optional[float] = Field(None, alias="locsaltlev") research_subsuplupdates1: Optional[bool] = Field(None, alias="subsuplupdates1") research_linkdriedmx: Optional[int] = Field(None, alias="linkdriedmx") @@ -449,10 +452,12 @@ class Comments(Numerics.Comments): research_numlimdt_baorg: Optional[int] = Field(None, alias="numlimdt_baorg") research_locsaltmax: Optional[float] = Field(None, alias="locsaltmax") research_cffachu: Optional[float] = Field(None, alias="cffachu") - research_jasfer3d: Optional[bool] = Field(None, alias="jasfer3d") research_vertadvtypmom3onbnd: Optional[int] = Field( None, alias="vertadvtypmom3onbnd" ) + research_noderivedtypes: Optional[int] = Field(None, alias="noderivedtypes") + research_jadelvappos: Optional[bool] = Field(None, alias="jadelvapos") + research_jarhoxu: Optional[int] = Field(None, alias="jarhoxu") class ResearchPhysics(Physics): @@ -485,7 +490,7 @@ class Comments(Physics.Comments): "Use soil temperature buffer if > 0.", alias="soiltempthick" ) research_selfattractionloading: Optional[str] = Field( - "Self attraction and loading (0=no, 1=yes, 2=only self attraction).", + "Use self attraction and loading (0: no, 1: yes, 2: only self attraction).", alias="selfattractionloading", ) research_prandtlnumbertemperature: Optional[str] = Field( @@ -500,10 +505,6 @@ class Comments(Physics.Comments): "Turbulent Schmidt number for tracer(s).", alias="schmidtnumbertracer", ) - research_umodlin: Optional[str] = Field( - "Linear friction umod, for ifrctyp=4,5,6.", - alias="umodlin", - ) research_uniffrictcoef1dgrlay: Optional[str] = Field( "Uniform ground layer friction coefficient for ocean models (m/s) (0: no friction).", alias="uniffrictcoef1dgrlay", @@ -536,7 +537,6 @@ class Comments(Physics.Comments): research_schmidtnumbertracer: Optional[float] = Field( None, alias="schmidtnumbertracer" ) - research_umodlin: Optional[float] = Field(None, alias="umodlin") research_uniffrictcoef1dgrlay: Optional[float] = Field( None, alias="uniffrictcoef1dgrlay" ) @@ -578,7 +578,7 @@ class Comments(Wind.Comments): "Wind hu or zws based, 0 = hu, 1 = zws.", alias="windhuorzwsbased" ) research_varyingairdensity: Optional[str] = Field( - "Compute air density yes/no (), 1/0, default 0.", alias="varyingAirDensity" + "Compute air density yes/no (), 1/0, default 0.", alias="varyingairdensity" ) research_wind_eachstep: Optional[str] = Field( "1=wind (and air pressure) each computational timestep, 0=wind (and air pressure) each usertimestep.", @@ -588,7 +588,7 @@ class Comments(Wind.Comments): comments: Comments = Comments() research_windhuorzwsbased: Optional[int] = Field(None, alias="windhuorzwsbased") - research_varyingairdensity: Optional[bool] = Field(None, alias="varyingAirDensity") + research_varyingairdensity: Optional[bool] = Field(None, alias="varyingairdensity") research_wind_eachstep: Optional[int] = Field(None, alias="wind_eachstep") @@ -667,15 +667,13 @@ class ResearchTime(Time): class Comments(Time.Comments): research_timestepanalysis: Optional[str] = Field( - "0=no, 1=see file *.steps.", alias="timestepanalysis" + "Write time steps analysis file *.steps (0: no, 1: yes).", + alias="timestepanalysis", ) research_autotimestepvisc: Optional[str] = Field( "0 = no, 1 = yes (Time limitation based on explicit diffusive term).", alias="autotimestepvisc", ) - research_dtfacmax: Optional[str] = Field( - "Max timestep increase factor ( ).", alias="dtfacmax" - ) research_tstarttlfsmo: Optional[str] = Field( "Start time of smoothing of boundary conditions (Tlfsmo) w.r.t. RefDate (in TUnit).", alias="tstarttlfsmo", @@ -683,9 +681,8 @@ class Comments(Time.Comments): comments: Comments = Comments() - research_timestepanalysis: Optional[int] = Field(None, alias="timestepanalysis") + research_timestepanalysis: Optional[bool] = Field(None, alias="timestepanalysis") research_autotimestepvisc: Optional[bool] = Field(None, alias="autotimestepvisc") - research_dtfacmax: Optional[float] = Field(None, alias="dtfacmax") research_tstarttlfsmo: Optional[float] = Field(None, alias="tstarttlfsmo") @@ -737,10 +734,7 @@ class Comments(Output.Comments): research_wrimap_nearfield: Optional[str] = Field( "Write near field parameters (1: yes, 0: no).", alias="wrimap_nearfield" ) - research_velocitymagnitudeclasses: Optional[str] = Field( - "Class map's list of class values for velocity magnitudes.", - alias="velocitymagnitudeclasses", - ) + research_writedfminterpretedvalues: Optional[str] = Field( "Write DFMinterpretedvalues (1: yes, 0: no).", alias="writedfminterpretedvalues", @@ -752,9 +746,6 @@ class Comments(Output.Comments): "Lump MBA boundary mass balance terms (1: yes, 0: no).", alias="mbalumpboundaries", ) - research_writepart_domain: Optional[str] = Field( - "Write partition domain info. for postprocessing.", alias="writepart_domain" - ) research_waqhoraggr: Optional[str] = Field( "DELWAQ output horizontal aggregation file (*.dwq).", alias="waqhoraggr" ) @@ -769,10 +760,6 @@ class Comments(Output.Comments): research_mbainterval: Optional[str] = Field( "Mass balance area output interval (s).", alias="mbainterval" ) - research_velocitydirectionclassesinterval: Optional[str] = Field( - "Class map's step size of class values for velocity direction.", - alias="velocitydirectionclassesinterval", - ) research_wrirst_bnd: Optional[str] = Field( "Write waterlevel", alias="wrirst_bnd" ) @@ -829,9 +816,6 @@ class Comments(Output.Comments): None, alias="mbalumpsourcesinks" ) research_wrimap_nearfield: Optional[bool] = Field(None, alias="wrimap_nearfield") - research_velocitymagnitudeclasses: Optional[List[float]] = Field( - None, alias="velocitymagnitudeclasses" - ) research_writedfminterpretedvalues: Optional[bool] = Field( None, alias="writedfminterpretedvalues" ) @@ -839,7 +823,6 @@ class Comments(Output.Comments): None, alias="deleteobspointsoutsidegrid" ) research_mbalumpboundaries: Optional[bool] = Field(None, alias="mbalumpboundaries") - research_writepart_domain: Optional[bool] = Field(None, alias="writepart_domain") research_waqhoraggr: Optional[DiskOnlyFileModel] = Field(None, alias="waqhoraggr") research_writedetailedtimers: Optional[bool] = Field( None, alias="writedetailedtimers" @@ -848,9 +831,6 @@ class Comments(Output.Comments): None, alias="metadatafile" ) research_mbainterval: Optional[float] = Field(None, alias="mbainterval") - research_velocitydirectionclassesinterval: Optional[int] = Field( - None, alias="velocitydirectionclassesinterval" - ) research_wrirst_bnd: Optional[bool] = Field(None, alias="wrirst_bnd") research_generateuuid: Optional[bool] = Field(None, alias="generateuuid") research_timesplitinterval: Optional[str] = Field(None, alias="timesplitinterval") @@ -867,10 +847,6 @@ class Comments(Output.Comments): None, alias="wrimap_trachytopes" ) - _split_to_list = get_split_string_on_delimiter_validator( - "research_velocitymagnitudeclasses", - ) - class ResearchProcesses(Processes): """An extended [processes] section that includes highly experimental research keywords.""" diff --git a/tests/data/input/e02/f006_external_forcing/c063_rain_tim/rainschematic.mdu b/tests/data/input/e02/f006_external_forcing/c063_rain_tim/rainschematic.mdu index 08465c386..d47c7f942 100644 --- a/tests/data/input/e02/f006_external_forcing/c063_rain_tim/rainschematic.mdu +++ b/tests/data/input/e02/f006_external_forcing/c063_rain_tim/rainschematic.mdu @@ -74,7 +74,6 @@ Jbasqbnddownwindhs = 0 # 0 cstbnd = 0 # Delft-3D type velocity treatment near boundaries for small coastal models (1) or not (0) Maxitverticalforestersal = 100 # 0 : no vertical filter, > 0 = Max nr of iterations Maxitverticalforestertem = 0 # 0 : no vertical filter for temp, > 0 = Max nr of iterations -Jaorgsethu = 1 # Velocity reconstruction scheme (0 : setumod, sethu, setau sequence, 1 : sethu, setau, setumod sequence (standard)) Turbulencemodel = 3 # 0=no, 1 = constant, 2 = algebraic, 3 = k-eps, 4 = k-tau Turbulenceadvection = 3 # 0=no, 3 = hor. expl., vert. impl. AntiCreep = 0 # Include anti-creep calculation, (0=no, 1=yes) @@ -87,7 +86,6 @@ UnifFrictCoef = 0.1 # U UnifFrictType = 2 # 0=Chezy, 1=Manning, 2=White Colebrook, 3=idem, WAQUA style UnifFrictCoef1D = 2.3d-2 # Uniform friction coefficient in 1D links, 0=no friction UnifFrictCoefLin = 0. # Uniform linear friction coefficient for ocean models (m/s), 0=no -Umodlin = 0 # Use 1 for linear friction umod, for ifrctyp=4,5,6 Vicouv = 0.0 # Uniform horizontal eddy viscosity (m2/s) Dicouv = 0.0000000 # Uniform horizontal eddy diffusivity (m2/s) Vicoww = 0. # Uniform vertical eddy viscosity (m2/s) @@ -116,7 +114,6 @@ Secchidepth = 1. # W Stanton = -1. # Coefficient for convective heat flux ( ) , if negative, Cd wind*abs(Stanton) Dalton = -1. # Coefficient for evaporative heat flux ( ), if negative, Cd wind*abs(Dalton) SecondaryFlow = 0 # Secondary flow (0=no, 1=yes) -EffectSpiral = 0. # Factor for weighing the effect of the spiral flow intensity on transport angle BetaSpiral = 0. # Factor for weighing the effect of the spiral flow on flow dispersion stresses [grw] @@ -135,7 +132,6 @@ Gapres = 101325.0000000 # O [waves] Wavemodelnr = 0 # Wave model nr, 0=no, 1=fetch/depth limited hurdlestive, 2=youngverhagen, 3 = Delft3D-WAVE, 4=wave group forcing -WaveNikuradse = 1.d-2 # Wave friction Nikuradse ks coefficient, used in Krone Swart, e.g. 0.01 m Rouwav = # Friction model for wave induced shear stress Gammax = 1. # Maximum wave height/water depth ratio @@ -169,11 +165,9 @@ XLSInterval = # I MapFile = # *_map.nc Map file in NetCDF format. MapInterval = 0.0 # Map file output, given as "interval" "start period" "end period" (s) RstInterval = 0.0 # Restart file output, given as "interval" "start period" "end period" (s) -S1incinterval = # Interval (m) in incremental file for waterlevels S1 WaqFileBase = # Basename (without extension) for all Delwaq files to be written. WaqInterval = # Interval (in s) between Delwaq file outputs StatsInterval = # Interval (in s) between simulation statistics output. -Writebalancefile = 0 # Write Balancefile, 1=yes, 0=no TimingsInterval = # Timings output interval TimeSplitInterval = 0X # Time splitting interval, after which a new output file is started. value+unit, e.g. '1 M', valid units: Y,M,D,h,m,s. MapFormat = 4 # Map file format, 1: netCDF, 2: Tecplot, 3: netCFD and Tecplot, 4: NetCDF-UGRID diff --git a/tests/data/input/e02/f006_external_forcing/c069_rain_bc/rainschematic.mdu b/tests/data/input/e02/f006_external_forcing/c069_rain_bc/rainschematic.mdu index 71c43a564..f17a1c31a 100644 --- a/tests/data/input/e02/f006_external_forcing/c069_rain_bc/rainschematic.mdu +++ b/tests/data/input/e02/f006_external_forcing/c069_rain_bc/rainschematic.mdu @@ -50,7 +50,6 @@ TimeStepType = 2 # Limtyphu = 0 # Limiter type for waterdepth in continuity eq., 0=no, 1=minmod,2=vanLeer,3=Kooren,4=Monotone Central Limtypmom = 4 # Limiter type for cell center advection velocity, 0=no, 1=minmod,2=vanLeer,3=Kooren,4=Monotone Central Limtypsa = 4 # Limiter type for salinity transport, 0=no, 1=minmod,2=vanLeer,3=Kooren,4=Monotone Central -TransportMethod = 1 # Transport method, 0=Herman method, 1=Sander method Vertadvtypsal = 5 # Vertical advection type for salinity, 0=No, 1=UpwexpL, 2=Centralexpl, 3=UpwimpL, 4=CentraLimpL, 5=4 but 3 for neg. stratif., 6=higher order expl, no forester Horadvtypzlayer = 0 # Horizontal advection treatment zlayer, 1=default, 2 = Sigma like Icgsolver = 4 # Solver type , 1 = sobekGS_OMP, 2 = sobekGS_OMPthreadsafe, 3 = sobekGS, 4 = sobekGS + Saadilud, 5 = parallel/global Saad, 6 = parallel/Petsc, 7 = parallel/GS @@ -72,7 +71,6 @@ Jbasqbnddownwindhs = 0 # 0 cstbnd = 0 # Delft-3D type velocity treatment near boundaries for small coastal models (1) or not (0) Maxitverticalforestersal = 100 # 0 : no vertical filter, > 0 = Max nr of iterations Maxitverticalforestertem = 0 # 0 : no vertical filter for temp, > 0 = Max nr of iterations -Jaorgsethu = 1 # Velocity reconstruction scheme (0 : setumod, sethu, setau sequence, 1 : sethu, setau, setumod sequence (standard)) Turbulencemodel = 3 # 0=no, 1 = constant, 2 = algebraic, 3 = k-eps, 4 = k-tau Turbulenceadvection = 3 # 0=no, 3 = hor. expl., vert. impl. AntiCreep = 0 # Include anti-creep calculation, (0=no, 1=yes) @@ -85,7 +83,6 @@ UnifFrictCoef = 0.1 # U UnifFrictType = 2 # 0=Chezy, 1=Manning, 2=White Colebrook, 3=idem, WAQUA style UnifFrictCoef1D = 2.3d-2 # Uniform friction coefficient in 1D links, 0=no friction UnifFrictCoefLin = 0. # Uniform linear friction coefficient for ocean models (m/s), 0=no -Umodlin = 0 # Use 1 for linear friction umod, for ifrctyp=4,5,6 Vicouv = 0.0 # Uniform horizontal eddy viscosity (m2/s) Dicouv = 0.0000000 # Uniform horizontal eddy diffusivity (m2/s) Vicoww = 0. # Uniform vertical eddy viscosity (m2/s) @@ -114,7 +111,6 @@ Secchidepth = 1. # W Stanton = -1. # Coefficient for convective heat flux ( ) , if negative, Cd wind*abs(Stanton) Dalton = -1. # Coefficient for evaporative heat flux ( ), if negative, Cd wind*abs(Dalton) SecondaryFlow = 0 # Secondary flow (0=no, 1=yes) -EffectSpiral = 0. # Factor for weighing the effect of the spiral flow intensity on transport angle BetaSpiral = 0. # Factor for weighing the effect of the spiral flow on flow dispersion stresses [grw] @@ -133,7 +129,6 @@ Gapres = 101325.0000000 # O [waves] Wavemodelnr = 0 # Wave model nr, 0=no, 1=fetch/depth limited hurdlestive, 2=youngverhagen, 3 = Delft3D-WAVE, 4=wave group forcing -WaveNikuradse = 1.d-2 # Wave friction Nikuradse ks coefficient, used in Krone Swart, e.g. 0.01 m Rouwav = # Friction model for wave induced shear stress Gammax = 1. # Maximum wave height/water depth ratio @@ -167,7 +162,6 @@ XLSInterval = # I MapFile = # *_map.nc Map file in NetCDF format. MapInterval = 0.0 # Map file output, given as "interval" "start period" "end period" (s) RstInterval = 0.0 # Restart file output, given as "interval" "start period" "end period" (s) -S1incinterval = # Interval (m) in incremental file for waterlevels S1 WaqFileBase = # Basename (without extension) for all Delwaq files to be written. WaqInterval = # Interval (in s) between Delwaq file outputs StatsInterval = # Interval (in s) between simulation statistics output. diff --git a/tests/data/input/e02/f152_1d2d_projectmodels_rhu/c04_DHydamo-MGB-initialisation/fm/moergestels_broek.mdu b/tests/data/input/e02/f152_1d2d_projectmodels_rhu/c04_DHydamo-MGB-initialisation/fm/moergestels_broek.mdu index 9a6e480c6..fc6d91d82 100644 --- a/tests/data/input/e02/f152_1d2d_projectmodels_rhu/c04_DHydamo-MGB-initialisation/fm/moergestels_broek.mdu +++ b/tests/data/input/e02/f152_1d2d_projectmodels_rhu/c04_DHydamo-MGB-initialisation/fm/moergestels_broek.mdu @@ -11,9 +11,7 @@ PathsRelativeToParent = 0 # Whether or not (1/0) t [geometry] NetFile = moergestels_broek_net.nc# Unstructured grid file *_net.nc -BathymetryFile = -OneDNetworkFile = # 1d networkfile -BedlevelFile = # street_level.xyz , Bedlevels points file e.g. *.xyz, only needed for bedlevtype not equal 3 +BathymetryFile = DryPointsFile = # Dry points file *.xyz (third column dummy z values), or dry areas polygon file *.pol (third column 1/-1: inside/outside) WaterLevIniFile = # Initial water levels sample file *.xyz LandBoundaryFile = structures.ldb # Land boundaries file *.ldb, used for visualization diff --git a/tests/data/input/research/mdu_with_research_keywords_from_dia_file_2024.03_release.mdu b/tests/data/input/research/mdu_with_research_keywords_from_dia_file_2024.03_release.mdu index e01bd008a..26e4b510c 100644 --- a/tests/data/input/research/mdu_with_research_keywords_from_dia_file_2024.03_release.mdu +++ b/tests/data/input/research/mdu_with_research_keywords_from_dia_file_2024.03_release.mdu @@ -222,7 +222,6 @@ UnifFrictCoef1D = 2.3d-2 # Uniform fricti UnifFrictCoef1D2D = 2.3d-2 # Uniform friction coefficient in 1D links (0: no friction) UnifFrictCoefLin = 0. # Uniform linear friction coefficient (0: no friction) UnifFrictCoef1DgrLay = 5.d-2 # Uniform ground layer friction coefficient for ocean models (m/s) (0: no friction) -Umodlin = 0. # Linear friction umod, for ifrctyp=4,5,6 Vicouv = 1. # Uniform horizontal eddy viscosity (m2/s) Dicouv = 1. # Uniform horizontal eddy diffusivity (m2/s) Vicoww = 5.d-5 # Uniform vertical eddy viscosity (m2/s) @@ -350,7 +349,7 @@ AutoTimestepNoQout = 1 # 0 = no, 1 = ye Tunit = S # Time unit for start/stop times (D, H, M or S) TStart = 410227200. # Start time w.r.t. RefDate (in TUnit) TStop = 410270400. # Stop time w.r.t. RefDate (in TUnit) -TStartTlfsmo = 0. # Start time of smoothing of boundary conditions (Tlfsmo) w.r.t. RefDate (in TUnit) +TStartTlfsmo = 1.1 # Start time of smoothing of boundary conditions (Tlfsmo) w.r.t. RefDate (in TUnit) Startdatetime = 20140101000000 # Computation Startdatetime (yyyymmddhhmmss), when specified, overrides Tstart Stopdatetime = 20140101120000 # Computation Stopdatetime (yyyymmddhhmmss), when specified, overrides Tstop UpdateRoughnessInterval = 86400. # Update interval for time dependent roughness parameters (in s) diff --git a/tests/data/reference/fm/special_3d_settings.mdu b/tests/data/reference/fm/special_3d_settings.mdu index 2ab0bfda7..d4201a0cb 100644 --- a/tests/data/reference/fm/special_3d_settings.mdu +++ b/tests/data/reference/fm/special_3d_settings.mdu @@ -7,6 +7,7 @@ program = D-Flow FM # Program version = 1.2.100.66357 # Version number of computational kernel autoStart = 0 # Autostart simulation after loading MDU or not (0=no, 1=autostart, 2=autostartstop). pathsRelativeToParent = 0 # Default: 0. Whether or not (1/0) to resolve file names (e.g. inside the *.ext file) relative to their direct parent, instead of to the toplevel MDU working dir. +guiVersion = # DeltaShell FM suite version. [Geometry] netFile = SEA_coarse_net.nc # Unstructured grid file *_net.nc @@ -81,7 +82,7 @@ uniformTyp1DRoofGutterPipes = -2 # Uniform cross section type uniformWidth1DRoofGutterPipes = 0.1 # Uniform width for roof gutter pipes [m]. [VolumeTables] -useVolumeTables = 0 # Use volume tables for 1D grid cells (1: yes, 0 = no). +useVolumeTables = 0 # Use 1D volume tables (0: no, 1: yes). increment = 0.2 # The height increment for the volume tables [m]. useVolumeTableFile = 0 # Read and write the volume table from/to file (1: yes, 0= no). @@ -145,6 +146,8 @@ checkerboardMonitor = 0 # Flag for checkerboarding output on history velocityWarn = 0.0 # Warning level [m/s] on normal velocity(<= 0: no check). advecCorrection1D2D = 0 # Advection correction of 1D2D link volume (0: regular advection, 1: link volume au*dx, 2: advection on 1D2D switched off.) fixedWeirTalud = 4.0 # Uniform talud slope of fixed weirs. +lateral_fixedweir_umin = 0.0 # Minimal velocity threshold for weir losses in iterative lateral 1d2d weir coupling. +jasfer3D = 0 # Corrections for spherical coordinates (0: no, 1: yes). [Physics] unifFrictCoef = 0.028 # Uniform friction coefficient (0: no friction) @@ -226,6 +229,7 @@ tStop = 86400.0 # Stop time w.r.t. RefDate [TUnit]. startDateTime = 19980101000000 # Start date time (yyyymmddHHMMSS) stopDateTime = 19980110000000 # Stop date time (yyyymmddHHMMSS) updateRoughnessInterval = 86400.0 # Update interval for time dependent roughness parameters [s]. +Dtfacmax = 1.1 # Max timestep increase factor in successive time steps. [Restart] restartFile = # Restart netcdf-file, either *_rst.nc or *_map.nc @@ -337,6 +341,9 @@ wrimap_rain = 1 wrimap_wind = 1 # Write wind velocities to map file (1: yes, 0: no) wrimap_windstress = 0 # Write wind stress to map file (1: yes, 0: no) wrimap_airdensity = 0 # Write air density to map file, (1:yes, 0:no). +wrimap_calibration = 1 # Write roughness calibration factors to map file. +wrimap_salinity = 1 # Write salinity to map file. +wrimap_temperature = 1 # Write temperature to map file. writek_CdWind = 0 # Write wind friction coeffs to tek file (1: yes, 0: no) wrimap_heat_fluxes = 1 # Write heat fluxes to map file (1: yes, 0: no) wrimap_wet_waterDepth_threshold = 2e-05 # Waterdepth threshold above which a grid point counts as 'wet'. Defaults to 0.2·Epshu. It is used for Wrimap_time_water_on_ground, Wrimap_waterdepth_on_ground and Wrimap_volume_on_ground. @@ -362,7 +369,7 @@ waqInterval = 0.0 statsInterval = 3600.0 # Screen step output interval in seconds simulation time, if negative in seconds wall clock time timingsInterval = 0.0 # Timings statistics output interval richardsonOnOutput = 0 # Write Richardson number, (1: yes, 0: no). -wrimap_input_dt = 0 # Write output to map file every computational timestep, between start and stop time from MapInterval, (1: yes, 0: no). +wrimap_every_dt = 0 # Write output to map file every computational timestep, between start and stop time from MapInterval, (1: yes, 0: no). wrimap_input_roughness = 0 # Write chezy input roughness on flow links to map file, (1: yes, 0: no). wrimap_flowarea_au = 1 # Write flow areas au to map file (1: yes, 0: no) wrimap_flow_flux_q1_main = 1 # Write flow flux in main channel to map file (1: yes, 0: no) @@ -379,6 +386,9 @@ wrimap_interception = 1 wrimap_volume1 = 1 # Write volumes to map file (1: yes, 0: no) wrimap_ancillary_variables = 1 # Write ancillary_variables attributes to map file (1: yes, 0: no) wrimap_chezy_on_flow_links = 0 # Write chezy roughness on flow links to map file, (1: yes, 0: no) +writepart_domain = 1 # Write partition domain info. for postprocessing (0: no, 1: yes). +VelocityDirectionClassesInterval = 0.0 # Class map's step size of class values for velocity direction. +VelocityMagnitudeClasses = 0.0 # Class map's list of class values for velocity magnitudes. [Calibration] UseCalibration = 0 # Activate calibration factor friction multiplier (1 = yes, 0 = no) diff --git a/tests/dflowfm/test_research.py b/tests/dflowfm/test_research.py index 509dba90c..e7c93ac62 100644 --- a/tests/dflowfm/test_research.py +++ b/tests/dflowfm/test_research.py @@ -1,3 +1,5 @@ +from pathlib import Path + import pytest from hydrolib.core.dflowfm.research.models import ( @@ -48,6 +50,12 @@ def test_load_model_with_research_keywords_as_researchfmmodel(self): assert model.sediment.research_implicitfallvelocity == 1 assert model.wind.research_wind_eachstep == 0 assert model.waves.research_threedwaveboundarylayer == 1 - assert model.time.research_dtfacmax == pytest.approx(1.1) + assert model.time.research_tstarttlfsmo == pytest.approx(1.1) assert model.trachytopes.research_trtmnh == pytest.approx(0.1) assert model.output.research_mbainterval == pytest.approx(0.0) + + def test_can_save_and_load_research_model_from_scratch_without_errors(self): + file_mdu = Path("mdu.mdu") + mdu = ResearchFMModel() + mdu.save(file_mdu) + _ = ResearchFMModel(file_mdu) From 479c47f565bc114f1b66adf0306af4cc051965cc Mon Sep 17 00:00:00 2001 From: veenstrajelmer <60435591+veenstrajelmer@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:23:14 +0200 Subject: [PATCH 2/4] chore: Corrected default mdu.wind.rhoair value to value in manual and kernel code (#667) refs: #653 --- hydrolib/core/dflowfm/mdu/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hydrolib/core/dflowfm/mdu/models.py b/hydrolib/core/dflowfm/mdu/models.py index 49bd2aeb8..c0d785e75 100644 --- a/hydrolib/core/dflowfm/mdu/models.py +++ b/hydrolib/core/dflowfm/mdu/models.py @@ -712,7 +712,7 @@ class Comments(INIBasedModel.Comments): windspeedbreakpoints: List[float] = Field( [0.0, 100.0], alias="windSpeedBreakpoints" ) - rhoair: float = Field(1.205, alias="rhoAir") + rhoair: float = Field(1.2, alias="rhoAir") relativewind: float = Field(0.0, alias="relativeWind") windpartialdry: bool = Field(True, alias="windPartialDry") pavbnd: float = Field(0.0, alias="pavBnd") From aa0af4cbedbdd2633fb5050916cad6395d8a21ae Mon Sep 17 00:00:00 2001 From: Tim van den Aardweg <71257004+tim-vd-aardweg@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:24:53 +0200 Subject: [PATCH 3/4] feat: Don't write keywords with None values (#663) refs: #661 --- hydrolib/core/dflowfm/ini/models.py | 48 ++++++++++++++++- hydrolib/core/dflowfm/mdu/models.py | 52 +++++++++++-------- .../with_optional_sections.mdu | 1 - .../data/reference/fm/special_3d_settings.mdu | 12 ++--- tests/dflowfm/ini/test_ini.py | 38 +++++++++++++- tests/dflowfm/test_mdu.py | 1 - tests/dflowfm/test_research.py | 26 ++++++++++ 7 files changed, 141 insertions(+), 37 deletions(-) diff --git a/hydrolib/core/dflowfm/ini/models.py b/hydrolib/core/dflowfm/ini/models.py index e5a30a22d..eda022101 100644 --- a/hydrolib/core/dflowfm/ini/models.py +++ b/hydrolib/core/dflowfm/ini/models.py @@ -3,7 +3,18 @@ from enum import Enum from math import isnan from re import compile -from typing import Any, Callable, List, Literal, Optional, Set, Type, Union +from typing import ( + Any, + Callable, + List, + Literal, + Optional, + Set, + Type, + Union, + get_args, + get_origin, +) from pydantic.v1 import Extra, Field, root_validator from pydantic.v1.class_validators import validator @@ -206,7 +217,7 @@ def _to_section( ) -> Section: props = [] for key, value in self: - if key in self._exclude_fields(): + if not self._should_be_serialized(key, value): continue field_key = key @@ -221,6 +232,39 @@ def _to_section( props.append(prop) return Section(header=self._header, content=props) + def _should_be_serialized(self, key: str, value: Any) -> bool: + if key in self._exclude_fields(): + return False + + field = self.__fields__.get(key) + if not field: + return value is not None + + field_type = field.type_ + if self._is_union(field_type): + return value is not None or self._union_has_filemodel(field_type) + + if self._is_list(field_type): + field_type = get_args(field_type)[0] + + return self._value_is_not_none_or_type_is_filemodel(field_type, value) + + @staticmethod + def _is_union(field_type: type) -> bool: + return get_origin(field_type) is Union + + @staticmethod + def _union_has_filemodel(field_type: type) -> bool: + return any(issubclass(arg, FileModel) for arg in get_args(field_type)) + + @staticmethod + def _is_list(field_type: type) -> bool: + return get_origin(field_type) is List + + @staticmethod + def _value_is_not_none_or_type_is_filemodel(field_type: type, value: Any) -> bool: + return value is not None or issubclass(field_type, FileModel) + Datablock = List[List[Union[float, str]]] diff --git a/hydrolib/core/dflowfm/mdu/models.py b/hydrolib/core/dflowfm/mdu/models.py index c0d785e75..2fd84e587 100644 --- a/hydrolib/core/dflowfm/mdu/models.py +++ b/hydrolib/core/dflowfm/mdu/models.py @@ -371,7 +371,7 @@ class Comments(INIBasedModel.Comments): maxvelocity: float = Field(0.0, alias="maxVelocity") waterlevelwarn: float = Field(0.0, alias="waterLevelWarn") tspinupturblogprof: float = Field(0.0, alias="tSpinUpTurbLogProf") - fixedweirtopfrictcoef: Optional[float] = Field(None, alias="fixedWeirTopFrictCoef") + fixedweirtopfrictcoef: Optional[float] = Field(-999, alias="fixedWeirTopFrictCoef") fixedweir1d2d_dx: float = Field(50.0, alias="fixedWeir1D2D_dx") junction1d: int = Field(0, alias="junction1D") fixedweirtopwidth: float = Field(3.0, alias="fixedWeirTopWidth") @@ -600,7 +600,7 @@ class Comments(INIBasedModel.Comments): idensform: int = Field(2, alias="idensform") ag: float = Field(9.81, alias="ag") tidalforcing: bool = Field(False, alias="tidalForcing") - itcap: Optional[float] = Field(None, alias="ITcap") + itcap: Optional[float] = Field(0.0, alias="ITcap") doodsonstart: float = Field(55.565, alias="doodsonStart") doodsonstop: float = Field(375.575, alias="doodsonStop") doodsoneps: float = Field(0.0, alias="doodsonEps") @@ -649,7 +649,7 @@ class Comments(INIBasedModel.Comments): ) _header: Literal["Sediment"] = "Sediment" - sedimentmodelnr: Optional[int] = Field(alias="Sedimentmodelnr") + sedimentmodelnr: Optional[int] = Field(0, alias="Sedimentmodelnr") morfile: DiskOnlyFileModel = Field( default_factory=lambda: DiskOnlyFileModel(None), alias="MorFile" ) @@ -832,13 +832,13 @@ class Comments(INIBasedModel.Comments): dtnodal: float = Field(21600.0, alias="dtNodal") dtmax: float = Field(30.0, alias="dtMax") dtinit: float = Field(1.0, alias="dtInit") - autotimestep: Optional[int] = Field(None, alias="autoTimestep") + autotimestep: Optional[int] = Field(1, alias="autoTimestep") autotimestepnostruct: bool = Field(False, alias="autoTimestepNoStruct") autotimestepnoqout: bool = Field(True, alias="autoTimestepNoQout") tstart: float = Field(0.0, alias="tStart") tstop: float = Field(86400.0, alias="tStop") - startdatetime: Optional[str] = Field(None, alias="startDateTime") - stopdatetime: Optional[str] = Field(None, alias="stopDateTime") + startdatetime: Optional[str] = Field("", alias="startDateTime") + stopdatetime: Optional[str] = Field("", alias="stopDateTime") updateroughnessinterval: float = Field(86400.0, alias="updateRoughnessInterval") dtfacmax: float = Field(1.1, alias="Dtfacmax") @@ -877,7 +877,7 @@ class Comments(INIBasedModel.Comments): restartfile: DiskOnlyFileModel = Field( default_factory=lambda: DiskOnlyFileModel(None), alias="restartFile" ) - restartdatetime: Optional[str] = Field(None, alias="restartDateTime") + restartdatetime: Optional[str] = Field("", alias="restartDateTime") @validator("restartdatetime") def _validate_datetime(cls, value, field): @@ -991,10 +991,10 @@ class Comments(INIBasedModel.Comments): _header: Literal["Trachytopes"] = "Trachytopes" trtrou: str = Field("N", alias="trtRou") # TODO bool - trtdef: Optional[Path] = Field(None, alias="trtDef") - trtl: Optional[Path] = Field(None, alias="trtL") + trtdef: Optional[Path] = Field("", alias="trtDef") + trtl: Optional[Path] = Field("", alias="trtL") dttrt: float = Field(60.0, alias="dtTrt") - trtmxr: Optional[int] = Field(None, alias="trtMxR") + trtmxr: Optional[int] = Field(8, alias="trtMxR") ObsFile = Union[XYNModel, ObservationPointModel] @@ -1532,8 +1532,8 @@ class Comments(INIBasedModel.Comments): wrishp_enc: bool = Field(False, alias="wrishp_enc") wrishp_src: bool = Field(False, alias="wrishp_src") wrishp_pump: bool = Field(False, alias="wrishp_pump") - outputdir: Optional[Path] = Field(None, alias="outputDir") - waqoutputdir: Optional[Path] = Field(None, alias="waqOutputDir") + outputdir: Optional[Path] = Field("", alias="outputDir") + waqoutputdir: Optional[Path] = Field("", alias="waqOutputDir") flowgeomfile: DiskOnlyFileModel = Field( default_factory=lambda: DiskOnlyFileModel(None), alias="flowGeomFile" ) @@ -1822,7 +1822,10 @@ class Comments(INIBasedModel.Comments): partitionfile: Optional[str] = Field( "<*_part.pol>, polyline(s) x, y.", alias="partitionFile" ) - uniformwidth1d: Optional[str] = Field(None, alias="uniformWidth1D") + uniformwidth1d: Optional[str] = Field( + "Uniform width for channel profiles not specified by profloc", + alias="uniformWidth1D", + ) dxwuimin2d: Optional[str] = Field( "Smallest fraction dx/wu , set dx > Dxwuimin2D*wu", alias="dxWuiMin2D", @@ -2060,9 +2063,9 @@ class Comments(INIBasedModel.Comments): numtopsig: int = Field(0, alias="numTopSig") numtopsiguniform: bool = Field(True, alias="numTopSigUniform") sigmagrowthfactor: float = Field(1.0, alias="sigmaGrowthFactor") - dztop: Optional[float] = Field(None, alias="dzTop") - floorlevtoplay: Optional[float] = Field(None, alias="floorLevTopLay") - dztopuniabovez: Optional[float] = Field(None, alias="dzTopUniAboveZ") + dztop: Optional[float] = Field(-999, alias="dzTop") + floorlevtoplay: Optional[float] = Field(-999, alias="floorLevTopLay") + dztopuniabovez: Optional[float] = Field(-999, alias="dzTopUniAboveZ") keepzlayeringatbed: int = Field(2, alias="keepZLayeringAtBed") dxdoubleat1dendnodes: bool = Field(True, alias="dxDoubleAt1DEndNodes") changevelocityatstructures: bool = Field(False, alias="changeVelocityAtStructures") @@ -2167,12 +2170,17 @@ class GroundWater(INIBasedModel): """ class Comments(INIBasedModel.Comments): - groundwater: Optional[str] = Field(None, alias="GroundWater") + groundwater: Optional[str] = Field( + "0=No (horizontal) groundwater flow, 1=With groundwater flow", + alias="GroundWater", + ) infiltrationmodel: Optional[str] = Field( "Infiltration method (0: No infiltration, 1: Interception layer, 2: Constant infiltration capacity, 3: model unsaturated/saturated (with grw), 4: Horton).", alias="Infiltrationmodel", ) - hinterceptionlayer: Optional[str] = Field(None, alias="Hinterceptionlayer") + hinterceptionlayer: Optional[str] = Field( + "Intercept this amount of rain (m)", alias="Hinterceptionlayer" + ) unifinfiltrationcapacity: Optional[str] = Field( "Uniform maximum infiltration capacity [m/s].", alias="UnifInfiltrationCapacity", @@ -2204,15 +2212,15 @@ class Comments(INIBasedModel.Comments): infiltrationmodel: Optional[InfiltrationMethod] = Field( InfiltrationMethod.NoInfiltration, alias="Infiltrationmodel" ) - hinterceptionlayer: Optional[float] = Field(None, alias="Hinterceptionlayer") + hinterceptionlayer: Optional[float] = Field(0.0, alias="Hinterceptionlayer") unifinfiltrationcapacity: Optional[float] = Field( 0.0, alias="UnifInfiltrationCapacity" ) conductivity: Optional[float] = Field(0.0, alias="Conductivity") h_aquiferuni: Optional[float] = Field(20.0, alias="h_aquiferuni") - bgrwuni: Optional[float] = Field(None, alias="bgrwuni") + bgrwuni: Optional[float] = Field(-999, alias="bgrwuni") h_unsatini: Optional[float] = Field(0.2, alias="h_unsatini") - sgrwini: Optional[float] = Field(None, alias="sgrwini") + sgrwini: Optional[float] = Field(-999, alias="sgrwini") class ProcessFluxIntegration(IntEnum): @@ -2255,7 +2263,6 @@ class Comments(INIBasedModel.Comments): "Waq processes time step [s]. Must be a multiple of DtUser. If DtProcesses is negative, water quality processes are calculated with every hydrodynamic time step.", alias="DtProcesses", ) - dtmassbalance: Optional[str] = Field(None, alias="DtMassBalance") processfluxintegration: Optional[str] = Field( "Process fluxes integration option (1: WAQ, 2: D-Flow FM).", alias="ProcessFluxIntegration", @@ -2293,7 +2300,6 @@ class Comments(INIBasedModel.Comments): ) thetavertical: Optional[float] = Field(0.0, alias="ThetaVertical") dtprocesses: Optional[float] = Field(0.0, alias="DtProcesses") - dtmassbalance: Optional[float] = Field(0.0, alias="DtMassBalance") processfluxintegration: Optional[ProcessFluxIntegration] = Field( ProcessFluxIntegration.WAQ, alias="ProcessFluxIntegration" ) diff --git a/tests/data/input/dflowfm_individual_files/with_optional_sections.mdu b/tests/data/input/dflowfm_individual_files/with_optional_sections.mdu index eb91dc289..6cef0edb9 100644 --- a/tests/data/input/dflowfm_individual_files/with_optional_sections.mdu +++ b/tests/data/input/dflowfm_individual_files/with_optional_sections.mdu @@ -384,7 +384,6 @@ AdditionalHistoryOutputFile = # extra history StatisticsFile = # statistics file ThetaVertical = 0. # theta vertical for waq DtProcesses = 0. # waq processes time step -DtMassBalance = 0. # waq mass balance output time step ProcessFluxIntegration = 1 # Process fluxes integration option (1: WAQ, 2: D-Flow FM) Wriwaqbot3Doutput = 0 # Write 3D water quality bottom variables (1: yes, 0: no) VolumeDryThreshold = 1.d-3 diff --git a/tests/data/reference/fm/special_3d_settings.mdu b/tests/data/reference/fm/special_3d_settings.mdu index d4201a0cb..5f3a3fd12 100644 --- a/tests/data/reference/fm/special_3d_settings.mdu +++ b/tests/data/reference/fm/special_3d_settings.mdu @@ -7,7 +7,6 @@ program = D-Flow FM # Program version = 1.2.100.66357 # Version number of computational kernel autoStart = 0 # Autostart simulation after loading MDU or not (0=no, 1=autostart, 2=autostartstop). pathsRelativeToParent = 0 # Default: 0. Whether or not (1/0) to resolve file names (e.g. inside the *.ext file) relative to their direct parent, instead of to the toplevel MDU working dir. -guiVersion = # DeltaShell FM suite version. [Geometry] netFile = SEA_coarse_net.nc # Unstructured grid file *_net.nc @@ -32,7 +31,7 @@ profDefFile = # <*_profdefinition.def>) def profDefXyzFile = # <*_profdefinition.def>) definition for all profile nrs. manholeFile = # File containing manholes (e.g. <*.dat>). partitionFile = # <*_part.pol>, polyline(s) x, y. -uniformWidth1D = 2.0 +uniformWidth1D = 2.0 # Uniform width for channel profiles not specified by profloc dxWuiMin2D = 0.1 # Smallest fraction dx/wu , set dx > Dxwuimin2D*wu, Default = 0.1 waterLevIni = 0.0 # Initial water level at missing s0 values bedLevUni = 5.0 # Uniform bed level used at missing z values if BedlevType > 2 @@ -197,9 +196,9 @@ secondaryFlow = 0 # Secondary flow (0: no, 1: yes) betaSpiral = 0.0 # Weight factor of the spiral flow intensity on flow dispersion stresses (0d0 = disabled). [Sediment] -Sedimentmodelnr = # Sediment model nr, (0=no, 1=Krone, 2=SvR2007, 3=E-H, 4=MorphologyModule). -MorFile = # Morphology settings file (*.mor) -SedFile = # Sediment characteristics file (*.sed) +Sedimentmodelnr = 0 # Sediment model nr, (0=no, 1=Krone, 2=SvR2007, 3=E-H, 4=MorphologyModule). +MorFile = # Morphology settings file (*.mor) +SedFile = # Sediment characteristics file (*.sed) [Wind] iCdTyp = 4 # Wind drag coefficient type (1=Const; 2=Smith&Banke (2 pts); 3=S&B (3 pts); 4=Charnock 1955, 5=Hwang 2005, 6=Wuest 2005, 7=Hersbach 2010 (2 pts) @@ -238,9 +237,6 @@ restartDateTime = # Restart date and time (yyyymmddhhmmss) when restarting from [External Forcing] extForceFile = SEA_3D_3km_spatial.ext # Old format for external forcings file *.ext, link with tim/cmp-format boundary conditions specification extForceFileNew = # New format for external forcings file *.ext, link with bc-format boundary conditions specification -rainfall = # Include rainfall, (0=no, 1=yes). -qExt = # Include user Qin/out, externally provided, (0=no, 1=yes). -evaporation = # Include evaporation in water balance, (0=no, 1=yes). windExt = 1 # Include wind, externally provided, (0=no, 1=reserved for EC, 2=yes) [Hydrology] diff --git a/tests/dflowfm/ini/test_ini.py b/tests/dflowfm/ini/test_ini.py index 679cfb7c1..30c5a4838 100644 --- a/tests/dflowfm/ini/test_ini.py +++ b/tests/dflowfm/ini/test_ini.py @@ -1,10 +1,11 @@ import inspect from itertools import chain -from typing import Iterable, List, Optional, Sequence, Tuple, Union +from typing import Iterable, List, Optional, Union import pytest -from pydantic.v1 import ValidationError +from pydantic.v1 import Field, ValidationError +from hydrolib.core.basemodel import FileModel, ModelSaveSettings from hydrolib.core.dflowfm.ini.io_models import ( CommentBlock, ContentElement, @@ -13,6 +14,7 @@ Property, Section, ) +from hydrolib.core.dflowfm.ini.models import INIBasedModel from hydrolib.core.dflowfm.ini.parser import ( Parser, ParserConfig, @@ -1696,6 +1698,38 @@ def test_deserialize_serialize_should_give_the_same_result(self): assert result == input_str + def test_non_filemodel_keyword_with_none_value_does_not_get_added_to_section(self): + class TestINIBasedModel(INIBasedModel): + random_property: str = Field(None) + + config = INISerializerConfig() + settings = ModelSaveSettings() + model = TestINIBasedModel() + + section = model._to_section(config, settings) + + assert len(section.content) == 0 + + def test_filemodel_keyword_with_none_value_does_get_added_to_section(self): + class TestINIBasedModel(INIBasedModel): + random_property: FileModel = Field(None) + random_property2: Union[FileModel, str] = Field(None) + random_property3: List[FileModel] = Field(None) + + config = INISerializerConfig() + settings = ModelSaveSettings() + model = TestINIBasedModel() + + section = model._to_section(config, settings) + + assert len(section.content) == 3 + assert section.content[0].key == "random_property" + assert section.content[0].value == "" + assert section.content[1].key == "random_property2" + assert section.content[1].value == "" + assert section.content[2].key == "random_property3" + assert section.content[2].value == "" + def test_serialize_deserialize_should_give_the_same_result(): document = Document( diff --git a/tests/dflowfm/test_mdu.py b/tests/dflowfm/test_mdu.py index 9748a3b5e..4f3cd7c73 100644 --- a/tests/dflowfm/test_mdu.py +++ b/tests/dflowfm/test_mdu.py @@ -111,7 +111,6 @@ def test_mdu_with_optional_sections(self): assert fm_model.processes.statisticsfile.filepath is None assert fm_model.processes.thetavertical == 0.0 assert fm_model.processes.dtprocesses == 0.0 - assert fm_model.processes.dtmassbalance == 0.0 assert fm_model.processes.processfluxintegration == ProcessFluxIntegration.WAQ assert fm_model.processes.wriwaqbot3doutput is False assert fm_model.processes.volumedrythreshold == 1e-3 diff --git a/tests/dflowfm/test_research.py b/tests/dflowfm/test_research.py index e7c93ac62..bd11fda33 100644 --- a/tests/dflowfm/test_research.py +++ b/tests/dflowfm/test_research.py @@ -54,6 +54,32 @@ def test_load_model_with_research_keywords_as_researchfmmodel(self): assert model.trachytopes.research_trtmnh == pytest.approx(0.1) assert model.output.research_mbainterval == pytest.approx(0.0) + def test_save_model_with_single_research_keyword_does_not_write_other_research_keywords( + self, tmpdir: Path + ): + model = ResearchFMModel() + model.geometry.research_waterdepthini1d = 12.34 # a random research keyword + + save_path = tmpdir / "test.mdu" + model.save(filepath=save_path) + + # I picked 5 random research keywords to check + keywords_to_check = [ + "inputspecific", + "toplayminthick", + "faclaxturb", + "surftempsmofac", + "mbalumpsourcesinks", + ] + + with open(save_path, "r") as file: + content = file.read() + + for keyword in keywords_to_check: + assert keyword not in content + + assert "waterdepthini1d" in content + def test_can_save_and_load_research_model_from_scratch_without_errors(self): file_mdu = Path("mdu.mdu") mdu = ResearchFMModel() From f22d6bd4eda128fde218209665df1cdc64192d48 Mon Sep 17 00:00:00 2001 From: Tim van den Aardweg <71257004+tim-vd-aardweg@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:30:11 +0200 Subject: [PATCH 4/4] feat: Add support for optional [sedtrails] research section. (#651) refs: #620 --- hydrolib/core/dflowfm/research/__init__.py | 2 + hydrolib/core/dflowfm/research/models.py | 46 ++++++++++++++++++- ...keywords_from_dia_file_2024.03_release.mdu | 8 +++- tests/dflowfm/test_research.py | 24 ++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/hydrolib/core/dflowfm/research/__init__.py b/hydrolib/core/dflowfm/research/__init__.py index 7d05db7b3..71d3584d8 100644 --- a/hydrolib/core/dflowfm/research/__init__.py +++ b/hydrolib/core/dflowfm/research/__init__.py @@ -8,6 +8,7 @@ ResearchProcesses, ResearchRestart, ResearchSediment, + ResearchSedtrails, ResearchTime, ResearchTrachytopes, ResearchWaves, @@ -28,4 +29,5 @@ "ResearchTrachytopes", "ResearchWaves", "ResearchWind", + "ResearchSedtrails", ] diff --git a/hydrolib/core/dflowfm/research/models.py b/hydrolib/core/dflowfm/research/models.py index 10c990365..7e0f1dd22 100644 --- a/hydrolib/core/dflowfm/research/models.py +++ b/hydrolib/core/dflowfm/research/models.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import List, Literal, Optional from pydantic.v1 import Field @@ -19,6 +19,8 @@ Waves, Wind, ) +from hydrolib.core.dflowfm.ini.models import INIBasedModel +from hydrolib.core.dflowfm.ini.util import get_split_string_on_delimiter_validator class ResearchGeneral(General): @@ -863,6 +865,47 @@ class Comments(Processes.Comments): ) +class ResearchSedtrails(INIBasedModel): + """The `[Sedtrails]` section in an MDU file.""" + + class Comments(INIBasedModel.Comments): + research_sedtrailsgrid: Optional[str] = Field( + "Grid file for sedtrails output locations on corners.", + alias="sedtrailsgrid", + ) + research_sedtrailsanalysis: Optional[str] = Field( + "Sedtrails analysis. Should be all, transport, flowvelocity or soulsby.", + alias="sedtrailsanalysis", + ) + research_sedtrailsinterval: Optional[str] = Field( + "Sedtrails output times (s), interval, starttime, stoptime (s), if starttime, stoptime are left blank, use whole simulation period.", + alias="sedtrailsinterval", + ) + research_sedtrailsoutputfile: Optional[str] = Field( + "Sedtrails time-avgd output file.", alias="sedtrailsoutputfile" + ) + + comments: Comments = Comments() + _header: Literal["sedtrails"] = "sedtrails" + + research_sedtrailsgrid: Optional[DiskOnlyFileModel] = Field( + None, alias="sedtrailsgrid" + ) + research_sedtrailsanalysis: Optional[ + Literal["all", "transport", "flowvelocity", "soulsby"] + ] = Field(None, alias="sedtrailsanalysis") + research_sedtrailsinterval: Optional[List[float]] = Field( + None, alias="sedtrailsinterval" + ) + research_sedtrailsoutputfile: Optional[DiskOnlyFileModel] = Field( + None, alias="sedtrailsoutputfile" + ) + + _split_to_list = get_split_string_on_delimiter_validator( + "research_sedtrailsinterval", + ) + + class ResearchFMModel(FMModel): """ An extended FMModel that includes highly experimental research sections and keywords. @@ -880,3 +923,4 @@ class ResearchFMModel(FMModel): trachytopes: ResearchTrachytopes = Field(default_factory=ResearchTrachytopes) output: ResearchOutput = Field(default_factory=ResearchOutput) processes: Optional[ResearchProcesses] = Field(None) + sedtrails: Optional[ResearchSedtrails] = Field(None) diff --git a/tests/data/input/research/mdu_with_research_keywords_from_dia_file_2024.03_release.mdu b/tests/data/input/research/mdu_with_research_keywords_from_dia_file_2024.03_release.mdu index 26e4b510c..4f1a571b2 100644 --- a/tests/data/input/research/mdu_with_research_keywords_from_dia_file_2024.03_release.mdu +++ b/tests/data/input/research/mdu_with_research_keywords_from_dia_file_2024.03_release.mdu @@ -542,4 +542,10 @@ ProcessFluxIntegration = 1 # Process fluxes Wriwaqbot3Doutput = 0 # Write 3D water quality bottom variables (1: yes, 0: no) VolumeDryThreshold = 1.d-3 # Volume below which segments are marked as dry. (m3) DepthDryThreshold = 1.d-3 # Water depth below which segments are marked as dry. (m) -SubstanceDensityCoupling = 0 # Substance density coupling (1: yes, 0: no). It only functions correctly when all substances are sediments. \ No newline at end of file +SubstanceDensityCoupling = 0 # Substance density coupling (1: yes, 0: no). It only functions correctly when all substances are sediments. + +[sedtrails] +SedtrailsGrid = c:\test.txt # Grid file for sedtrails output locations on corners +SedtrailsAnalysis = all # Sedtrails analysis. Should be all, transport, flowvelocity or soulsby. +SedtrailsInterval = 3600. 1.1 2.2 # Sedtrails output times (s), interval, starttime, stoptime (s), if starttime, stoptime are left blank, use whole simulation period +SedtrailsOutputFile = d:\test2.txt # Sedtrails time-avgd output file \ No newline at end of file diff --git a/tests/dflowfm/test_research.py b/tests/dflowfm/test_research.py index bd11fda33..0a2f8c9b0 100644 --- a/tests/dflowfm/test_research.py +++ b/tests/dflowfm/test_research.py @@ -10,6 +10,7 @@ ResearchOutput, ResearchPhysics, ResearchSediment, + ResearchSedtrails, ResearchTime, ResearchTrachytopes, ResearchWaves, @@ -85,3 +86,26 @@ def test_can_save_and_load_research_model_from_scratch_without_errors(self): mdu = ResearchFMModel() mdu.save(file_mdu) _ = ResearchFMModel(file_mdu) + + def test_sedtrails_fromscratch(self): + model = ResearchFMModel() + model.sedtrails = ResearchSedtrails() + + model.sedtrails.research_sedtrailsgrid = r"c:\random.txt" + model.sedtrails.research_sedtrailsanalysis = "all" + model.sedtrails.research_sedtrailsinterval = [1.0, 2.0, 3.0] + model.sedtrails.research_sedtrailsoutputfile = r"c:\random2.txt" + + def test_sedtrails_can_be_loaded_from_mdu(self): + input_mdu = ( + test_input_dir + / "research" + / "mdu_with_research_keywords_from_dia_file_2024.03_release.mdu" + ) + + model = ResearchFMModel(filepath=input_mdu) + + assert str(model.sedtrails.research_sedtrailsgrid) == r"c:\test.txt" + assert model.sedtrails.research_sedtrailsanalysis == "all" + assert model.sedtrails.research_sedtrailsinterval == [3600.0, 1.1, 2.2] + assert str(model.sedtrails.research_sedtrailsoutputfile) == r"d:\test2.txt"