From 28af7a54ed6df3e5bd3dada92fd879d81a8382b8 Mon Sep 17 00:00:00 2001 From: Cinzia Mazzetti Date: Fri, 26 Sep 2025 15:25:15 +0000 Subject: [PATCH 1/9] Using ChanQAvgDt for inflows --- .../global_modules/default_options.py | 2 ++ src/lisflood/hydrological_modules/inflow.py | 5 ++-- src/lisfloodSettings_reference.xml | 15 ++++++---- .../LF_ETRS89_UseCase/settings/inflow.xml | 8 +++++- .../LF_ETRS89_UseCase/settings/mct_cold.xml | 5 ++++ .../mct_cold_for_results_generation.xml | 6 ++++ .../LF_ETRS89_UseCase/settings/mct_inflow.xml | 6 ++++ .../settings/mct_inflow_test.xml | 6 ++++ .../LF_ETRS89_UseCase/settings/mct_warm.xml | 6 ++++ .../data/LF_MCT_UseCase/settings/mct_cold.xml | 15 ++++++---- .../mct_cold_for_results_generation.xml | 6 ++++ .../LF_MCT_UseCase/settings/mct_inflow.xml | 6 ++++ .../settings/mct_inflow_test.xml | 6 ++++ .../settings/mct_prerun_test_only.xml | 6 ++++ .../data/LF_MCT_UseCase/settings/mct_warm.xml | 6 ++++ .../settings/mct_warm_endmaps.xml | 6 ++++ tests/test_mct_dyn_inflow.py | 8 ++++-- tests/test_mct_dyn_inflow_slow.py | 21 ++++++++------ tests/test_utils.py | 28 +++++++++++++++++++ 19 files changed, 141 insertions(+), 26 deletions(-) diff --git a/src/lisflood/global_modules/default_options.py b/src/lisflood/global_modules/default_options.py index 8d334495..16a7fcf4 100644 --- a/src/lisflood/global_modules/default_options.py +++ b/src/lisflood/global_modules/default_options.py @@ -1294,6 +1294,8 @@ 'timeseries': { 'ChanqTS': TimeSeries(name='ChanqTS', output_var='ChanQ', where='Gauges', repoption=['repDischargeTs'], restrictoption=[], operation=['']), + 'ChanqavgdtTS': TimeSeries(name='ChanqavgdtTS', output_var='ChanQAvgDt', where='Gauges', + repoption=['repDischargeTs'], restrictoption=[], operation=['']), 'DSLRAvUpsTS': TimeSeries(name='DSLRAvUpsTS', output_var='DSLR[0]', where='Gauges', repoption=['repStateUpsGauges'], restrictoption=['nonInit'], operation=['total']), diff --git a/src/lisflood/hydrological_modules/inflow.py b/src/lisflood/hydrological_modules/inflow.py index 5a71e557..ebbe712d 100755 --- a/src/lisflood/hydrological_modules/inflow.py +++ b/src/lisflood/hydrological_modules/inflow.py @@ -57,7 +57,7 @@ def initial(self): if option['inflow']: self.var.InflowPoints = loadmap('InflowPoints') #1D array size is pixels belonging to basin mask - self.var.QInM3Old = np.where(self.var.InflowPoints > 0, self.var.ChanQ * self.var.DtSec, 0) + self.var.QInM3Old = np.where(self.var.InflowPoints > 0, self.var.ChanQAvgDt * self.var.DtSec, 0) # inflow volume for model step # read inflow map @@ -125,7 +125,6 @@ def dynamic(self): # Get inflow hydrograph at each inflow point [m3/s] QIn = compressArray(QIn) QIn[np.isnan(QIn)] = 0 - #cmcheck - inflow self.var.QInM3 = QIn * self.var.DtSec # Convert to [m3] per time step self.var.TotalQInM3 += self.var.QInM3 @@ -145,7 +144,7 @@ def dynamic_inloop(self, NoRoutingExecuted): settings = LisSettings.instance() option = settings.options - if option['inflow']: #cmcheck - inflow + if option['inflow']: self.var.QInDt = (self.var.QInM3Old + (NoRoutingExecuted + 1) * self.var.QDelta) * self.var.InvNoRoutSteps # flow from inlets per sub step diff --git a/src/lisfloodSettings_reference.xml b/src/lisfloodSettings_reference.xml index 1cec854d..160d6d26 100644 --- a/src/lisfloodSettings_reference.xml +++ b/src/lisfloodSettings_reference.xml @@ -1711,17 +1711,14 @@ Multiplier [] applied to ChanSdXdY - OPTIONAL: nominal map with locations of (measured) - inflow hydrographs [cu m / s] + OPTIONAL: nominal map with locations of (measured) inflow hydrographs [cu m / s] - OPTIONAL: observed or simulated input hydrographs as - time series [cu m / s] - Note that identifiers in time series correspond to - InflowPoints map (also optional) + OPTIONAL: observed or simulated input hydrographs as time series [cu m / s] + Note that identifiers in time series correspond to InflowPoints map (also optional). ChanqavgdtTS should be used during calibration @@ -4208,6 +4205,12 @@ Multiplier [] applied to ChanSdXdY + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_ETRS89_UseCase/settings/inflow.xml b/tests/data/LF_ETRS89_UseCase/settings/inflow.xml index e109c586..290ccbcb 100644 --- a/tests/data/LF_ETRS89_UseCase/settings/inflow.xml +++ b/tests/data/LF_ETRS89_UseCase/settings/inflow.xml @@ -3834,7 +3834,13 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT - Reported discharge over last routing sub-step [cu m/s] + Reported instantaneous discharge at the end of routing sub-step [cu m/s] + + + + + + Reported average discharge on the last routing sub-step [cu m/s] diff --git a/tests/data/LF_ETRS89_UseCase/settings/mct_cold.xml b/tests/data/LF_ETRS89_UseCase/settings/mct_cold.xml index 00f7927c..e4b4879f 100644 --- a/tests/data/LF_ETRS89_UseCase/settings/mct_cold.xml +++ b/tests/data/LF_ETRS89_UseCase/settings/mct_cold.xml @@ -4071,6 +4071,11 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + Reported water level [m] diff --git a/tests/data/LF_ETRS89_UseCase/settings/mct_cold_for_results_generation.xml b/tests/data/LF_ETRS89_UseCase/settings/mct_cold_for_results_generation.xml index bd4c21f5..0ef0ddbe 100644 --- a/tests/data/LF_ETRS89_UseCase/settings/mct_cold_for_results_generation.xml +++ b/tests/data/LF_ETRS89_UseCase/settings/mct_cold_for_results_generation.xml @@ -4028,6 +4028,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_ETRS89_UseCase/settings/mct_inflow.xml b/tests/data/LF_ETRS89_UseCase/settings/mct_inflow.xml index d78fa3d9..5ff82c29 100644 --- a/tests/data/LF_ETRS89_UseCase/settings/mct_inflow.xml +++ b/tests/data/LF_ETRS89_UseCase/settings/mct_inflow.xml @@ -4082,6 +4082,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_ETRS89_UseCase/settings/mct_inflow_test.xml b/tests/data/LF_ETRS89_UseCase/settings/mct_inflow_test.xml index 01af2c06..7000ca10 100644 --- a/tests/data/LF_ETRS89_UseCase/settings/mct_inflow_test.xml +++ b/tests/data/LF_ETRS89_UseCase/settings/mct_inflow_test.xml @@ -4082,6 +4082,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_ETRS89_UseCase/settings/mct_warm.xml b/tests/data/LF_ETRS89_UseCase/settings/mct_warm.xml index f4a1fde7..639730fc 100644 --- a/tests/data/LF_ETRS89_UseCase/settings/mct_warm.xml +++ b/tests/data/LF_ETRS89_UseCase/settings/mct_warm.xml @@ -4028,6 +4028,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_MCT_UseCase/settings/mct_cold.xml b/tests/data/LF_MCT_UseCase/settings/mct_cold.xml index 98ebf057..fe7351a6 100644 --- a/tests/data/LF_MCT_UseCase/settings/mct_cold.xml +++ b/tests/data/LF_MCT_UseCase/settings/mct_cold.xml @@ -50,8 +50,6 @@ You can use builtin path variables in this template and reference to other paths - - # use inflow data @@ -62,13 +60,15 @@ You can use builtin path variables in this template and reference to other paths # option to initialize Lisflood + # option to read/write NetCDF - + # option to Report PaddyRiceDebug information in CSV file for debugging Paddy Rice Water Abstraction issue on dry Channels + #----------------------------------------------------------- # report time series @@ -164,8 +164,6 @@ You can use builtin path variables in this template and reference to other paths - - @@ -173,7 +171,6 @@ You can use builtin path variables in this template and reference to other paths ************************************************************** netCDF parameters ************************************************************** - @@ -4187,6 +4184,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_MCT_UseCase/settings/mct_cold_for_results_generation.xml b/tests/data/LF_MCT_UseCase/settings/mct_cold_for_results_generation.xml index e1771e1e..b6a12f34 100644 --- a/tests/data/LF_MCT_UseCase/settings/mct_cold_for_results_generation.xml +++ b/tests/data/LF_MCT_UseCase/settings/mct_cold_for_results_generation.xml @@ -4188,6 +4188,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_MCT_UseCase/settings/mct_inflow.xml b/tests/data/LF_MCT_UseCase/settings/mct_inflow.xml index 71c44d75..78ae22e8 100644 --- a/tests/data/LF_MCT_UseCase/settings/mct_inflow.xml +++ b/tests/data/LF_MCT_UseCase/settings/mct_inflow.xml @@ -4194,6 +4194,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_MCT_UseCase/settings/mct_inflow_test.xml b/tests/data/LF_MCT_UseCase/settings/mct_inflow_test.xml index f756e260..267cf188 100644 --- a/tests/data/LF_MCT_UseCase/settings/mct_inflow_test.xml +++ b/tests/data/LF_MCT_UseCase/settings/mct_inflow_test.xml @@ -4087,6 +4087,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_MCT_UseCase/settings/mct_prerun_test_only.xml b/tests/data/LF_MCT_UseCase/settings/mct_prerun_test_only.xml index ddc0a769..8031fcff 100644 --- a/tests/data/LF_MCT_UseCase/settings/mct_prerun_test_only.xml +++ b/tests/data/LF_MCT_UseCase/settings/mct_prerun_test_only.xml @@ -4187,6 +4187,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_MCT_UseCase/settings/mct_warm.xml b/tests/data/LF_MCT_UseCase/settings/mct_warm.xml index c3648984..e9e105c9 100644 --- a/tests/data/LF_MCT_UseCase/settings/mct_warm.xml +++ b/tests/data/LF_MCT_UseCase/settings/mct_warm.xml @@ -4035,6 +4035,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_MCT_UseCase/settings/mct_warm_endmaps.xml b/tests/data/LF_MCT_UseCase/settings/mct_warm_endmaps.xml index a43688a7..1c22cda6 100644 --- a/tests/data/LF_MCT_UseCase/settings/mct_warm_endmaps.xml +++ b/tests/data/LF_MCT_UseCase/settings/mct_warm_endmaps.xml @@ -4035,6 +4035,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/test_mct_dyn_inflow.py b/tests/test_mct_dyn_inflow.py index 933901af..269096f7 100644 --- a/tests/test_mct_dyn_inflow.py +++ b/tests/test_mct_dyn_inflow.py @@ -32,7 +32,7 @@ def run(self, date_start, date_end, dtsec, type): 'BankFullPerc': '0.2', 'MaskMap': '$(PathRoot)/maps/mask.nc', 'Gauges': '4292500 2377500', # one cell upstream of inflow point - 'ChanqTS': out_path_run+'/inflow.tss', + 'ChanqavgdtTS': out_path_run+'/inflow.tss', 'PathOut': out_path_run}) mk_path_out(out_path_ref) mk_path_out(out_path_run) @@ -78,7 +78,7 @@ def run(self, date_start, date_end, dtsec, type): lisfloodexe(settings) # set precisioon for the test - atol = 7. + atol = 3.0 rtol = 0.01 comparator = TSSComparator(atol,rtol) @@ -90,7 +90,11 @@ def run(self, date_start, date_end, dtsec, type): # test when DtSec != DtSecChannel reference = os.path.join(out_path_ref, 'chanqWin.tss') output_tss = os.path.join(out_path_run, 'chanqWin.tss') + comparator.compare_files(reference, output_tss) + # test when DtSec != DtSecChannel + reference = os.path.join(out_path_ref, 'chanqavgdt.tss') + output_tss = os.path.join(out_path_run, 'chanqavgdt.tss') comparator.compare_files(reference, output_tss) def teardown_method(self, type): diff --git a/tests/test_mct_dyn_inflow_slow.py b/tests/test_mct_dyn_inflow_slow.py index 890ba6f7..a7ce0c7b 100644 --- a/tests/test_mct_dyn_inflow_slow.py +++ b/tests/test_mct_dyn_inflow_slow.py @@ -12,7 +12,7 @@ from .test_utils import setoptions, mk_path_out -@pytest.mark.slow +# @pytest.mark.slow class TestInflow(): case_dir = os.path.join(os.path.dirname(__file__), 'data', 'LF_ETRS89_UseCase') @@ -26,7 +26,7 @@ def run(self, date_start, date_end, dtsec, type): settings_file = os.path.join(self.case_dir, 'settings', 'mct_inflow.xml') settings = setoptions(settings_file, opts_to_set = ['MCTRouting'], - opts_to_unset = ['inflow', + opts_to_unset = ['inflow', 'SplitRouting'], vars_to_set={'StepStart': date_start, 'StepEnd': date_end, @@ -36,7 +36,7 @@ def run(self, date_start, date_end, dtsec, type): 'BankFullPerc': '0.1', 'MaskMap': '$(PathRoot)/maps/mask.nc', 'Gauges': '4317500 2447500', # one cell upstream of inflow point - 'ChanqTS': out_path_run+'/inflow.tss', + 'ChanqavgdtTS': out_path_run+'/inflow.tss', 'PathOut': out_path_run}) mk_path_out(out_path_ref) mk_path_out(out_path_run) @@ -86,21 +86,26 @@ def run(self, date_start, date_end, dtsec, type): lisfloodexe(settings) # set precision for the test - atol = 15. + atol = 550. rtol = 0.1 comparator = TSSComparator(atol,rtol) - # # test when DtSec = DtSecChannel + # # # test when DtSec = DtSecChannel # reference = os.path.join(out_path_ref, 'disWin.tss') # output_tss = os.path.join(out_path_run, 'disWin.tss') # comparator.compare_files(reference, output_tss) + # + # # test when DtSec != DtSecChannel + # reference = os.path.join(out_path_ref, 'chanqWin.tss') + # output_tss = os.path.join(out_path_run, 'chanqWin.tss') + # comparator.compare_files(reference, output_tss) # test when DtSec != DtSecChannel - reference = os.path.join(out_path_ref, 'chanqWin.tss') - output_tss = os.path.join(out_path_run, 'chanqWin.tss') - + reference = os.path.join(out_path_ref, 'chanqavgdt.tss') + output_tss = os.path.join(out_path_run, 'chanqavgdt.tss') comparator.compare_files(reference, output_tss) + def teardown_method(self, type): print('Cleaning directories') diff --git a/tests/test_utils.py b/tests/test_utils.py index 00d1662b..c6ddbd87 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -94,6 +94,18 @@ class ETRS89TestCase(object): 'tss': os.path.join(ref_dir, 'output_reference_6h/chanqWin.tss'), }, }, + # 'chanqavgdt': { + # 'report_map': None, + # 'report_tss': 'ChanqavgdtTS', + # '86400': { + # 'map': None, + # 'tss': os.path.join(ref_dir, 'output_reference_daily/chanqavgdt.tss'), + # }, + # '21600': { + # 'map': None, + # 'tss': os.path.join(ref_dir, 'output_reference_6h/chanqavgdt.tss'), + # }, + # }, 'thia': { 'report_map': 'Theta1IrrigationState', 'report_tss': None, @@ -354,6 +366,22 @@ class MCTTestCase(object): 'tss': os.path.join(ref_dir, 'output_reference_6h_1h/chanqX.tss'), }, }, + # 'chanqavgdt': { + # 'report_map': None, + # 'report_tss': 'ChanqavgdtTS', + # '86400-3600': { + # 'map': None, + # 'tss': os.path.join(ref_dir, 'output_reference_daily/chanqavgdt.tss'), + # }, + # '21600-21600': { + # 'map': None, + # 'tss': os.path.join(ref_dir, 'output_reference_6h_6h/chanqavgdt.tss'), + # }, + # '21600-3600': { + # 'map': None, + # 'tss': os.path.join(ref_dir, 'output_reference_6h_1h/chanqavgdt.tss'), + # }, + # }, 'mbError': { 'report_map': None, 'report_tss': 'WaterMassBalanceTSS', From b6e92a559d800a242ff09ff3b35806f62a10707c Mon Sep 17 00:00:00 2001 From: Cinzia Mazzetti Date: Thu, 2 Oct 2025 13:53:44 +0000 Subject: [PATCH 2/9] Added two options to compare ChanQ and ChanQAvgDt in MCT and through a warning --- src/lisflood/hydrological_modules/routing.py | 27 ++++++++++++++++ tests/test_mct_dyn_inflow.py | 10 +++--- tests/test_mct_dyn_inflow_slow.py | 33 ++++++++++---------- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/lisflood/hydrological_modules/routing.py b/src/lisflood/hydrological_modules/routing.py index 6807d67c..d3276467 100644 --- a/src/lisflood/hydrological_modules/routing.py +++ b/src/lisflood/hydrological_modules/routing.py @@ -69,8 +69,10 @@ def initial(self): """ settings = LisSettings.instance() option = settings.options + flags = settings.flags maskinfo = MaskInfo.instance() + # ************************************************************ # ***** NUMBER OF ROUTING STEPS ********************* # ************************************************************ @@ -542,6 +544,7 @@ def initialMCT(self): """ settings = LisSettings.instance() option = settings.options + flags = settings.flags if not (option['SplitRouting']): self.var.ChannelAlpha2 = None @@ -631,6 +634,7 @@ def dynamic(self, NoRoutingExecuted): """ settings = LisSettings.instance() option = settings.options + flags = settings.flags if not(option['InitLisflood']): # only with no InitLisflood self.lakes_module.dynamic_inloop(NoRoutingExecuted) @@ -804,6 +808,29 @@ def dynamic(self, NoRoutingExecuted): self.var.ChanM3 # Channel storage volume. In input: at time t V00; in output: at time t+dt V11 ) + ##################################################################3 + # if flags['debug']: + # checking Courant number for potential instability in MCT + if not np.all(self.var.PrevCm0 <= 1): + warnings.warn(LisfloodWarning("WARNING! Courant > 1. Consider using smaller DtRouting steps or using kinematic routing")) + + ##################################################################3 + # checking cahnqvagdt and chanq for instability in MCT that can can create issues when using inflows + # Only consider elements where ChanQAvgDt >1000 + dismask = self.var.ChanQAvgDt > 1000. + # Check for ChanQ values that are 10x larger or smaller than ChanQAvgDt + too_large = self.var.ChanQ[dismask] > 15 * self.var.ChanQAvgDt[dismask] + too_small = self.var.ChanQ[dismask] < 0.05 * self.var.ChanQAvgDt[dismask] + + bad = too_large | too_small + + if np.any(bad): + warnings.warn(LisfloodWarning("WARNING! At least one ChanQ is >> or << ChanQAvgDt. Consider increasing DtRouting step or using kinematic routing")) + # # list 'bad' cells + # bad_indices = np.where(dismask)[0][bad] + # print("Bad indices:", bad_indices) + ##################################################################3 + else: # Store results of kinematic/split routing in the general variables self.var.ChanQ = ChanQ diff --git a/tests/test_mct_dyn_inflow.py b/tests/test_mct_dyn_inflow.py index 269096f7..135ce437 100644 --- a/tests/test_mct_dyn_inflow.py +++ b/tests/test_mct_dyn_inflow.py @@ -32,7 +32,7 @@ def run(self, date_start, date_end, dtsec, type): 'BankFullPerc': '0.2', 'MaskMap': '$(PathRoot)/maps/mask.nc', 'Gauges': '4292500 2377500', # one cell upstream of inflow point - 'ChanqavgdtTS': out_path_run+'/inflow.tss', + 'ChanqavgdtTS': out_path_run+'/inflow.tss', # use chanqavgdt as inflow 'PathOut': out_path_run}) mk_path_out(out_path_ref) mk_path_out(out_path_run) @@ -77,10 +77,12 @@ def run(self, date_start, date_end, dtsec, type): mk_path_out(out_path_run) lisfloodexe(settings) - # set precisioon for the test - atol = 3.0 + # set precision for the test and number of steps to skip at the beginning of the time series + atol = 2.0 + # atol = 5.0 # single routing step rtol = 0.01 - comparator = TSSComparator(atol,rtol) + init_steps_to_skip = 20 + comparator = TSSComparator(atol,rtol,init_steps_to_skip) # test when DtSec = DtSecChannel reference = os.path.join(out_path_ref, 'disWin.tss') diff --git a/tests/test_mct_dyn_inflow_slow.py b/tests/test_mct_dyn_inflow_slow.py index a7ce0c7b..07680d29 100644 --- a/tests/test_mct_dyn_inflow_slow.py +++ b/tests/test_mct_dyn_inflow_slow.py @@ -12,7 +12,7 @@ from .test_utils import setoptions, mk_path_out -# @pytest.mark.slow +@pytest.mark.slow class TestInflow(): case_dir = os.path.join(os.path.dirname(__file__), 'data', 'LF_ETRS89_UseCase') @@ -36,7 +36,7 @@ def run(self, date_start, date_end, dtsec, type): 'BankFullPerc': '0.1', 'MaskMap': '$(PathRoot)/maps/mask.nc', 'Gauges': '4317500 2447500', # one cell upstream of inflow point - 'ChanqavgdtTS': out_path_run+'/inflow.tss', + 'ChanqavgdtTS': out_path_run+'/inflow.tss', # use chanqavgdt as inflow 'PathOut': out_path_run}) mk_path_out(out_path_ref) mk_path_out(out_path_run) @@ -85,20 +85,21 @@ def run(self, date_start, date_end, dtsec, type): mk_path_out(out_path_run) lisfloodexe(settings) - # set precision for the test - atol = 550. - rtol = 0.1 - comparator = TSSComparator(atol,rtol) - - # # # test when DtSec = DtSecChannel - # reference = os.path.join(out_path_ref, 'disWin.tss') - # output_tss = os.path.join(out_path_run, 'disWin.tss') - # comparator.compare_files(reference, output_tss) - # - # # test when DtSec != DtSecChannel - # reference = os.path.join(out_path_ref, 'chanqWin.tss') - # output_tss = os.path.join(out_path_run, 'chanqWin.tss') - # comparator.compare_files(reference, output_tss) + # set precision for the test and number of steps to skip at the beginning of the time series + atol = 505. + rtol = 0.01 + init_steps_to_skip = 20 + comparator = TSSComparator(atol,rtol,init_steps_to_skip) + + # test when DtSec = DtSecChannel + reference = os.path.join(out_path_ref, 'disWin.tss') + output_tss = os.path.join(out_path_run, 'disWin.tss') + comparator.compare_files(reference, output_tss) + + # test when DtSec != DtSecChannel + reference = os.path.join(out_path_ref, 'chanqWin.tss') + output_tss = os.path.join(out_path_run, 'chanqWin.tss') + comparator.compare_files(reference, output_tss) # test when DtSec != DtSecChannel reference = os.path.join(out_path_ref, 'chanqavgdt.tss') From 120da0cc2abe668ac7ac2b4ed1a0fd600859217c Mon Sep 17 00:00:00 2001 From: Carlo Russo Date: Tue, 14 Oct 2025 14:33:00 +0200 Subject: [PATCH 3/9] Updated thresholds in chanq and chanqavgdt check for instability in MCT --- VERSION | 2 +- src/lisflood/hydrological_modules/routing.py | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/VERSION b/VERSION index 91a2c526..c3ef9b53 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.3.1.504 \ No newline at end of file +4.3.1.505 \ No newline at end of file diff --git a/src/lisflood/hydrological_modules/routing.py b/src/lisflood/hydrological_modules/routing.py index d3276467..feb2fc7d 100644 --- a/src/lisflood/hydrological_modules/routing.py +++ b/src/lisflood/hydrological_modules/routing.py @@ -809,18 +809,18 @@ def dynamic(self, NoRoutingExecuted): ) ##################################################################3 - # if flags['debug']: - # checking Courant number for potential instability in MCT - if not np.all(self.var.PrevCm0 <= 1): - warnings.warn(LisfloodWarning("WARNING! Courant > 1. Consider using smaller DtRouting steps or using kinematic routing")) + if flags['debug']: + # checking Courant number for potential instability in MCT + if not np.all(self.var.PrevCm0 <= 1): + warnings.warn(LisfloodWarning("WARNING! Courant > 1. Consider using smaller DtRouting steps or using kinematic routing")) ##################################################################3 - # checking cahnqvagdt and chanq for instability in MCT that can can create issues when using inflows - # Only consider elements where ChanQAvgDt >1000 - dismask = self.var.ChanQAvgDt > 1000. + # checking chanqvagdt and chanq for instability in MCT that can can create issues when using inflows + # Only consider elements where ChanQAvgDt >100 or ChanQ >100 + dismask = (self.var.ChanQ > 100.) | (self.var.ChanQAvgDt > 100.) # Check for ChanQ values that are 10x larger or smaller than ChanQAvgDt - too_large = self.var.ChanQ[dismask] > 15 * self.var.ChanQAvgDt[dismask] - too_small = self.var.ChanQ[dismask] < 0.05 * self.var.ChanQAvgDt[dismask] + too_large = self.var.ChanQ[dismask] > 10 * self.var.ChanQAvgDt[dismask] + too_small = self.var.ChanQ[dismask] < 0.1 * self.var.ChanQAvgDt[dismask] bad = too_large | too_small From 6fcbd70aa2b1e2b2bbeaf41057400bb2bab1a6b8 Mon Sep 17 00:00:00 2001 From: Carlo Russo Date: Thu, 16 Oct 2025 15:54:36 +0200 Subject: [PATCH 4/9] Added ChanqavgdtTS key in xml files. Small fix to cache UT --- tests/data/LF_ETRS89_UseCase/settings/base.xml | 6 ++++++ tests/data/LF_ETRS89_UseCase/settings/cold.xml | 6 ++++++ tests/data/LF_ETRS89_UseCase/settings/full.xml | 5 +++++ tests/data/LF_ETRS89_UseCase/settings/prerun.xml | 6 ++++++ tests/data/LF_ETRS89_UseCase/settings/warm.xml | 6 ++++++ tests/data/LF_lat_lon_UseCase/prerun_lat_lon.xml | 6 ++++++ tests/data/LF_lat_lon_UseCase/run_lat_lon.xml | 6 ++++++ tests/test_caching.py | 4 ++-- 8 files changed, 43 insertions(+), 2 deletions(-) diff --git a/tests/data/LF_ETRS89_UseCase/settings/base.xml b/tests/data/LF_ETRS89_UseCase/settings/base.xml index 692b55d8..0be78688 100644 --- a/tests/data/LF_ETRS89_UseCase/settings/base.xml +++ b/tests/data/LF_ETRS89_UseCase/settings/base.xml @@ -3861,6 +3861,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_ETRS89_UseCase/settings/cold.xml b/tests/data/LF_ETRS89_UseCase/settings/cold.xml index 25556e82..865edfe6 100644 --- a/tests/data/LF_ETRS89_UseCase/settings/cold.xml +++ b/tests/data/LF_ETRS89_UseCase/settings/cold.xml @@ -3905,6 +3905,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/data/LF_ETRS89_UseCase/settings/full.xml b/tests/data/LF_ETRS89_UseCase/settings/full.xml index 0bb6b73d..e4d16667 100644 --- a/tests/data/LF_ETRS89_UseCase/settings/full.xml +++ b/tests/data/LF_ETRS89_UseCase/settings/full.xml @@ -6032,6 +6032,11 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + diff --git a/tests/data/LF_ETRS89_UseCase/settings/prerun.xml b/tests/data/LF_ETRS89_UseCase/settings/prerun.xml index 093348ab..5dc97d95 100644 --- a/tests/data/LF_ETRS89_UseCase/settings/prerun.xml +++ b/tests/data/LF_ETRS89_UseCase/settings/prerun.xml @@ -3836,6 +3836,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT Reported discharge over last routing sub-step [cu m/s] + + + + Reported average discharge on the last routing sub-step [cu m/s] + + diff --git a/tests/data/LF_ETRS89_UseCase/settings/warm.xml b/tests/data/LF_ETRS89_UseCase/settings/warm.xml index 63eb6053..7776caea 100644 --- a/tests/data/LF_ETRS89_UseCase/settings/warm.xml +++ b/tests/data/LF_ETRS89_UseCase/settings/warm.xml @@ -3881,6 +3881,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT Reported discharge over last routing sub-step [cu m/s] + + + + Reported average discharge on the last routing sub-step [cu m/s] + + diff --git a/tests/data/LF_lat_lon_UseCase/prerun_lat_lon.xml b/tests/data/LF_lat_lon_UseCase/prerun_lat_lon.xml index 15ebdd18..135681f9 100644 --- a/tests/data/LF_lat_lon_UseCase/prerun_lat_lon.xml +++ b/tests/data/LF_lat_lon_UseCase/prerun_lat_lon.xml @@ -3689,6 +3689,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT Reported discharge over last routing sub-step [cu m/s] + + + + Reported average discharge on the last routing sub-step [cu m/s] + + diff --git a/tests/data/LF_lat_lon_UseCase/run_lat_lon.xml b/tests/data/LF_lat_lon_UseCase/run_lat_lon.xml index 29270027..b69a48d6 100644 --- a/tests/data/LF_lat_lon_UseCase/run_lat_lon.xml +++ b/tests/data/LF_lat_lon_UseCase/run_lat_lon.xml @@ -3694,6 +3694,12 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT + + + Reported average discharge on the last routing sub-step [cu m/s] + + + Reported water level [m] diff --git a/tests/test_caching.py b/tests/test_caching.py index 0120da86..816ae5c5 100644 --- a/tests/test_caching.py +++ b/tests/test_caching.py @@ -130,7 +130,7 @@ def run(self, dt_sec, step_start, step_end): print('Cache size is {}'.format(cache_size_a)) print('Items found: {}'.format(cache_found_a)) - assert cache_found_a == 1 # apparently one map is called twice + assert cache_found_a == 2 # here we used Gauges map 3 times (for DisTS, ChanqTS and ChanqAvgDtTS) lisfloodexe(settings) @@ -141,7 +141,7 @@ def run(self, dt_sec, step_start, step_end): Cache.info() - assert cache_found_b == cache_size_b + 2 + assert cache_found_b == cache_size_b + 4 # add 4 for the 2 additional calls of Gauges map assert cache_size_a == cache_size_b self.compare_reference('dis', check='map', step_length=dt_sec) From b8ae5ad33ff521e0d5ab6b31fbe3a80251805058 Mon Sep 17 00:00:00 2001 From: Carlo Russo Date: Thu, 16 Oct 2025 16:36:22 +0200 Subject: [PATCH 5/9] Small fix in inflow unit test --- tests/test_mct_dyn_inflow.py | 2 +- tests/test_mct_dyn_inflow_slow.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_mct_dyn_inflow.py b/tests/test_mct_dyn_inflow.py index 135ce437..f52d0716 100644 --- a/tests/test_mct_dyn_inflow.py +++ b/tests/test_mct_dyn_inflow.py @@ -82,7 +82,7 @@ def run(self, date_start, date_end, dtsec, type): # atol = 5.0 # single routing step rtol = 0.01 init_steps_to_skip = 20 - comparator = TSSComparator(atol,rtol,init_steps_to_skip) + comparator = TSSComparator(atol,rtol,init_skip_steps = init_steps_to_skip) # test when DtSec = DtSecChannel reference = os.path.join(out_path_ref, 'disWin.tss') diff --git a/tests/test_mct_dyn_inflow_slow.py b/tests/test_mct_dyn_inflow_slow.py index 07680d29..8b0437c7 100644 --- a/tests/test_mct_dyn_inflow_slow.py +++ b/tests/test_mct_dyn_inflow_slow.py @@ -89,7 +89,7 @@ def run(self, date_start, date_end, dtsec, type): atol = 505. rtol = 0.01 init_steps_to_skip = 20 - comparator = TSSComparator(atol,rtol,init_steps_to_skip) + comparator = TSSComparator(atol,rtol,init_skip_steps = init_steps_to_skip) # test when DtSec = DtSecChannel reference = os.path.join(out_path_ref, 'disWin.tss') From 6b8c579fe9b64ca492d2f4bc64b28d69374c79f3 Mon Sep 17 00:00:00 2001 From: Carlo Russo Date: Mon, 20 Oct 2025 12:27:25 +0200 Subject: [PATCH 6/9] Fix to malformed xml file causing mct UT deadlock --- tests/data/LF_MCT_UseCase/settings/mct_cold.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/data/LF_MCT_UseCase/settings/mct_cold.xml b/tests/data/LF_MCT_UseCase/settings/mct_cold.xml index fe7351a6..6159ced7 100644 --- a/tests/data/LF_MCT_UseCase/settings/mct_cold.xml +++ b/tests/data/LF_MCT_UseCase/settings/mct_cold.xml @@ -171,7 +171,7 @@ You can use builtin path variables in this template and reference to other paths ************************************************************** netCDF parameters ************************************************************** - + !-- Optimization of netCDF I/O through chunking and caching. From 9f733652edb78f6d0755c85a6bba15b032e267b8 Mon Sep 17 00:00:00 2001 From: Carlo Russo Date: Mon, 20 Oct 2025 13:09:05 +0200 Subject: [PATCH 7/9] Added check on xml syntax in test_utils --- tests/test_utils.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_utils.py b/tests/test_utils.py index c6ddbd87..f3289f09 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,3 +1,4 @@ +from lxml import etree import os import sys @@ -23,6 +24,14 @@ def setoptions(settings_file, opts_to_set=None, opts_to_unset=None, vars_to_set= opts_to_unset = [] if opts_to_unset is None else opts_to_unset vars_to_set = {} if vars_to_set is None else vars_to_set with open(settings_file) as tpl: + try: + # Attempt to parse the XML file + etree.parse(tpl) + except etree.XMLSyntaxError as e: + # If a syntax error is encountered, print the error and exit + print(f"XMLSyntaxError: {e}") + raise e + soup = BeautifulSoup(tpl, 'lxml-xml') for opt in opts_to_set: for tag in soup.find_all("setoption", {'name': opt}): From 58263841f83610a248eded8d9eded0d4c555b691 Mon Sep 17 00:00:00 2001 From: Carlo Russo Date: Mon, 20 Oct 2025 13:15:15 +0200 Subject: [PATCH 8/9] small fix to UT xml check --- tests/test_utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index f3289f09..50bd36d1 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -23,15 +23,16 @@ def setoptions(settings_file, opts_to_set=None, opts_to_unset=None, vars_to_set= opts_to_set = [] if opts_to_set is None else opts_to_set opts_to_unset = [] if opts_to_unset is None else opts_to_unset vars_to_set = {} if vars_to_set is None else vars_to_set - with open(settings_file) as tpl: + with open(settings_file) as filetocheck: try: # Attempt to parse the XML file - etree.parse(tpl) + etree.parse(filetocheck) except etree.XMLSyntaxError as e: # If a syntax error is encountered, print the error and exit print(f"XMLSyntaxError: {e}") raise e + with open(settings_file) as tpl: soup = BeautifulSoup(tpl, 'lxml-xml') for opt in opts_to_set: for tag in soup.find_all("setoption", {'name': opt}): From 1a419f3f9fdac401ec5d38699af5d74556e0d43f Mon Sep 17 00:00:00 2001 From: Carlo Russo Date: Mon, 20 Oct 2025 15:24:50 +0200 Subject: [PATCH 9/9] Fixed malformed warm.xml file in UT --- tests/data/LF_ETRS89_UseCase/settings/warm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/data/LF_ETRS89_UseCase/settings/warm.xml b/tests/data/LF_ETRS89_UseCase/settings/warm.xml index 7776caea..17904c7d 100644 --- a/tests/data/LF_ETRS89_UseCase/settings/warm.xml +++ b/tests/data/LF_ETRS89_UseCase/settings/warm.xml @@ -5417,7 +5417,7 @@ LFBINDING: MORE LOW-LEVEL CONTROL OVER MODEL IN- AND OUTPUT - + Reported pF lower soil layer [-]