Soil Water Balance (SWB2)
Loading...
Searching...
No Matches
runoff__curve_number.F90
Go to the documentation of this file.
2
3 use iso_c_binding, only : c_int, c_float, c_double, c_bool
5 use datetime
6 use exceptions
8 use fstring
10 use parameters, only : params, params_dict
11 implicit none
12
13 private
14
15 real (c_float), allocatable :: cn_arciii(:,:)
16 real (c_float), allocatable :: cn_arcii(:,:)
17 real (c_float), allocatable :: cn_arci(:,:)
18 real (c_float), allocatable :: prev_5_days_rain(:,:)
19 integer (c_int), allocatable :: ilandusecodes(:)
20 integer (c_int) :: daycount
21 integer (c_int), parameter :: five_day_sum = 6
22
23
28 public :: cn_arci, cn_arcii, cn_arciii
30
31 real (c_float), parameter :: amc_dry_growing = 1.40_c_float
32 real (c_float), parameter :: amc_dry_dormant = 0.50_c_float
33 real (c_float), parameter :: amc_wet_growing = 2.10_c_float
34 real (c_float), parameter :: amc_wet_dormant = 1.10_c_float
35
37
38contains
39
40 subroutine runoff_curve_number_initialize( cell_is_active )
41
42 use ieee_arithmetic, only : ieee_is_nan, ieee_is_finite
43
44 logical (c_bool), intent(in) :: cell_is_active(:,:)
45
46 ! [ LOCALS ]
47 integer (c_int) :: inumberoflanduses
48 integer (c_int) :: inumberofsoilgroups
49 integer (c_int), allocatable :: icurvenumberseqnums(:)
50 type (fstring_list_t) :: sllist
51 type (fstring_list_t) :: slcurvenumber
52 integer (c_int) :: istat
53 integer (c_int) :: isoilsindex
54 character (len=:), allocatable :: stext
55 real (c_float), allocatable :: cn(:)
56
57 call sllist%append("LU_Code")
58 call sllist%append("Landuse_Lookup_Code")
59
60 !> Determine how many soil groups are present
61
62 ! retrieve a string list of all keys associated with curve number (i.e. "CN_1", "CN_2", "CN_3", etc)
63 slcurvenumber = params%grep_name( "CN", lfatal=true )
64
65 ! Convert the string list to an vector of integers; this call strips off the "CN_" part of label
66 icurvenumberseqnums = slcurvenumber%get_integer()
67
68 ! count how many items are present in the vector; this should equal the number of soils groups
69 inumberofsoilgroups = count( icurvenumberseqnums > 0 )
70
71 !> Determine how many landuse codes are present
72 call params%get_parameters( slkeys=sllist, ivalues=ilandusecodes )
73 inumberoflanduses = count( ilandusecodes >= 0 )
74
75 allocate( cn_arciii(inumberoflanduses, inumberofsoilgroups), stat=istat )
76 call assert( istat == 0, "Failed to allocate memory for curve number table - AMC III", &
77 __file__, __line__)
78
79 allocate( cn_arcii(inumberoflanduses, inumberofsoilgroups), stat=istat )
80 call assert( istat == 0, "Failed to allocate memory for curve number table - AMC II", &
81 __file__, __line__)
82
83 allocate( cn_arci(inumberoflanduses, inumberofsoilgroups), stat=istat )
84 call assert( istat == 0, "Failed to allocate memory for curve number table - AMC I", &
85 __file__, __line__)
86
87 ! we should have the curve number table fully filled out following this block
88 do isoilsindex = 1, inumberofsoilgroups
89 stext = "CN_"//ascharacter(isoilsindex)
90 call params%get_parameters( skey=stext, fvalues=cn )
91 cn_arcii(:, isoilsindex) = cn
92 enddo
93
94 allocate( prev_5_days_rain( count(cell_is_active), 6 ), stat=istat )
95 call assert( istat == 0, "Failed to allocate memory for curve number PREV_5_DAYS_RAIN table", &
96 __file__, __line__)
97
98 prev_5_days_rain = 0.0_c_float
99
100 ! DAYCOUNT will vary from 1 to 5 and serve as the second index value for
101 ! PREV_5_DAYS_RAIN
102 daycount = 0
103
104 ! calculate curve numbers for antecedent runof conditions I and III
107
108 call date_last_updated%parsedate("01/01/1000")
109
110 end subroutine runoff_curve_number_initialize
111
112
113!--------------------------------------------------------------------------------------------------
114
115 elemental function prob_runoff_enhancement( fCFGI, fCFGI_UL, fCFGI_LL ) result(fPf)
116
117 real (c_float), intent(in) :: fcfgi
118 real (c_float), intent(in) :: fcfgi_ul
119 real (c_float), intent(in) :: fcfgi_ll
120
121 real (c_float) :: fpf
122
123 if(fcfgi <= fcfgi_ll ) then
124 fpf = 0_c_float
125 elseif(fcfgi >= fcfgi_ul) then
126 fpf = 1.0_c_float
127 else
128 fpf = ( fcfgi - fcfgi_ll ) / ( fcfgi_ul - fcfgi_ll )
129 end if
130
131 end function prob_runoff_enhancement
132
133!--------------------------------------------------------------------------------------------------
134
135 subroutine update_previous_5_day_rainfall( infil, indx )
136
137 real (c_float), intent(in) :: infil
138 integer (c_int), intent(in) :: indx
139
140 ! we only want to increment DAYCOUNT 1x per day!
141 if ( .not. date_last_updated == sim_dt%curr ) then
142
143 if ( daycount < 5 ) then
144 daycount = daycount + 1
145 else
146 daycount = 1
147 endif
148
150
151 endif
152
153 prev_5_days_rain( indx, daycount ) = infil
154 prev_5_days_rain( indx, five_day_sum ) = sum( prev_5_days_rain( indx, 1:5 ) )
155
156 end subroutine
157!--------------------------------------------------------------------------------------------------
158
159 elemental function update_curve_number_fn( iLanduseIndex, iSoilsIndex, cell_index, &
160 it_is_growing_season, fSoilStorage_Max, &
161 fCFGI, fCFGI_LL, fCFGI_UL ) result( CN_adj )
162
163 integer (c_int), intent(in) :: ilanduseindex
164 integer (c_int), intent(in) :: isoilsindex
165 integer (c_int), intent(in) :: cell_index
166 logical (c_bool), intent(in) :: it_is_growing_season
167 real (c_float), intent(in) :: fsoilstorage_max
168 real (c_float), intent(in) :: fcfgi
169 real (c_float), intent(in) :: fcfgi_ll
170 real (c_float), intent(in) :: fcfgi_ul
171 real (c_float) :: cn_adj
172
173 ! [ LOCALS ]
174 real (c_float) :: pf
175 real (c_float) :: finflow
176
177 finflow = prev_5_days_rain( cell_index, five_day_sum )
178
179 associate( cn_i => cn_arci( ilanduseindex, isoilsindex ), &
180 cn_ii => cn_arcii( ilanduseindex, isoilsindex ), &
181 cn_iii => cn_arciii( ilanduseindex, isoilsindex ) )
182
183 ! Correct the curve number...
184 if( ( fcfgi > fcfgi_ll ) .and. ( fsoilstorage_max > 0.0_c_float ) ) then
185
186 pf = prob_runoff_enhancement( fcfgi=fcfgi, &
187 fcfgi_ul=fcfgi_ul, &
188 fcfgi_ll=fcfgi_ll )
189
190 ! use probability of runoff enhancement to calculate a weighted
191 ! average of curve number under Type II vs Type III antecedent
192 ! runoff conditions
193 cn_adj = cn_ii * (1-pf) + cn_iii * pf
194
195 else if ( it_is_growing_season ) then
196
197 if ( finflow < amc_dry_growing ) then
198
199 cn_adj = cn_i
200
201 else if ( finflow >= amc_dry_growing &
202 .and. finflow < amc_wet_growing ) then
203
204 cn_adj = cn_ii
205
206 else
207
208 cn_adj = cn_iii
209
210 end if
211
212 else ! dormant (non-growing) season
213
214 if ( finflow < amc_dry_dormant ) then
215
216 cn_adj = cn_i
217
218 else if ( finflow >= amc_dry_dormant &
219 .and. finflow < amc_wet_dormant ) then
220
221 cn_adj = cn_ii
222
223 else
224
225 cn_adj = cn_iii
226
227 end if
228
229 end if
230
231 end associate
232
233 ! ensure that whatever modification have been made to the curve number
234 ! remain within reasonable bounds
235 cn_adj = min(cn_adj,100.0_c_float)
236 cn_adj = max(cn_adj,30.0_c_float)
237
238
239 end function update_curve_number_fn
240
241!--------------------------------------------------------------------------------------------------
242
243 elemental function cn_ii_to_cn_iii(CN_II) result(CN_III)
244
245 real (c_float), intent(in) :: cn_ii
246 real (c_float) :: cn_iii
247
248 cn_iii = cn_ii / ( 0.427_c_float + 0.00573_c_float * cn_ii )
249
250 cn_iii = max( cn_iii, 30.0_c_float )
251 cn_iii = min( cn_iii, 100.0_c_float )
252
253 end function cn_ii_to_cn_iii
254
255!--------------------------------------------------------------------------------------------------
256
257 elemental function cn_ii_to_cn_i(CN_II) result(CN_I)
258
259 real (c_float), intent(in) :: cn_ii
260 real (c_float) :: cn_i
261
262 ! The following comes from page 192, eq. 3.145 of "SCS Curve Number Methodology"
263 cn_i = cn_ii / (2.281_c_float - 0.01281_c_float * cn_ii )
264
265 cn_i = max( cn_i, 30.0_c_float )
266 cn_i = min( cn_i, 100.0_c_float )
267
268 end function cn_ii_to_cn_i
269
270!--------------------------------------------------------------------------------------------------
271 !> Calculate the runoff by means of the curve number method.
272 !!
273 !! Runoff is calculated using a modification of the curve number method.
274 !! Specifically, the initial abstraction is defined as 0.05 * SMax rather than the
275 !! standard 0.20 * SMax of the original method. This redefinition of the initial abstraction
276 !! term was found to be more appropriate for long-term continuous simulations than the
277 !! standard 0.2 * SMax of the original.
278 !! @param[in] iLanduseIndex Pre-configured index number corresponding to a line in the landuse lookup table.
279 !! @param[in] iSoilsGroup The numerical index associated with the soils group of interest.
280 !! @param[in] fInflow The sum of net rainfall, snowmelt, and runon from upslope cells (and possibly irrigation).
281 !! @param[in] fCFGI The current value of the continuous frozen-ground index.
282 !! @param[in] lIsGrowingSeason Logical value indicating whether dormant season or growing season
283 !! criteria values are to be used when calculating runoff.
284 !!
285 !! @retval fRunoff Daily runoff calculated by means of the SCS Curve Number method.
286 !!
287 !! @note Reference: Woodward, D. E., R. H. Hawkins, R. Jiang, A. Hjelmfeldt Jr, J. Van Mullem,
288 !! and Q. D. Quan. "Runoff Curve Number Method: Examination of the Initial Abstraction Ratio."
289 !! In Conference Proceeding Paper, World Water and Environmental Resources Congress, 2003.
290 elemental subroutine runoff_curve_number_calculate(runoff, &
291 curve_num_adj, &
292 cell_index, &
293 landuse_index, &
294 soil_group, &
295 it_is_growing_season, &
296 inflow, &
297 soil_storage_max, &
298 continuous_frozen_ground_index, &
299 cfgi_lower_limit, &
300 cfgi_upper_limit )
301
302 real (c_float), intent(inout) :: runoff
303 real (c_float), intent(inout) :: curve_num_adj
304 integer (c_int), intent(in) :: cell_index
305 integer (c_int), intent(in) :: landuse_index
306 integer (c_int), intent(in) :: soil_group
307 logical (c_bool), intent(in) :: it_is_growing_season
308 real (c_float), intent(in) :: inflow
309 real (c_float), intent(in) :: soil_storage_max
310 real (c_float), intent(in) :: continuous_frozen_ground_index
311 real (c_float), intent(in) :: cfgi_lower_limit
312 real (c_float), intent(in) :: cfgi_upper_limit
313
314 ! [ LOCALS ]
315! real (c_float) :: CN_05
316 real (c_float) :: smax
317
318 curve_num_adj = update_curve_number_fn( landuse_index, soil_group, &
319 cell_index, &
320 it_is_growing_season, &
321 soil_storage_max, &
323 cfgi_lower_limit, &
324 cfgi_upper_limit )
325
326 smax = ( 1000.0_c_float / curve_num_adj ) - 10.0_c_float
327
328! ! Equation 9, Hawkins and others, 2002
329! CN_05 = 100_c_float / &
330! ((1.879_c_float * ((100.0_c_float / CN_adj ) - 1.0_c_float )**1.15_c_float) + 1.0_c_float)
331
332 ! Equation 8, Hawkins and others, 2002
333 ! adjust Smax for alternate initial abstraction amount
334 smax = 1.33_c_float * ( smax**1.15_c_float )
335
336 ! now consider runoff if Ia ~ 0.05S
337 if ( inflow > 0.05_c_float * smax ) then
338 runoff = ( inflow - 0.05_c_float * smax )**2 / ( inflow + 0.95_c_float * smax )
339 else
340 runoff = 0.0_c_float
341 end if
342
343 end subroutine runoff_curve_number_calculate
344
345end module runoff__curve_number
This module contains physical constants and convenience functions aimed at performing unit conversion...
logical(c_bool), parameter, public true
logical(c_bool), parameter, public false
This module contains the DATETIME_T class and associated time and date-related routines,...
Definition datetime.F90:9
type(parameters_t), public params
type(dict_t), public params_dict
integer(c_int), parameter, public five_day_sum
elemental real(c_float) function, public update_curve_number_fn(ilanduseindex, isoilsindex, cell_index, it_is_growing_season, fsoilstorage_max, fcfgi, fcfgi_ll, fcfgi_ul)
type(datetime_t) date_last_updated
elemental real(c_float) function cn_ii_to_cn_i(cn_ii)
real(c_float), parameter amc_dry_growing
elemental real(c_float) function cn_ii_to_cn_iii(cn_ii)
elemental subroutine, public runoff_curve_number_calculate(runoff, curve_num_adj, cell_index, landuse_index, soil_group, it_is_growing_season, inflow, soil_storage_max, continuous_frozen_ground_index, cfgi_lower_limit, cfgi_upper_limit)
Calculate the runoff by means of the curve number method.
real(c_float), dimension(:,:), allocatable, public prev_5_days_rain
subroutine, public update_previous_5_day_rainfall(infil, indx)
real(c_float), parameter amc_wet_growing
real(c_float), parameter amc_dry_dormant
real(c_float), dimension(:,:), allocatable, public cn_arciii
real(c_float), dimension(:,:), allocatable, public cn_arci
subroutine, public runoff_curve_number_initialize(cell_is_active)
real(c_float), parameter amc_wet_dormant
real(c_float), dimension(:,:), allocatable, public cn_arcii
integer(c_int), dimension(:), allocatable ilandusecodes
elemental real(c_float) function prob_runoff_enhancement(fcfgi, fcfgi_ul, fcfgi_ll)
type(date_range_t), public sim_dt