Soil Water Balance (SWB2)
Loading...
Searching...
No Matches
crop_coefficients__fao56.F90
Go to the documentation of this file.
1!> @file
2!> Contains a single module, \ref crop_coefficients__fao56, which
3!> provides support for modifying reference ET through the use of
4!> crop coefficients
5
6!> Update crop coefficients for crop types in simulation.
7
9
10 use iso_c_binding, only : c_bool, c_short, c_int, c_float, c_double
14 use data_catalog, only : dat
16 use datetime
17 use logfiles, only : logs, log_all
18 use exceptions, only : assert, warn, die
19 use parameters, only : params
20 use simulation_datetime, only : sim_dt
21 use fstring, only : ascharacter, squote, operator(.contains.)
22 use fstring_list
23 implicit none
24
25 private
26
33 public :: kcb_min, kcb_ini, kcb_mid, kcb_end
36
37 enum, bind(c)
39 end enum
40
41 enum, bind(c)
43 end enum
44
45 enum, bind(c)
48 end enum
49
50 enum, bind(c)
51 enumerator :: kcb_ini=13, kcb_mid, kcb_end, kcb_min
52 end enum
53
54 enum, bind(c)
55 enumerator :: jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
56 end enum
57
58 enum, bind(c)
60 end enum
61
62 ! Private, module level variables
63 ! kept at a landuse code level (i.e. same value applies to all cells with same LU codes)
64 integer (c_int), allocatable :: landuse_code(:)
65! real (c_float), allocatable :: REW(:,:)
66! real (c_float), allocatable :: TEW(:,:)
67 real (c_float), allocatable :: kcb_l(:,:)
68 integer (c_int), allocatable :: kcb_method(:)
69 real (c_float), allocatable :: growth_stage_length_in_days(:,:)
70 real (c_float), allocatable :: growth_stage_gdd(:,:)
71 type (datetime_t), allocatable :: growth_stage_date(:,:)
73
74contains
75
76
77 function crop_coefficients_calculate_planting_date(sPlantingDate, iYear) result(dtNewPlantingDate)
78 character(len=*), intent(in) :: splantingdate
79 integer (c_int), intent(in) :: iyear
80 type (datetime_t) :: dtnewplantingdate
81
82 ! [ LOCAL ]
83 character (len=10) :: smmddyyyy
84
85 if ( splantingdate .contains. "/" ) then
86 smmddyyyy = trim(splantingdate)//"/"//ascharacter( iyear )
87 call dtnewplantingdate%parsedate( smmddyyyy, __file__, __line__ )
88
89 else
90 ! assume the value is a day-of-year value
91 smmddyyyy = "01/01/"//ascharacter( iyear )
92 call dtnewplantingdate%parsedate( smmddyyyy, __file__, __line__ )
93 dtnewplantingdate = dtnewplantingdate + ( asfloat( splantingdate ) - 1.0_c_float )
94 call dtnewplantingdate%calcJulianDay()
95 endif
96
98
99
101
102 ! [ LOCALS ]
103 ! type (FSTRING_LIST_T) :: slREW, slTEW
104 type (fstring_list_t) :: sllist
105 ! integer (c_int), allocatable :: iTEWSeqNums(:)
106 ! integer (c_int), allocatable :: iREWSeqNums(:)
107 integer (c_int) :: inumberoflanduses
108 integer (c_int) :: iindex
109 integer (c_int) :: istat
110
111
112 !type (FSTRING_LIST_T) :: slPlantingDate
113 character (len=:), allocatable :: plantingdate_str
114
115 real (c_float), allocatable :: l_ini_l(:)
116 real (c_float), allocatable :: l_dev_l(:)
117 real (c_float), allocatable :: l_mid_l(:)
118 real (c_float), allocatable :: l_late_l(:)
119 real (c_float), allocatable :: l_fallow_l(:)
120
121 real (c_float), allocatable :: gdd_plant_l(:)
122 real (c_float), allocatable :: gdd_ini_l(:)
123 real (c_float), allocatable :: gdd_dev_l(:)
124 real (c_float), allocatable :: gdd_mid_l(:)
125 real (c_float), allocatable :: gdd_late_l(:)
126
127
128 real (c_float), allocatable :: kcb_ini_l(:)
129 real (c_float), allocatable :: kcb_mid_l(:)
130 real (c_float), allocatable :: kcb_end_l(:)
131 real (c_float), allocatable :: kcb_min_l(:)
132
133 real (c_float), allocatable :: kcb_jan(:)
134 real (c_float), allocatable :: kcb_feb(:)
135 real (c_float), allocatable :: kcb_mar(:)
136 real (c_float), allocatable :: kcb_apr(:)
137 real (c_float), allocatable :: kcb_may(:)
138 real (c_float), allocatable :: kcb_jun(:)
139 real (c_float), allocatable :: kcb_jul(:)
140 real (c_float), allocatable :: kcb_aug(:)
141 real (c_float), allocatable :: kcb_sep(:)
142 real (c_float), allocatable :: kcb_oct(:)
143 real (c_float), allocatable :: kcb_nov(:)
144 real (c_float), allocatable :: kcb_dec(:)
145
146
147
148 !> create string list that allows for alternate heading identifiers for the landuse code
149 sllist = create_list("LU_Code, Landuse_Code, Landuse_Lookup_Code")
150
151 !> Determine how many landuse codes are present
152 call params%get_parameters( slkeys=sllist, ivalues=landuse_code )
153 inumberoflanduses = count( landuse_code >= 0 )
154 !> @todo Implement thorough input error checking:
155 !! are all soils in grid included in table values?
156 !> is soil suffix vector continuous?
157
158 ! Retrieve and populate the Readily Evaporable Water (REW) table values
159 ! CALL PARAMS%get_parameters( fValues=REW, sPrefix="REW_", iNumRows=iNumberOfLanduses )
160
161 ! Retrieve and populate the Total Evaporable Water (TEW) table values
162 ! CALL PARAMS%get_parameters( fValues=TEW, sPrefix="TEW_", iNumRows=iNumberOfLanduses )
163
164 !> @TODO What should happen if the TEW / REW header entries do *not* fall in a
165 !! logical sequence of values? In other words, if the user has columns named
166 !! REW_1, REW_3, REW_5, only the values associated with "REW_1" would be retrieved.
167 !! Needless to say, this would be catastrophic.
168
169 call params%get_parameters( skey="Planting_date", slvalues=sl_planting_date )
170
171 call params%get_parameters( skey="L_ini", fvalues=l_ini_l)
172 call params%get_parameters( skey="L_dev", fvalues=l_dev_l)
173 call params%get_parameters( skey="L_mid", fvalues=l_mid_l)
174 call params%get_parameters( skey="L_late", fvalues=l_late_l)
175 call params%get_parameters( skey="L_fallow", fvalues=l_fallow_l)
176
177 call params%get_parameters( skey="GDD_plant", fvalues=gdd_plant_l)
178 call params%get_parameters( skey="GDD_ini", fvalues=gdd_ini_l)
179 call params%get_parameters( skey="GDD_dev", fvalues=gdd_dev_l)
180 call params%get_parameters( skey="GDD_mid", fvalues=gdd_mid_l)
181 call params%get_parameters( skey="GDD_late", fvalues=gdd_late_l)
182
183 call params%get_parameters( skey="Kcb_ini", fvalues=kcb_ini_l)
184 call params%get_parameters( skey="Kcb_mid", fvalues=kcb_mid_l)
185 call params%get_parameters( skey="Kcb_end", fvalues=kcb_end_l)
186 call params%get_parameters( skey="Kcb_min", fvalues=kcb_min_l)
187
188 call params%get_parameters( skey="Kcb_Jan", fvalues=kcb_jan )
189 call params%get_parameters( skey="Kcb_Feb", fvalues=kcb_feb )
190 call params%get_parameters( skey="Kcb_Mar", fvalues=kcb_mar )
191 call params%get_parameters( skey="Kcb_Apr", fvalues=kcb_apr )
192 call params%get_parameters( skey="Kcb_May", fvalues=kcb_may )
193 call params%get_parameters( skey="Kcb_Jun", fvalues=kcb_jun )
194 call params%get_parameters( skey="Kcb_Jul", fvalues=kcb_jul )
195 call params%get_parameters( skey="Kcb_Aug", fvalues=kcb_aug )
196 call params%get_parameters( skey="Kcb_Sep", fvalues=kcb_sep )
197 call params%get_parameters( skey="Kcb_Oct", fvalues=kcb_oct )
198 call params%get_parameters( skey="Kcb_Nov", fvalues=kcb_nov )
199 call params%get_parameters( skey="Kcb_Dec", fvalues=kcb_dec )
200
201
202 allocate( growth_stage_length_in_days( 5, inumberoflanduses ), stat=istat )
203 call assert( istat==0, "Failed to allocate memory for GROWTH_STAGE_LENGTH_IN_DAYS array", &
204 __file__, __line__ )
205
206 allocate( growth_stage_gdd( 5, inumberoflanduses ), stat=istat )
207 call assert( istat==0, "Failed to allocate memory for GROWTH_STAGE_GDD array", &
208 __file__, __line__ )
209
210 allocate( growth_stage_date( 6, inumberoflanduses ), stat=istat )
211 call assert( istat==0, "Failed to allocate memory for GROWTH_STAGE_DATE array", &
212 __file__, __line__ )
213
214 allocate( kcb_l( 16, inumberoflanduses ), stat=istat )
215 call assert( istat==0, "Failed to allocate memory for KCB_l array", &
216 __file__, __line__ )
217
218 allocate( kcb_method( inumberoflanduses ), stat=istat )
219 call assert( istat==0, "Failed to allocate memory for KCB_METHOD vector", &
220 __file__, __line__ )
221
222 kcb_method = -9999
223 kcb_l = -9999.
224 growth_stage_gdd = -9999.
226
227 if ( ubound(l_ini_l,1) == inumberoflanduses ) &
229
230 if ( ubound(l_dev_l,1) == inumberoflanduses ) &
232
233 if ( ubound(l_mid_l,1) == inumberoflanduses ) &
235
236 if ( ubound(l_late_l,1) == inumberoflanduses ) &
238
239 if ( ubound(l_fallow_l,1) == inumberoflanduses ) &
241
242 call logs%write(" ## Crop Kcb Curve Summary ##", ilinesafter=1)
243 call logs%write(" _only meaningful for landuses where the Kcb curve is defined " &
244 //"in terms of days _", ilinesafter=1)
245 call logs%write("Landuse Code | Planting Date | End of 'ini' | End of 'dev' " &
246 //"| End of 'mid' | End of 'late' | End of 'fallow' ")
247 call logs%write("-------------|---------------|--------------|--------------" &
248 //"|--------------|---------------|-----------------")
249
250 if ( sl_planting_date%count == inumberoflanduses .and. sl_planting_date%count > 0 ) then
251
252 do iindex=1, sl_planting_date%count
253
254 plantingdate_str = sl_planting_date%get( iindex )
255
256 ! if there is no planting date entry, assume user is specifying
257 ! a planting GDD for this landuse code
258 if ( len_trim(plantingdate_str) == 0 ) cycle
259
260 ! if ( PlantingDate_str .contains. "/" ) then
261
262 ! ! append current year to the end of the user-entered planting date in mm/dd
263 ! sMMDDYYYY = trim(PlantingDate_str)//"/"//asCharacter( SIM_DT%start%iYear )
264 ! call GROWTH_STAGE_DATE( PLANTING_DATE, iIndex)%parsedate( sMMDDYYYY, __FILE__, __LINE__ )
265
266 ! GROWTH_STAGE_DATE( PLANTING_DATE, iIndex) = GROWTH_STAGE_DATE( PLANTING_DATE, iIndex)
267
268 ! else
269 ! ! assume the value is a day-of-year value
270 ! dtPlantingDate = SIM_DT%start + asFloat( PlantingDate_str)
271 ! call dtPlantingDate%calcJulianDay()
272 ! GROWTH_STAGE_DATE( PLANTING_DATE, iIndex) = dtPlantingDate
273 ! endif
274
275 growth_stage_date( planting_date, iindex) = &
276 crop_coefficients_calculate_planting_date(splantingdate=plantingdate_str, &
277 iyear=sim_dt%start%iYear)
278
279 ! march forward through time calculating the various dates on the Kcb curve
280 ! GROWTH_STAGE_DATE( ENDDATE_INI, iIndex ) = GROWTH_STAGE_DATE( PLANTING_DATE, iIndex ) + L_ini_l( iIndex )
281 ! GROWTH_STAGE_DATE( ENDDATE_DEV, iIndex ) = GROWTH_STAGE_DATE( ENDDATE_INI, iIndex ) + L_dev_l( iIndex )
282 ! GROWTH_STAGE_DATE( ENDDATE_MID, iIndex ) = GROWTH_STAGE_DATE( ENDDATE_DEV, iIndex ) + L_mid_l( iIndex )
283 ! GROWTH_STAGE_DATE( ENDDATE_LATE, iIndex ) = GROWTH_STAGE_DATE( ENDDATE_MID, iIndex ) + L_late_l( iIndex )
284 ! GROWTH_STAGE_DATE( ENDDATE_FALLOW, iIndex ) = GROWTH_STAGE_DATE( ENDDATE_LATE, iIndex ) + L_fallow_l( iIndex )
285
286 ! if any of the L_* length values is missing, a value of zero will be used, resulting in a wierd looking Kcb curve
297
298 call logs%write( "| "//ascharacter( landuse_code( iindex ))//" | " &
299 //trim( growth_stage_date( planting_date, iindex )%prettydate() ) &
300 //" (doy:"//ascharacter( growth_stage_date( planting_date, iindex )%getDayOfYear() )//") | " &
301 //trim( growth_stage_date( enddate_ini, iindex )%prettydate() )//" | " &
302 //" (doy:"//ascharacter( growth_stage_date( enddate_ini, iindex )%getDayOfYear() )//") | " &
303 //trim( growth_stage_date( enddate_dev, iindex )%prettydate() )//" | " &
304 //" (doy:"//ascharacter( growth_stage_date( enddate_dev, iindex )%getDayOfYear() )//") | " &
305 //trim( growth_stage_date( enddate_mid, iindex )%prettydate() )//" | " &
306 //" (doy:"//ascharacter( growth_stage_date( enddate_mid, iindex )%getDayOfYear() )//") | " &
307 //trim( growth_stage_date( enddate_late, iindex )%prettydate() )//" | " &
308 //" (doy:"//ascharacter( growth_stage_date( enddate_late, iindex )%getDayOfYear() )//") | " &
309 //trim( growth_stage_date( enddate_fallow, iindex )%prettydate() ) &
310 //" (doy:"//ascharacter( growth_stage_date( enddate_fallow, iindex )%getDayOfYear() )//") | ")
311 enddo
312
313 endif
314
315 if (ubound(gdd_plant_l,1) == inumberoflanduses) growth_stage_gdd( gdd_plant, : ) = gdd_plant_l
316 if (ubound(gdd_ini_l,1) == inumberoflanduses) growth_stage_gdd( gdd_ini, : ) = gdd_ini_l
317 if (ubound(gdd_dev_l,1) == inumberoflanduses) growth_stage_gdd( gdd_dev, : ) = gdd_dev_l
318 if (ubound(gdd_mid_l,1) == inumberoflanduses) growth_stage_gdd( gdd_mid, : ) = gdd_mid_l
319 if (ubound(gdd_late_l,1) == inumberoflanduses) growth_stage_gdd( gdd_late, : ) = gdd_late_l
320
321 if (ubound(kcb_ini_l,1) == inumberoflanduses) kcb_l( kcb_ini, :) = kcb_ini_l
322 if (ubound(kcb_mid_l,1) == inumberoflanduses) kcb_l( kcb_mid, :) = kcb_mid_l
323 if (ubound(kcb_end_l,1) == inumberoflanduses) kcb_l( kcb_end, :) = kcb_end_l
324 if (ubound(kcb_min_l,1) == inumberoflanduses) kcb_l( kcb_min, :) = kcb_min_l
325
326 if (ubound(kcb_jan,1) == inumberoflanduses) kcb_l( jan, :) = kcb_jan
327 if (ubound(kcb_feb,1) == inumberoflanduses) kcb_l( feb, :) = kcb_feb
328 if (ubound(kcb_mar,1) == inumberoflanduses) kcb_l( mar, :) = kcb_mar
329 if (ubound(kcb_apr,1) == inumberoflanduses) kcb_l( apr, :) = kcb_apr
330 if (ubound(kcb_may,1) == inumberoflanduses) kcb_l( may, :) = kcb_may
331 if (ubound(kcb_jun,1) == inumberoflanduses) kcb_l( jun, :) = kcb_jun
332 if (ubound(kcb_jul,1) == inumberoflanduses) kcb_l( jul, :) = kcb_jul
333 if (ubound(kcb_aug,1) == inumberoflanduses) kcb_l( aug, :) = kcb_aug
334 if (ubound(kcb_sep,1) == inumberoflanduses) kcb_l( sep, :) = kcb_sep
335 if (ubound(kcb_oct,1) == inumberoflanduses) kcb_l( oct, :) = kcb_oct
336 if (ubound(kcb_nov,1) == inumberoflanduses) kcb_l( nov, :) = kcb_nov
337 if (ubound(kcb_dec,1) == inumberoflanduses) kcb_l( dec, :) = kcb_dec
338
339 ! go through the table values and try to figure out how Kcb curves should be constructed:
340 ! Monthly Kcb, GDD-based, or DOY-based
341 do iindex = lbound( kcb_method, 1), ubound( kcb_method, 1)
342
343 if ( all( kcb_l( jan:dec, iindex ) > 0.0_c_float ) ) then
345 kcb_l( kcb_min, iindex ) = minval( kcb_l(jan:dec, iindex) )
346 kcb_l( kcb_mid, iindex) = minval( kcb_l(jan:dec, iindex) )
347
348 elseif ( all( growth_stage_gdd( :, iindex ) >= 0.0_c_float ) &
349 .and. all( kcb_l( kcb_ini:kcb_min, iindex ) > 0.0_c_float ) ) then
350 kcb_method( iindex ) = kcb_method_gdd
351
352 elseif ( all( growth_stage_length_in_days( planting_date:, iindex ) >= 0.0_c_float ) &
353 .and. all( kcb_l( kcb_ini:kcb_min, iindex ) > 0.0_c_float ) ) then
354 kcb_method( iindex ) = kcb_method_fao56
355 endif
356
357 if ( kcb_method( iindex ) < 0 ) then
358 call warn("There are missing day-of-year (L_ini, L_dev, L_mid, L_late, L_fallow), " &
359 //"growing degree-day ~(GDD_plant, GDD_ini, GDD_dev, GDD_mid, GDD_late)," &
360 //" or monthly crop ~coefficients (Kcb_jan...Kcb_dec) for" &
361 //" landuse "//ascharacter( landuse_code( iindex ) ), lfatal=true )
362 endif
363
364 enddo
365
366! do iIndex = lbound( fSoilStorage, 1 ), ubound( fSoilStorage,1 )
367
368! fKcb_initial = update_crop_coefficient_date_as_threshold( iLanduseIndex( iIndex ) )
369
370 ! call calc_effective_root_depth( fRz_i=fRz_initial, iLanduseIndex=iLanduseIndex( iIndex ), &
371 ! fZr_max=fMax_Rooting_Depths( iLanduseIndex( iIndex ), &
372 ! iSoilGroup( iIndex ) ), &
373 ! Kcb=fKcb_initial )
374 !
375 ! fSoilStorage( iIndex ) = INITIAL_PERCENT_SOIL_MOISTURE( iIndex ) / 100.0_c_float &
376 ! * fRz_initial * fAvailable_Water_Content( iIndex )
377
378! enddo
379
380 !> @TODO Add more logic here to perform checks on the validity of this data.
381
382 !> @TODO Need to handle missing values. WHat do we do if an entire column of values
383 !! is missing?
384
386
387!------------------------------------------------------------------------------
388
389 !> Update the current basal crop coefficient (Kcb) for
390 !! a SINGLE irrigation table entry
391 !!
392 !! @param[inout] pIRRIGATION pointer to a single line of information in the irrigation file.
393 !! @param[in] iThreshold either the current day of year or the number of growing degree days.
394 !! @retval rKcb Basal crop coefficient given the irrigation table entries and the
395 !! current threshold values.
396
397 impure elemental function update_crop_coefficient_date_as_threshold( iLanduseIndex ) &
398 result(kcb)
399
400 integer (c_int), intent(in) :: ilanduseindex
401 real (c_float) :: kcb
402
403 ! [ LOCALS ]
404 real (c_double) :: ffrac
405
406 if ( kcb_method( ilanduseindex ) == kcb_method_monthly_values ) then
407
408 kcb = kcb_l( sim_dt%curr%iMonth, ilanduseindex )
409
410 else
411
412 ! define shorthand variable names for remainder of function
413 associate( date_ini => growth_stage_date( enddate_ini, ilanduseindex ), &
414 date_dev => growth_stage_date( enddate_dev, ilanduseindex ), &
415 date_mid => growth_stage_date( enddate_mid, ilanduseindex ), &
416 date_late => growth_stage_date( enddate_late, ilanduseindex ), &
417 date_fallow => growth_stage_date( enddate_fallow, ilanduseindex ), &
418 kcb_ini => kcb_l(kcb_ini, ilanduseindex), &
419 kcb_mid => kcb_l(kcb_mid, ilanduseindex), &
420 kcb_min => kcb_l(kcb_min, ilanduseindex), &
421 plantingdate => growth_stage_date( planting_date, ilanduseindex), &
422 kcb_end => kcb_l(kcb_end, ilanduseindex), &
423 current_date => sim_dt%curr )
424
425 ! now calculate Kcb for the given landuse
426
427 if( current_date >= date_late ) then
428
429 kcb = kcb_min
430
431 elseif ( current_date >= date_mid ) then
432
433 ffrac = ( current_date - date_mid ) / ( date_late - date_mid )
434
435 kcb = real(kcb_mid * (1.0_c_double - ffrac) + kcb_end * ffrac, c_float)
436
437 elseif ( current_date >= date_dev ) then
438
439 kcb = kcb_mid
440
441 elseif ( current_date >= date_ini ) then
442
443 ffrac = ( current_date - date_ini ) / ( date_dev - date_ini )
444
445 kcb = real(kcb_ini * (1.0_c_double - ffrac) + kcb_mid * ffrac, c_float)
446
447 elseif ( current_date >= plantingdate ) then
448
449 kcb = kcb_ini
450
451 else
452
453 kcb = kcb_min
454
455 endif
456
457 end associate
458
459 end if
460
462
463!------------------------------------------------------------------------------
464
465pure elemental function crop_coefficients_fao56_calculate_kcb_max(wind_speed_meters_per_sec, &
466 relative_humidity_min_pct, &
467 Kcb, &
468 plant_height_meters) result(kcb_max)
469
470 real (c_float), intent(in) :: wind_speed_meters_per_sec
471 real (c_float), intent(in) :: relative_humidity_min_pct
472 real (c_float), intent(in) :: kcb
473 real (c_float), intent(in) :: plant_height_meters
474
475 real (c_float) :: kcb_max
476 real (c_double) :: u2
477 real (c_double) :: rhmin
478 real (c_double) :: plant_height
479
480 ! Limits are as suggested on page 123 of FAO-56 with respect to
481 ! modifying mid-season KCB_mid values
482 rhmin = clip( relative_humidity_min_pct, minval=20., maxval=80. )
483 u2 = clip(wind_speed_meters_per_sec, minval=1., maxval=6.)
484 plant_height = clip(plant_height_meters, minval=1., maxval=10.)
485
486 ! equation 72, FAO-56, p 199
487 kcb_max = real(max( 1.2_c_double + ( (0.04_c_double * (u2 - 2._c_double) &
488 - 0.004_c_double * (rhmin - 45._c_double) ) ) &
489 * (plant_height_meters/3._c_double)**0.3_c_double, &
490 kcb + 0.05_c_double ), c_float)
491
493
494!------------------------------------------------------------------------------
495
496 !> Update the current basal crop coefficient (Kcb), with GDD as the threhold
497 !!
498 !! @param[in] fGDD current growing degree day value associated with the cell.
499 !! @retval fKcb Basal crop coefficient given the irrigation table entries and the
500 !! current threshold values.
501
502 impure elemental function update_crop_coefficient_gdd_as_threshold( iLanduseIndex, fGDD ) &
503 result(fkcb)
504
505 integer (c_int), intent(in) :: ilanduseindex
506 real (c_float), intent(in) :: fgdd
507 real (c_float) :: fkcb
508
509 ! [ LOCALS ]
510 real (c_double) :: ffrac
511
512 ! define shorthand variable names for remainder of function
513 associate( gdd_ini_l => growth_stage_gdd( gdd_ini, ilanduseindex ), &
514 gdd_dev_l => growth_stage_gdd( gdd_dev, ilanduseindex ), &
515 gdd_mid_l => growth_stage_gdd( gdd_mid, ilanduseindex ), &
516 gdd_late_l => growth_stage_gdd( gdd_late, ilanduseindex ), &
517 kcb_ini => kcb_l(kcb_ini, ilanduseindex), &
518 kcb_mid => kcb_l(kcb_mid, ilanduseindex), &
519 kcb_min => kcb_l(kcb_min, ilanduseindex), &
520 plantingdoy => growth_stage_date( planting_date, &
521 ilanduseindex)%getDayOfYear(), &
522 gdd_plant_l => growth_stage_gdd( gdd_plant, ilanduseindex), &
523 kcb_end => kcb_l(kcb_end, ilanduseindex), &
524 current_doy => sim_dt%curr%getDayOfYear() )
525
526 ! now calculate Kcb for the given landuse
527 if( fgdd > gdd_late_l ) then
528
529 fkcb = kcb_min
530
531 elseif ( fgdd > gdd_mid_l ) then
532
533 ffrac = ( fgdd - gdd_mid_l ) / ( gdd_late_l - gdd_mid_l )
534
535 fkcb = real(kcb_mid * (1.0_c_double - ffrac) + kcb_end * ffrac, c_float)
536
537 elseif ( fgdd > gdd_dev_l ) then
538
539 fkcb = kcb_mid
540
541 elseif ( fgdd > gdd_ini_l ) then
542
543 ffrac = ( fgdd - gdd_ini_l ) / ( gdd_dev_l - gdd_ini_l )
544
545 fkcb = real(kcb_ini * (1_c_double - ffrac) + kcb_mid * ffrac, c_float)
546
547 elseif ( (plantingdoy > 0) .and. (current_doy >= plantingdoy) ) then
548
549 ! if there is a valid value for the Planting Date, use it
550 fkcb = kcb_ini
551
552 elseif ( (gdd_plant_l >= 0.) .and. (fgdd >= gdd_plant_l) ) then
553
554 fkcb = kcb_ini
555
556 else
557
558 fkcb = kcb_min
559
560 endif
561
562 end associate
563
565
566!------------------------------------------------------------------------------
567
569
570 ! [ LOCALS ]
571 integer (c_int) :: iindex
572
573 do iindex=lbound(growth_stage_date,2), ubound(growth_stage_date,2)
574
575 ! print *, SIM_DT%curr%prettydate(), " | ", GROWTH_STAGE_DATE( ENDDATE_LATE, iIndex )%prettydate()
576
577 ! if we have not yet reached the enddate associated with the fallow period, skip
578 if ( sim_dt%curr < growth_stage_date( enddate_fallow, iindex ) ) cycle
579
580 if ( kcb_method( iindex ) /= kcb_method_fao56 ) cycle
581
582 ! current date is beyond the enddate associated with fallow period;
583 ! update Kcb curve and dates
584
585! print *, "a) ",SIM_DT%curr%prettydate(), " | ", GROWTH_STAGE_DATE( ENDDATE_LATE, iIndex )%prettydate()
586
587 ! it's possible that the planting date might be later in the current calendar year
588 !call GROWTH_STAGE_DATE( PLANTING_DATE, iIndex )%setYear( SIM_DT%curr%iYear )
589
590! print *, "b) ",SIM_DT%curr%prettydate(), " | ", GROWTH_STAGE_DATE( PLANTING_DATE, iIndex )%prettydate()
591
592 ! if we are already past the planting doy, planting date must be
593 ! next calendar year
594 if ( sim_dt%iDOY > growth_stage_date( planting_date, iindex )%getDayOfYear() ) then
595
596 growth_stage_date( planting_date, iindex ) = &
598 iyear=sim_dt%curr%iYear + 1)
599
600 else
601
602 ! allow for planting date to be later in the current year
603 growth_stage_date( planting_date, iindex ) = &
605 iyear=sim_dt%curr%iYear )
606
607 endif
608
609 ! now calculate dates associated with the rest of the Kcb curve
620
621 call logs%write("## Updated Crop Kcb Curve Summary ##", ilinesafter=1, lecho=false )
622 call logs%write("Landuse Code | Planting Date | End of 'ini' | End of 'dev' " &
623 //"| End of 'mid' | End of 'late' | End of 'fallow' ", lecho=false )
624 call logs%write("-------------|---------------|--------------|--------------" &
625 //"|--------------|---------------|-----------------", lecho=false )
626
627 ! call LOGS%write( asCharacter( LANDUSE_CODE( iIndex ))//" | " &
628 ! //trim( GROWTH_STAGE_DATE( PLANTING_DATE, iIndex )%prettydate() )//" | " &
629 ! //trim( GROWTH_STAGE_DATE( ENDDATE_INI, iIndex )%prettydate() )//" | " &
630 ! //trim( GROWTH_STAGE_DATE( ENDDATE_DEV, iIndex )%prettydate() )//" | " &
631 ! //trim( GROWTH_STAGE_DATE( ENDDATE_MID, iIndex )%prettydate() )//" | " &
632 ! //trim( GROWTH_STAGE_DATE( ENDDATE_LATE, iIndex )%prettydate() )//" | " &
633 ! //trim( GROWTH_STAGE_DATE( ENDDATE_FALLOW, iIndex )%prettydate() ), &
634 ! lEcho=FALSE, iLogLevel=LOG_ALL )
635
636
637 call logs%write( "| "//ascharacter( landuse_code( iindex ))//" | " &
638 //trim( growth_stage_date( planting_date, iindex )%prettydate() ) &
639 //" (doy:"//ascharacter( growth_stage_date( planting_date, iindex )%getDayOfYear() )//") | " &
640 //trim( growth_stage_date( enddate_ini, iindex )%prettydate() )//" | " &
641 //" (doy:"//ascharacter( growth_stage_date( enddate_ini, iindex )%getDayOfYear() )//") | " &
642 //trim( growth_stage_date( enddate_dev, iindex )%prettydate() )//" | " &
643 //" (doy:"//ascharacter( growth_stage_date( enddate_dev, iindex )%getDayOfYear() )//") | " &
644 //trim( growth_stage_date( enddate_mid, iindex )%prettydate() )//" | " &
645 //" (doy:"//ascharacter( growth_stage_date( enddate_mid, iindex )%getDayOfYear() )//") | " &
646 //trim( growth_stage_date( enddate_late, iindex )%prettydate() )//" | " &
647 //" (doy:"//ascharacter( growth_stage_date( enddate_late, iindex )%getDayOfYear() )//") | " &
648 //trim( growth_stage_date( enddate_fallow, iindex )%prettydate() ) &
649 //" (doy:"//ascharacter( growth_stage_date( enddate_fallow, iindex )%getDayOfYear() )//") | ", &
650 lecho=false, iloglevel=log_all)
651
652 enddo
653
654
656
657!--------------------------------------------------------------------------------------------------
658
659 impure elemental subroutine crop_coefficients_fao56_calculate( Kcb, landuse_index, GDD )
660
661 real (c_float), intent(inout) :: kcb
662 integer (c_int), intent(in) :: landuse_index
663 real (c_float), intent(in), optional :: gdd
664
665
666 if ( kcb_method( landuse_index ) == kcb_method_fao56 &
667 .or. kcb_method( landuse_index ) == kcb_method_monthly_values ) then
668
669 kcb = update_crop_coefficient_date_as_threshold( landuse_index )
670
671 else
672
673 kcb = update_crop_coefficient_gdd_as_threshold( landuse_index, gdd )
674
675 endif
676
678
679!--------------------------------------------------------------------------------------------------
680
682 landuse_index, &
683 Kcb, &
684 it_is_growing_season)
685
686 real (c_float), intent(in) :: kcb
687 integer (c_int), intent(in) :: landuse_index
688 logical (c_bool), intent(out) :: it_is_growing_season
689
690 if ( kcb > kcb_l( kcb_min, landuse_index) ) then
691 it_is_growing_season = true
692 else
693 it_is_growing_season = false
694 endif
695
697
This module contains physical constants and convenience functions aimed at performing unit conversion...
logical(c_bool), parameter, public true
real(c_float), parameter, public near_zero
logical(c_bool), parameter, public false
real(c_double), parameter, public m_per_foot
integer(c_int), parameter, public itinyval
Update crop coefficients for crop types in simulation.
subroutine, public crop_coefficients_fao56_initialize()
impure elemental real(c_float) function, public update_crop_coefficient_gdd_as_threshold(ilanduseindex, fgdd)
Update the current basal crop coefficient (Kcb), with GDD as the threhold.
pure elemental real(c_float) function, public crop_coefficients_fao56_calculate_kcb_max(wind_speed_meters_per_sec, relative_humidity_min_pct, kcb, plant_height_meters)
real(c_float), dimension(:,:), allocatable, public growth_stage_length_in_days
impure elemental subroutine, public crop_coefficients_fao56_update_growing_season(landuse_index, kcb, it_is_growing_season)
real(c_float), dimension(:,:), allocatable, public kcb_l
subroutine, public crop_coefficients_fao56_update_growth_stage_dates()
impure elemental real(c_float) function, public update_crop_coefficient_date_as_threshold(ilanduseindex)
Update the current basal crop coefficient (Kcb) for a SINGLE irrigation table entry.
real(c_float), dimension(:,:), allocatable growth_stage_gdd
integer(c_int), dimension(:), allocatable, public kcb_method
impure elemental subroutine, public crop_coefficients_fao56_calculate(kcb, landuse_index, gdd)
integer(c_int), dimension(:), allocatable landuse_code
type(datetime_t), dimension(:,:), allocatable, public growth_stage_date
type(datetime_t) function crop_coefficients_calculate_planting_date(splantingdate, iyear)
Defines the DATA_CATALOG_T data type, which contains type-bound procedures to add,...
type(data_catalog_t), public dat
DAT is a global to hold data catalog entries.
This module contains the DATETIME_T class and associated time and date-related routines,...
Definition datetime.F90:9
subroutine, public warn(smessage, smodule, iline, shints, lfatal, iloglevel, lecho)
subroutine, public die(smessage, smodule, iline, shints, scalledby, icalledbyline)
type(logfile_t), public logs
Definition logfiles.F90:62
type(parameters_t), public params
type(date_range_t), public sim_dt