solve mass continuity of reservoir using runge kutta method
References:
Chow, V. T., Maidment, D. R. &Mays, L. W. (1988) Applied Hydrology. McGraw-Hill, New York, USA
Fenton, J.D. (1992) Reservoir routing, Hydrological Sciences Journal, 37(3), 233-246, DOI: 10.1080/02626669209492584
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=float), | intent(in) | :: | hini |
initial stage value (m) |
||
| real(kind=float), | intent(in) | :: | Qin_begin |
input discharge at the beginning of time step (m3/s) |
||
| real(kind=float), | intent(in) | :: | Qin_end |
input discharge at the end of time step (m3/s) |
||
| integer, | intent(in) | :: | dt |
time step (s) |
||
| type(Table), | intent(in) | :: | geometry |
geometry of reservoir |
||
| integer, | intent(in) | :: | rk |
solution order 3 or 4 |
||
| integer, | intent(in) | :: | typOut |
type ofoutflow: 1=free flow 2=target level |
||
| real(kind=float), | intent(in) | :: | hTarget |
follow a target (observed) stage (m) |
||
| real(kind=float), | intent(in) | :: | eFlow |
environmental flow (m3/s) |
||
| real(kind=float), | intent(in) | :: | freeFlow |
free flow (m3/s) |
||
| real(kind=float), | intent(in) | :: | freeFlowElevation |
free flow elevation (m asl) |
||
| character(len=3), | intent(in) | :: | QoutDOY |
doy to compute Qout |
||
| real(kind=float), | intent(in) | :: | hmin |
minimum stage value (m) |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=float), | public | :: | Q1third | ||||
| real(kind=float), | public | :: | Q2third | ||||
| real(kind=float), | public | :: | Qout | ||||
| real(kind=float), | public | :: | S1 |
used to compute deltaS (m3) |
|||
| real(kind=float), | public | :: | S2 |
used to compute deltaS (m3) |
|||
| real(kind=float), | public | :: | area | ||||
| real(kind=float), | public | :: | deltaS |
delta storage volume (m3) |
|||
| real(kind=double), | public | :: | dh | ||||
| real(kind=double), | public | :: | dh1 | ||||
| real(kind=double), | public | :: | dh2 | ||||
| real(kind=double), | public | :: | dh3 | ||||
| real(kind=double), | public | :: | dh4 | ||||
| real(kind=float), | public | :: | h1 | ||||
| real(kind=float), | public | :: | h2 | ||||
| real(kind=float), | public | :: | h3 |
FUNCTION RungeKutta & ( hini, Qin_begin, Qin_end, dt, geometry, rk, typOut, hTarget, & eFlow, freeFlow, freeFlowElevation, QoutDOY, hmin ) & RESULT (stage) IMPLICIT NONE ! Function arguments ! Arguments with intent(in): REAL (KIND = float), INTENT(IN) :: hini !!initial stage value (m) REAL (KIND = float), INTENT(IN) :: Qin_begin !!input discharge at the beginning of time step (m3/s) REAL (KIND = float), INTENT(IN) :: Qin_end !!input discharge at the end of time step (m3/s) INTEGER, INTENT(IN) :: dt !!time step (s) TYPE (Table), INTENT(IN) :: geometry !!geometry of reservoir INTEGER, INTENT(IN) :: rk !! solution order 3 or 4 INTEGER, INTENT(IN) :: typOut !!type ofoutflow: 1=free flow 2=target level REAL (KIND = float), INTENT(IN) :: hTarget !!follow a target (observed) stage (m) REAL (KIND = float), INTENT(IN) :: eFlow !!environmental flow (m3/s) REAL (KIND = float), INTENT(IN) :: freeFlow !! free flow (m3/s) REAL (KIND = float), INTENT(IN) :: freeFlowElevation !! free flow elevation (m asl) CHARACTER (LEN = 3), INTENT(IN) :: QoutDOY !!doy to compute Qout REAL (KIND = float), INTENT(IN) :: hmin !!minimum stage value (m) ! Arguments with intent(OUT): REAL (KIND = float) :: stage !local declaration: REAL(KIND = float) :: h1, h2 REAL(KIND = float) :: h3 !used only if rk = 4 REAL(KIND = double) :: dh1, dh2, dh3 REAL(KIND = double) :: dh4 !used only if rk = 4 REAL(KIND = double) :: dh REAL(KIND = float) :: Q1third, Q2third REAL(KIND = float) :: Qout REAL(KIND = float) :: area !(m2) REAL(KIND = float) :: S1, S2 !!used to compute deltaS (m3) REAL(KIND = float) :: deltaS !!delta storage volume (m3) !------------end of declaration------------------------------------------------ SELECT CASE (rk) CASE(2) IF ( typOut == 2 .AND. hini < hTarget) THEN Qout = MIN (eFlow, Qin_begin) !step 1 !find area in table geometry CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut='area', match='linear', & valueOut=area, bound = 'extendconstant' ) !compute dh1 dh1 = DBLE ( (Qin_begin - Qout) * dt / area ) !update h1 h1 = DBLE ( hini + dh1 ) !step 2 !find area in table geometry CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut='area', match='linear', & valueOut=area, bound = 'extendconstant' ) !compute dh2 dh2 = DBLE ( (Qin_end - Qout) * dt / area ) ELSE !step 1 !find Qout IF ( hini <= freeFlowElevation .AND. Qin_begin < freeFlow ) THEN Qout = Qin_begin ELSE CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) IF ( eFlow > 0.) THEN Qout = MAX (eFlow, Qout) END IF END IF !find area in table geometry CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh1 dh1 = DBLE ( (Qin_begin - Qout) * dt / area ) !update h1 h1 = DBLE ( hini + dh1 ) !step2 !find Qout IF ( h1 <= freeFlowElevation .AND. Qin_begin < freeFlow ) THEN Qout = Qin_begin ELSE CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF !find area in table geometry CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh2 dh2 = DBLE ( (Qin_end - Qout) * dt / area ) END IF dh = DBLE ( 0.5 * (dh1 + dh2) ) CASE(3) IF ( typOut == 2 .AND. hini < hTarget) THEN Qout = MIN (eFlow, Qin_begin) !step 1 !find area in table geometry CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut='area', match='linear', & valueOut=area, bound = 'extendconstant' ) !compute dh1 dh1 = DBLE ( (Qin_begin - Qout) * dt / area ) !update h1 h1 = DBLE ( hini + dh1 / 3.0 ) !step 2 Q1third = LinearInterp (0., REAL(dt), Qin_begin, Qin_end, 1.0/3.0*dt) !find area in table geometry CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut='area', match='linear', & valueOut=area, bound = 'extendconstant' ) !compute dh2 dh2 = DBLE ( (Q1third - Qout) * dt / area ) !update h2 h2 = DBLE ( hini + 2.0 * dh2 / 3.0 ) !step 3 Q2third = LinearInterp (0., real(dt), Qin_begin, Qin_end, 2.0/3.0*dt) !find area in table geometry CALL TableGetValue ( valueIn = h2, tab = geometry, keyIn = 'h', & keyOut='area', match='linear', & valueOut=area, bound = 'extendconstant' ) !compute dh3 dh3 = DBLE ( (Q2third - Qout) * dt / area ) ELSE !step 1 !find Qout IF ( hini <= freeFlowElevation .AND. Qin_begin < freeFlow ) THEN Qout = Qin_begin ELSE CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) IF ( eFlow > 0.) THEN Qout = MAX (eFlow, Qout) END IF END IF !find area in table geometry CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh1 dh1 = DBLE ( (Qin_begin - Qout) * dt / area ) !update h1 h1 = DBLE ( hini + dh1 / 3.0 ) !step2 Q1third = LinearInterp (0., REAL(dt), Qin_begin, Qin_end, 1.0/3.0*dt) !find Qout IF ( h1 <= freeFlowElevation .AND. Q1third < freeFlow ) THEN Qout = Q1third ELSE CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF !find area in table geometry CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh2 dh2 = DBLE ( (Q1third - Qout) * dt / area ) !update h2 h2 = DBLE ( hini + 2.0 * dh2 / 3.0 ) !step3 Q2third = LinearInterp (0., real(dt), Qin_begin, Qin_end, 2.0/3.0*dt) !find Qout IF ( h2 <= freeFlowElevation .AND. Q2third < freeFlow ) THEN Qout = Q2third ELSE CALL TableGetValue ( valueIn = h2, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF !find area in table geometry CALL TableGetValue ( valueIn = h2, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh3 dh3 = DBLE ( (Q2third - Qout) * dt / area ) END IF dh = DBLE ( dh1 / 4.0 + 3.0 * dh3 / 4.0 ) CASE(4) !step 1 !find Qout IF ( typOut == 2 .AND. hini < hTarget) THEN Qout = MIN (eFlow, Qin_begin) ELSE IF ( typOut == 2 .AND. hini >= hTarget) THEN CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) IF ( eFlow > 0. ) THEN Qout = MAX (eFlow, Qout) END IF ELSE IF ( hini <= freeFlowElevation .AND. Qin_begin < freeFlow ) THEN Qout = Qin_begin ELSE CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF !find area in table geometry CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh1 dh1 = DBLE( (Qin_begin - Qout) * dt / area) !update h1 h1 = DBLE(hini + dh1 / 3.0) !step2 Q1third = LinearInterp (0., REAL(dt), Qin_begin, Qin_end, 1.0/3.0*dt) IF ( typOut == 1 ) THEN !update Qout IF ( h1 <= freeFlowElevation .AND. Q1third < freeFlow ) THEN Qout = Q1third ELSE CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF END IF !find area in table geometry CALL TableGetValue ( valueIn = h1, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh2 dh2 = DBLE( (Q1third - Qout) * dt / area) !update h2 h2 = DBLE(hini - 1.0 / 3.0 * dh1 + dh2) !step3 Q2third = LinearInterp (0., real(dt), Qin_begin, Qin_end, 2.0/3.0*dt) IF ( typOut == 1 ) THEN !update Qout IF ( h2 <= freeFlowElevation .AND. Q2third < freeFlow ) THEN Qout = Q2third ELSE CALL TableGetValue ( valueIn = h2, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF END IF !find area in table geometry CALL TableGetValue ( valueIn = h2, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh3 dh3 = DBLE ((Q2third - Qout) * dt / area) !update h3 h3 =DBLE( hini + dh1 - dh2 + dh3) !step 4 IF ( typOut == 1 ) THEN !update Qout IF ( h3 <= freeFlowElevation .AND. Qin_end < freeFlow ) THEN Qout = Qin_end ELSE CALL TableGetValue ( valueIn = h3, tab = geometry, keyIn = 'h', & keyOut = QoutDOY, match = 'linear', & valueOut = Qout, bound = 'extendconstant' ) END IF END IF !find area in table geometry CALL TableGetValue ( valueIn = h3, tab = geometry, keyIn = 'h', & keyOut = 'area', match = 'linear', & valueOut = area, bound = 'extendconstant' ) !compute dh4 dh4 = DBLE((Qin_end - Qout) * dt / area) !END IF dh = DBLE(dh1 / 8.0 + 3.0 * dh2 / 8.0 + 3.0 * dh3 / 8.0 + dh4 / 8.0) CASE DEFAULT CALL Catch ('error', 'RungeKutta', 'order Runge-Kutta not valid: ', & argument = ToString(rk)) STOP END SELECT !update reservoir stage stage = DBLE (hini + dh) !detect and filter instability IF (QfilterApply) THEN deltaS = Qfilter * dt !volume for a Qfilter (m3/s) net input discharge !compute S1 volume at previous step stage CALL TableGetValue ( valueIn = hini, tab = geometry, keyIn = 'h', & keyOut = 'volume', match = 'linear', & valueOut = S1, bound = 'extendconstant' ) !compute S2 volume at current step stage CALL TableGetValue ( valueIn = stage, tab = geometry, keyIn = 'h', & keyOut = 'volume', match = 'linear', & valueOut = S2, bound = 'extendconstant' ) IF ( (S2 - S1) > deltaS) THEN !too rapid volume change, possible instability detected stage = hini END IF END IF IF ( stage < hmin ) THEN stage = hmin END IF RETURN END FUNCTION RungeKutta