Skip to content

Commit b252216

Browse files
author
Cinzia Mazzetti
committed
trying to calculate the average discharge for kinematic routing
1 parent 313d00c commit b252216

File tree

4 files changed

+105
-42
lines changed

4 files changed

+105
-42
lines changed

src/lisflood/hydrological_modules/kinematic_wave_parallel.py

+10-3
Original file line numberDiff line numberDiff line change
@@ -122,16 +122,21 @@ def __init__(self, compressed_encoded_ldd, land_mask, alpha_channel, beta, space
122122
self.kinematic_wave_warning_printed=False
123123
self.flagnancheck=flagnancheck
124124
# Parameters for the solution of the discretised Kinematic wave continuity equation
125+
self.alpha_channel = alpha_channel
125126
self.space_delta = space_delta
127+
self.inv_time_delta = 1 / time_delta
126128
self.beta = beta
127129
self.inv_beta = 1 / beta
128130
self.b_minus_1 = beta - 1
129131
self.a_dx_div_dt_channel = alpha_channel * space_delta / time_delta
130132
self.b_a_dx_div_dt_channel = beta * self.a_dx_div_dt_channel
133+
self.a_dx = alpha_channel * space_delta
131134
# If split-routing (floodplains)
132135
if alpha_floodplains is not None:
136+
self.alpha_floodplains = alpha_floodplains
133137
self.a_dx_div_dt_floodplains = alpha_floodplains * space_delta / time_delta
134138
self.b_a_dx_div_dt_floodplains = beta * self.a_dx_div_dt_floodplains
139+
self.a_dx_floodplains = alpha_floodplains * space_delta
135140
# Process flow direction matrix: downstream and upstream lookups, and routing orders
136141
flow_dir = decodeFlowMatrix(rebuildFlowMatrix(compressed_encoded_ldd, land_mask))
137142
self.downstream_lookup, self.upstream_lookup = streamLookups(flow_dir, land_mask)
@@ -163,26 +168,28 @@ def _setRoutingOrders(self):
163168
self.order_start_stop = np.column_stack((np.append(0, stop[:-1]), stop)).astype(int)
164169
self.pixels_ordered = self.pixels_ordered.values.astype(int)
165170

166-
def kinematicWaveRouting(self, discharge, specific_lateral_inflow, section="main_channel"):
171+
def kinematicWaveRouting(self, discharge_avg, discharge, specific_lateral_inflow, section="main_channel"):
167172
"""Kinematic wave routing: wrapper around kinematic_wave_parallel_tools.kinematicWave"""
168173
# Lateral inflow (m3 s-1)
169174
lateral_inflow = nx.evaluate("q * dx", local_dict={"q": specific_lateral_inflow, "dx": self.space_delta})
170175
# Choose between main channel and floodplain routing
171176
if section == "main_channel":
172177
a_dx_div_dt = self.a_dx_div_dt_channel
173178
b_a_dx_div_dt = self.b_a_dx_div_dt_channel
179+
a_dx = self.a_dx
174180
elif section == "floodplains":
175181
a_dx_div_dt = self.a_dx_div_dt_floodplains
176182
b_a_dx_div_dt = self.b_a_dx_div_dt_floodplains
183+
a_dx = self.a_dx_floodplains
177184
else:
178185
raise Exception("The section parameter must be either 'main_channel' or 'floodplain'!")
179186
# Constant term in f(x) evaluation for Newton-Raphson method
180187
local_dict = {"a_dx_div_dt": a_dx_div_dt, "Qold": discharge, "b": self.beta, "lateral_inflow": lateral_inflow}
181188
constant = nx.evaluate("a_dx_div_dt * Qold ** b + lateral_inflow", local_dict=local_dict)
182189
# Solve the Kinematic wave equation
183-
kwpt.kinematicRouting(discharge, lateral_inflow, constant, self.upstream_lookup,\
190+
kwpt.kinematicRouting(discharge_avg, discharge, lateral_inflow, constant, self.upstream_lookup,\
184191
self.num_upstream_pixels, self.pixels_ordered, self.order_start_stop,\
185-
self.beta, self.inv_beta, self.b_minus_1, a_dx_div_dt, b_a_dx_div_dt)
192+
self.inv_time_delta,self.beta, self.inv_beta, self.b_minus_1, a_dx_div_dt, b_a_dx_div_dt, a_dx)
186193
if self.flagnancheck:
187194
if self.kinematic_wave_warning_printed==False:
188195
if np.all(np.isfinite(discharge))==False:

src/lisflood/hydrological_modules/kinematic_wave_parallel_tools.py

+29-8
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@
3232
# ROUTING FUNCTIONS
3333
# -------------------------------------------------------------------------------------------------
3434
@njit(parallel=True, fastmath=False, cache=True)
35-
def kinematicRouting(discharge, lateral_inflow, constant, upstream_lookup,\
36-
num_upstream_pixels, ordered_pixels, start_stop, beta, inv_beta,\
37-
b_minus_1, a_dx_div_dt, b_a_dx_div_dt):
35+
def kinematicRouting(discharge_avg, discharge, lateral_inflow, constant, upstream_lookup,\
36+
num_upstream_pixels, ordered_pixels, start_stop, inv_time_delta, beta, inv_beta,\
37+
b_minus_1, a_dx_div_dt, b_a_dx_div_dt, a_dx):
3838
"""
3939
This function performs the kinematic wave routing algorithm to simulate the movement of water through a network of interconnected channels.
4040
:param discharge:
@@ -49,6 +49,7 @@ def kinematicRouting(discharge, lateral_inflow, constant, upstream_lookup,\
4949
:param b_minus_1:
5050
:param a_dx_div_dt:
5151
:param b_a_dx_div_dt:
52+
:param a_dx: ChannelAlpha * ChanLength
5253
:return:
5354
"""
5455
num_orders = start_stop.shape[0]
@@ -59,34 +60,43 @@ def kinematicRouting(discharge, lateral_inflow, constant, upstream_lookup,\
5960
# Iterate through each pixel in the current order in parallel
6061
for index in prange(first, last):
6162
# Solve the kinematic wave for the current pixel
62-
solve1Pixel(ordered_pixels[index], discharge, lateral_inflow, constant, upstream_lookup,\
63-
num_upstream_pixels, a_dx_div_dt, b_a_dx_div_dt, beta, inv_beta, b_minus_1)
63+
solve1Pixel(ordered_pixels[index], discharge_avg, discharge, lateral_inflow, constant, upstream_lookup,\
64+
num_upstream_pixels, a_dx_div_dt, b_a_dx_div_dt, inv_time_delta, beta, inv_beta, b_minus_1, a_dx)
6465

6566
@njit(nogil=True, fastmath=False, cache=True)
66-
def solve1Pixel(pix, discharge, lateral_inflow, constant,\
67+
def solve1Pixel(pix, discharge_avg, discharge, lateral_inflow, constant,\
6768
upstream_lookup, num_upstream_pixels, a_dx_div_dt,\
68-
b_a_dx_div_dt, beta, inv_beta, b_minus_1):
69+
b_a_dx_div_dt, inv_time_delta, beta, inv_beta, b_minus_1, a_dx):
6970
"""
7071
Te Chow et al. 1988 - Applied Hydrology - Chapter 9.6
7172
:param pix:
72-
:param discharge:
73+
:param discharge_avg: average outflow discharge
74+
:param discharge: instantaneous outflow discharge
7375
:param lateral_inflow:
7476
:param constant:
7577
:param upstream_lookup:
7678
:param num_upstream_pixels:
7779
:param a_dx_div_dt:
7880
:param b_a_dx_div_dt:
81+
:param inv_time_delta: 1/DtRouting
7982
:param beta:
8083
:param inv_beta:
8184
:param b_minus_1:
85+
:param a_dx: ChannelAlpha * ChanLength
8286
:return:
8387
"""
8488
count = 0
8589
previous_estimate = -1.0
8690
upstream_inflow = 0.0
91+
upstream_inflow_avg = 0.0
92+
93+
# volume of water in channel at beginning of computation step
94+
channel_volume_start = a_dx * discharge[pix]**beta
95+
8796
# Inflow from upstream pixels
8897
for ups_ix in range(num_upstream_pixels[pix]):
8998
upstream_inflow += discharge[upstream_lookup[pix,ups_ix]]
99+
upstream_inflow_avg += discharge_avg[upstream_lookup[pix, ups_ix]]
90100
const_plus_ups_infl = upstream_inflow + constant[pix] # upstream_inflow + alpha*dx/dt*Qold**beta + dx*specific_lateral_inflow
91101
# If old discharge, upstream inflow and lateral inflow are below accuracy: set discharge to 0 and exit
92102
if const_plus_ups_infl <= NEWTON_TOL:
@@ -111,6 +121,17 @@ def solve1Pixel(pix, discharge, lateral_inflow, constant,\
111121
# If iterations converge to NEWTON_TOL, set value to 0
112122
if discharge[pix] == NEWTON_TOL:
113123
discharge[pix] = 0
124+
125+
# cmcheck
126+
# avoid negative discharge
127+
if discharge[pix] < 0:
128+
discharge[pix] = 0
129+
# volume of water in channel at end of computation step
130+
channel_volume_end = a_dx * discharge[pix]**beta
131+
# mass water balance to calc average outflow
132+
discharge_avg[pix] = upstream_inflow_avg + lateral_inflow + (channel_volume_start - channel_volume_end) * inv_time_delta
133+
134+
114135
# to simulate inf or nan: discharge[pix] = 1.0/0.0
115136
# with gil:
116137
# got_valid_value = np.isfinite(discharge[pix])

0 commit comments

Comments
 (0)