Soil Water Balance (SWB2)
Loading...
Searching...
No Matches
precipitation__method_of_fragments.F90
Go to the documentation of this file.
1!> @file
2!! Contains the module @ref precipitation__method_of_fragments.
3
4!>
5!! Module @ref precipitation__method_of_fragments
6!! provides support for creating synthetic daily precipitation
7!! given grids of monthly sum precipitation and a "fragments" file.
8!! The fragments file is generated from observations at discrete locations,
9!! the values of which range from 0 to 1, and the sum of which is 1.
10!! The fragment value is simply the daily observed precipitation value divided
11!! by the monthly sum of all observed precipitation values for that station.
12!!
13!! In addition, this routine accepts another set of rainfall adjustment grids,
14!! needed in order to ensure the resulting precipitation totals fall in line with
15!! other published values, in the development case, the Rainfall Atlas of Hawaii.
16
18
19 use iso_c_binding
21 use data_catalog
23 use dictionary
24 use exceptions
27 use logfiles, only : logs, log_all, log_debug
28 use parameters
29 use fstring
30 use fstring_list
32 use grid
33 implicit none
34
35 private
36
38 public :: read_daily_fragments
40
41 !> Module variable that holds the rainfall gage (zone) number
42 integer (c_int), allocatable, public :: rain_gage_id(:)
43
44 !> Module variable that holds the current day's rainfall fragment value
45 real (c_float), allocatable, public :: fragment_value(:)
46
47 !> Module variable indicating which "simulation number" is active
48 !! Only has meaning if the rainfall fragments are being applied via a predetermined
49 !! sequence file
50 integer (c_int), public :: simulation_number = 1
51
52 !> Module variable that holds the rainfall adjustment factor
53 real (c_float), allocatable, public :: rainfall_adjust_factor(:)
54
55 !> Module variable that holds a sequence of random numbers associated with the selection
56 !! of the fragment set to use
57 real (c_double), allocatable :: random_values(:,:)
58
59 !> Module level variable used to create subsets of the FRAGMENT_SEQUENCES file
60 logical (c_bool), allocatable :: sequence_selection(:)
61
62 !> Module variable detemining whether fragment sequences are chosen at random or
63 !! selected from an external file
64 logical (c_bool) :: random_fragment_sequences = .true._c_bool
65
66 !> Data structure that holds a single line of data from the input rainfall fragments file.
67 type, public :: fragments_t
68 integer (c_int) :: imonth
69 integer (c_int) :: iraingagezone
70 integer (c_int) :: ifragmentset
71 real (c_float) :: ffragmentvalue(31)
72 end type fragments_t
73
74 !> Pointer to a rainfall fragments data structure.
75 type, public :: ptr_fragments_t
76 type (fragments_t), pointer :: pfragment => null()
77 end type ptr_fragments_t
78
79 !> Data structure to hold the current active rainfall fragments for
80 !! a particular rain gage zone.
81 type, public :: fragments_set_t
82 integer (c_int) :: iraingagezone
83 integer (c_int) :: inumberoffragments(12)
84 integer (c_int) :: istartrecord(12)
85 end type fragments_set_t
86
87 !> Array of all fragments read in from the rainfall fragments file.
88 type (fragments_t), allocatable, target, public :: fragments(:)
89
90 !> Subset of rainfall fragments file pointing to the currently active fragments.
91 type (ptr_fragments_t), allocatable :: current_fragments(:,:)
92
93 !> Array of fragments sets; fragments sets include indices to the start record
94 !! associated with the fragment for each month; FRAGMENTS_SETS will have a
95 !! number of elements equal to the number of rainfall gages in the model domain
96 type (fragments_set_t), allocatable, public :: fragments_sets(:)
97
98 !> Data structure to hold static (pre-calculated) fragment selection numbers
99 type, public :: fragments_sequence_t
100 integer (c_int) :: sim_number
101 integer (c_int) :: sim_month
102 integer (c_int) :: sim_rainfall_zone
103 integer (c_int) :: sim_year
104 real (c_float) :: sim_random_number
105 integer (c_int) :: sim_selected_set
106 end type fragments_sequence_t
107
108 !> Array of fragment sequence sets
109 type (fragments_sequence_t), allocatable, public :: fragments_sequence(:)
110
111 integer (c_int) :: lu_fragments_echo
112
113contains
114
115 !> Initialize method of fragments.
116 !!
117 !! This routine accesses the "RAINFALL_ZONE" gridded data object and
118 !! calls the routine to read in the rainfall fragments file. Values of RAINFALL_ZONE are stored
119 !! in a module variable @ref RAIN_GAGE_ID for future reference.
120 !!
121 !! @params[in] lActive 2-D boolean array defining active and inactive cells
122
124
125 logical (c_bool), intent(in) :: lactive(:,:)
126
127 ! [ LOCALS ]
128 integer (c_int) :: istat
129 type (data_catalog_entry_t), pointer :: prainfall_zone
130 type (fstring_list_t) :: slstring
131 integer (c_int) :: imaxrainzones
132 integer (c_int), allocatable :: isimulationnumbers(:)
133 character (len=256) :: error_str
134
135 ! look up the simulation number associated with the desired fragment sequence set
136 call cf_dict%get_values( skey="FRAGMENTS_SEQUENCE_SIMULATION_NUMBER", ivalues=isimulationnumbers )
137 if ( isimulationnumbers(1) > 0 ) simulation_number = isimulationnumbers(1)
138
139 ! locate the data structure associated with the gridded rainfall zone entries
140 prainfall_zone => dat%find("RAINFALL_ZONE")
141 if ( .not. associated(prainfall_zone) ) &
142 call die("A RAINFALL_ZONE grid must be supplied in order to make use of this option.", &
143 __file__, __line__)
144
145 allocate( rain_gage_id( count(lactive) ), stat=istat )
146 call assert( istat == 0, "Problem allocating memory", __file__, __line__ )
147
148 call prainfall_zone%getvalues()
149
150 ! map the 2D array of RAINFALL_ZONE values to the vector of active cells
151 rain_gage_id = pack( prainfall_zone%pGrdBase%iData, lactive )
152
153 allocate( rainfall_adjust_factor( count(lactive) ), stat=istat )
154 call assert( istat == 0, "Problem allocating memory", __file__, __line__ )
155
156 allocate( fragment_value( count(lactive) ), stat=istat )
157 call assert( istat == 0, "Problem allocating memory", __file__, __line__ )
158
159
160 ! look up the name of the fragments file in the control file dictionary
161 call cf_dict%get_values( skey="FRAGMENTS_DAILY_FILE", slstring=slstring )
162
163 ! use the first entry in the string list slString as the filename to open for
164 ! use with the daily fragments routine
165
166
167 call read_daily_fragments( slstring%get(1) )
168 call slstring%clear()
169
170 ! look up the name of the fragments SEQUENCE file in the control file dictionary
171 call cf_dict%get_values( skey="FRAGMENTS_SEQUENCE_FILE", slstring=slstring )
172
173 if ( .not. ( slstring%get(1) .strequal. "<NA>" ) ) then
174 call read_fragments_sequence( slstring%get(1) )
176 allocate ( sequence_selection( count(fragments_sequence%sim_month > 0) ), stat=istat )
177 call assert( istat == 0, "Problem allocating memory", __file__, __line__ )
178 endif
179
180 !> Now the fragments file is in memory. Create an ancillary data structure
181 !> to keep track of which records correspond to various rain zones
182
183 imaxrainzones = maxval(fragments%iRainGageZone)
184
185 allocate ( fragments_sets( imaxrainzones ), stat=istat )
186 call assert( istat == 0, "Problem allocating memory", __file__, __line__ )
187
188 if ( .not. allocated(current_fragments) ) then
189 allocate (current_fragments( imaxrainzones, 1 ), stat=istat, errmsg=error_str )
190 call assert( istat == 0, "Problem allocating memory, stat="//ascharacter(istat) &
191 //"; msg: "//trim(error_str), __file__, __line__ )
192 endif
193
194 if ( .not. allocated( random_values) ) then
195 allocate (random_values( imaxrainzones, 1 ), stat=istat )
196 call assert( istat == 0, "Problem allocating memory, stat="//ascharacter(istat) &
197 //"; msg: "//trim(error_str), __file__, __line__ )
198 endif
199
201
203
204 open( newunit=lu_fragments_echo, file="Fragments_as_implemented_by_SWB.csv")
205 write( lu_fragments_echo, fmt="(a, 30('fragment, '),'fragment')") &
206 "Simulation_Number, Month, Rain_Zone, Year, Random_Number, Fragment_Set,"
207
209
210 !--------------------------------------------------------------------------------------------------
211
212 subroutine read_daily_fragments( sFilename )
213
214 character (len=*), intent(in) :: sfilename
215
216 ! [ LOCALS ]
217 character (len=512) :: srecord, ssubstring
218 integer (c_int) :: istat
219 integer (c_int) :: icount
220 integer (c_int) :: iindex
221 integer (c_int) :: last_zone
222 integer (c_int) :: last_fragment
223 integer (c_int) :: last_month
224 integer (c_int) :: inumlines
225 real (c_float) :: ftempvalue
226 type (ascii_file_t), allocatable :: fragments_file
227
228 allocate(fragments_file)
229
230 call fragments_file%open( sfilename = sfilename, &
231 scommentchars = "#%!", &
232 sdelimiters = "WHITESPACE", &
233 lhasheader = .false._c_bool )
234
235 inumlines = fragments_file%numLines()
236
237 allocate( fragments( inumlines ), stat=istat )
238 call assert( istat == 0, "Problem allocating memory for fragments table", __file__, __line__ )
239
240 icount = 0
241 last_zone = 1
242 last_fragment = 0
243 last_month = 1
244
245 do
246
247 ! read in next line of file
248 srecord = fragments_file%readLine()
249
250 if ( fragments_file%isEOF() ) exit
251
252 icount = icount + 1
253
254 ! read in month number
255 call chomp(srecord, ssubstring, fragments_file%sDelimiters )
256
257 if ( len_trim(ssubstring) == 0 ) &
258 call die( "Missing month number in the daily fragments file", &
259 __file__, __line__, "Problem occured on line number " &
260 //ascharacter(fragments_file%currentLineNum() ) &
261 //" of file "//dquote(sfilename) )
262
263 fragments(icount)%iMonth = asint(ssubstring)
264
265 ! reset the counter tracking the previous fragment ID
266 if ( fragments(icount)%iMonth == (last_month + 1) ) then
267 last_fragment = 0
268 last_zone = 0
269 endif
270
271 if ( fragments(icount)%iMonth < last_month ) &
272 call die( "Out-of-order month value in the daily fragments file", &
273 __file__, __line__, "Problem occured on line number " &
274 //ascharacter(fragments_file%currentLineNum() ) &
275 //" of file "//dquote(sfilename) )
276
277 last_month = fragments(icount)%iMonth
278
279 ! read in rain gage zone
280 call chomp(srecord, ssubstring, fragments_file%sDelimiters )
281
282 if ( len_trim(ssubstring) == 0 ) &
283 call die( "Missing rain gage zone number in the daily fragments file", &
284 __file__, __line__, "Problem occured on line number " &
285 //ascharacter(fragments_file%currentLineNum() ) &
286 //" of file "//dquote(sfilename) )
287
288 fragments(icount)%iRainGageZone = asint(ssubstring)
289
290 if ( fragments(icount)%iRainGageZone < last_zone ) &
291 call die( "Rain gage zone number out of order in the daily fragments file", &
292 __file__, __line__, "Problem occured on line number " &
293 //ascharacter(fragments_file%currentLineNum() ) &
294 //" of file "//dquote(sfilename) )
295
296 ! reset the counter tracking the previous fragment ID
297 if ( fragments(icount)%iRainGageZone == (last_zone + 1) ) &
298 last_fragment = 0
299
300 last_zone = fragments(icount)%iRainGageZone
301
302 ! read in fragment set number for this zone
303 call chomp(srecord, ssubstring, fragments_file%sDelimiters )
304
305 if ( len_trim(ssubstring) == 0 ) &
306 call die( "Missing fragment set number in the daily fragments file", &
307 __file__, __line__, "Problem occured on line number " &
308 //ascharacter(fragments_file%currentLineNum() ) &
309 //" of file "//dquote(sfilename) )
310
311 fragments(icount)%iFragmentSet = asint(ssubstring)
312
313 if ( fragments(icount)%iFragmentSet /= (last_fragment + 1) ) &
314 call die( "Missing or out-of-order fragment value in the daily fragments file", &
315 __file__, __line__, "Problem occured on line number " &
316 //ascharacter(fragments_file%currentLineNum() ) &
317 //" of file "//dquote(sfilename) )
318
319 last_fragment = fragments(icount)%iFragmentSet
320
321 ! read in fragments for each day of the current month
322 do iindex = 1, 31
323
324 ! read in fragment for given day of month
325 call chomp(srecord, ssubstring, fragments_file%sDelimiters )
326
327 if ( len_trim(ssubstring) == 0 ) &
328 call die( "Missing fragment value in the daily fragments file", &
329 __file__, __line__, "Problem occured on line number " &
330 //ascharacter(fragments_file%currentLineNum() ) &
331 //" of file "//dquote(sfilename) )
332
333 ftempvalue = asfloat( ssubstring )
334
335 ! This substitution is needed to prevent "-9999" or "9999" values embedded in the fragments file
336 ! from creeping into calculations. In the event of a "9999", the appropriate substitution is
337 ! zero, since the previous fragments for the month to this point should already sum to 1.0
338 if ( ( ftempvalue < 0.0_c_float ) .or. ( ftempvalue > 1.0_c_float ) ) then
339 fragments(icount)%fFragmentValue(iindex) = 0.0_c_float
340 else
341 fragments(icount)%fFragmentValue(iindex) = ftempvalue
342 endif
343
344 enddo
345
346 if ( fragments(icount)%iMonth == 2 ) call normalize_february_fragment_sequence( icount )
347
348 enddo
349
350 call logs%write("Maximum rain gage zone number: "//ascharacter(maxval(fragments%iRainGageZone)), &
351 itab=31, ilinesafter=1, iloglevel=log_all)
352
353 end subroutine read_daily_fragments
354
355!--------------------------------------------------------------------------------------------------
356
357 !> after fragments file has been read in, iterate over a set of rainfall fragments
358 ! and keep track of the index values that correspond with changes
359 ! in month and rain gage numbers
361
362 integer (c_int) :: iCount
363 integer (c_int) :: iIndex
364 integer (c_int) :: iRainGageZone
365 integer (c_int) :: iPreviousRainGageZone
366 integer (c_int) :: iMonth
367 integer (c_int) :: iPreviousMonth
368 character (len=10) :: sBuf0
369 character (len=10) :: sBuf1
370 character (len=12) :: sBuf2
371 character (len=10) :: sBuf3
372 character (len=52) :: sBuf4
373
374 ! this counter is used to accumulate the number of fragments associated with the
375 ! current raingage zone/month combination
376 icount = 1
377
378 iraingagezone = fragments( lbound( fragments, 1) )%iRainGageZone
379 ipreviousraingagezone = iraingagezone
380 ipreviousmonth = fragments( lbound( fragments, 1) )%iMonth
381
382 ! at this point, iRainGageZone should be 1, and iPreviousMonth should be 1,
383 ! assuming that the fragments were sorted properly upon input
384
385 ! populate the first record of FRAGMENT_SETS
386 fragments_sets( iraingagezone )%iRainGageZone = iraingagezone
387 fragments_sets( iraingagezone )%iStartRecord(ipreviousmonth) = lbound( fragments, 1)
388
389 ! now iterate through *all* fragments, keeping track of the starting record for each new rainfall gage
390 ! zone number
391 do iindex = lbound( fragments, 1) + 1, ubound( fragments, 1 )
392
393 iraingagezone = fragments(iindex)%iRainGageZone
394 imonth = fragments(iindex)%iMonth
395
396 if ( iraingagezone /= ipreviousraingagezone ) then
397 ! the previous record was the last one associated with the previous
398 ! rainfall gage zone; do not count the current record as part of the
399 ! collection of records associated with previous zone
400
401 fragments_sets( ipreviousraingagezone )%iNumberOfFragments(ipreviousmonth) = icount
402
403
404 fragments_sets( iraingagezone )%iRainGageZone = iraingagezone
405 fragments_sets( iraingagezone )%iStartRecord(imonth) = iindex
406 ! ! need to handle the last fragment set as a special case
407 ! FRAGMENTS_SETS( iRainGageZone )%iNumberOfFragments(iMonth) = iCount
408 icount = 1
409
410 else
411 icount = icount + 1
412 endif
413
414 ipreviousmonth = imonth
415 ipreviousraingagezone = iraingagezone
416
417 enddo
418
419 ! need to handle the last month of the last fragment set as a special case
420 fragments_sets( iraingagezone )%iNumberOfFragments(imonth) = icount
421
422 call logs%write("### Summary of fragment sets in memory ###", &
423 iloglevel=log_all, ilinesbefore=1, ilinesafter=1, lecho=false )
424 call logs%write("gage number | month | start index | num records ")
425 call logs%write("----------- | ---------- | ------------ | ------------")
426 do iindex=1, ubound( fragments_sets, 1)
427 do imonth=1,12
428 write (sbuf0, fmt="(i10)") iindex
429 write (sbuf1, fmt="(i10)") imonth
430 write (sbuf2, fmt="(i12)") fragments_sets(iindex)%iStartRecord(imonth)
431 write (sbuf3, fmt="(i10)") fragments_sets(iindex)%iNumberOfFragments(imonth)
432 write (sbuf4, fmt="(a10,' | ', a10,' | ', a12,' | ',a10)") adjustl(sbuf0), &
433 adjustl(sbuf1), adjustl(sbuf2), adjustl(sbuf3)
434 call logs%write( sbuf4 )
435 enddo
436 end do
437
438 end subroutine process_fragment_sets
439
440!--------------------------------------------------------------------------------------------------
441
442 !> eliminate rainfall on the 29th day of February; bump up all other values to ensure sum = 1
444
445 integer (c_int), intent(in) :: iCount
446
447 ! [ LOCALS ]
448 real (c_float) :: sum_fragments
449
450 ! we only want to correct the fragment if it was actually generated during a
451 ! leap year
452 if (fragments(icount)%fFragmentValue(29) > 0.0_c_float) then
453 sum_fragments = sum( fragments(icount)%fFragmentValue(1:28) )
454
455 ! bump up all February fragments so that their 28-day sum is 1
456 fragments(icount)%fFragmentValue(1:28) = fragments(icount)%fFragmentValue(1:28) &
457 / sum_fragments
458 ! zero out remaining values
459 fragments(icount)%fFragmentValue(29:31) = 0.0_c_float
460 endif
461
463
464!--------------------------------------------------------------------------------------------------
465
466 ! in order to compare Hawaii Water Budget results to SWB results,
467 ! it is necessary to force SWB to use the same sequence of fragments
468 ! that was used in the HWB simulations
469 subroutine read_fragments_sequence( sFilename )
470
471 character (len=*), intent(in) :: sFilename
472
473 ! [ LOCALS ]
474 character (len=512) :: sRecord, sSubstring
475 integer (c_int) :: iStat
476 integer (c_int) :: iCount
477 integer (c_int) :: iIndex
478 integer (c_int) :: iNumLines
479 type (ASCII_FILE_T), allocatable :: SEQUENCE_FILE
480 character (len=10) :: sBuf0
481 character (len=10) :: sBuf1
482 character (len=12) :: sBuf2
483 character (len=10) :: sBuf3
484 character (len=10) :: sBuf4
485 character (len=256) :: sBuf5
486 character (len=256) :: error_str
487 type (FSTRING_LIST_T) :: slHeader
488 integer (c_int) :: max_rain_gage_number
489 integer (c_int) :: max_simulation_number
490
491 allocate(sequence_file)
492
493 call sequence_file%open( sfilename = sfilename, &
494 scommentchars = "#%!", &
495 sdelimiters = "WHITESPACE", &
496 lhasheader = .true._c_bool )
497
498 slheader = sequence_file%readHeader()
499
500 inumlines = sequence_file%numLines()
501
502 allocate( fragments_sequence( inumlines ), stat=istat )
503 call assert( istat == 0, "Problem allocating memory for fragments sequence table", &
504 __file__, __line__ )
505
506 icount = 0
507
508 do
509
510 ! read in next line of file
511 srecord = sequence_file%readLine()
512
513 if ( sequence_file%isEOF() ) exit
514
515 icount = icount + 1
516
517 ! read in simulation number
518 call chomp(srecord, ssubstring, sequence_file%sDelimiters )
519
520 if ( len_trim(ssubstring) == 0 ) &
521 call die( "Missing simulation number in the fragments sequence file", &
522 __file__, __line__, "Problem occured on line number " &
523 //ascharacter(sequence_file%currentLineNum() ) &
524 //" of file "//dquote(sfilename) )
525
526 fragments_sequence(icount)%sim_number = asint(ssubstring)
527
528 ! read in month
529 call chomp(srecord, ssubstring, sequence_file%sDelimiters )
530
531 if ( len_trim(ssubstring) == 0 ) &
532 call die( "Missing month number in the fragments sequence file", &
533 __file__, __line__, "Problem occured on line number " &
534 //ascharacter(sequence_file%currentLineNum() ) &
535 //" of file "//dquote(sfilename) )
536
537 fragments_sequence(icount)%sim_month = asint(ssubstring)
538
539 ! read in rainfall zone
540 call chomp(srecord, ssubstring, sequence_file%sDelimiters )
541
542 if ( len_trim(ssubstring) == 0 ) &
543 call die( "Missing rainfall zone number in the fragments sequence file", &
544 __file__, __line__, "Problem occured on line number " &
545 //ascharacter(sequence_file%currentLineNum() ) &
546 //" of file "//dquote(sfilename) )
547
548 fragments_sequence(icount)%sim_rainfall_zone = asint(ssubstring)
549
550
551 ! read in sim_year
552 call chomp(srecord, ssubstring, sequence_file%sDelimiters )
553
554 if ( len_trim(ssubstring) == 0 ) &
555 call die( "Missing year number in the fragments sequence file", &
556 __file__, __line__, "Problem occured on line number " &
557 //ascharacter(sequence_file%currentLineNum() ) &
558 //" of file "//dquote(sfilename) )
559
560 fragments_sequence(icount)%sim_year = asint(ssubstring)
561
562 ! read in sim_random_number
563 call chomp(srecord, ssubstring, sequence_file%sDelimiters )
564
565 if ( len_trim(ssubstring) == 0 ) &
566 call die( "Missing simulation random number in the fragments sequence file", &
567 __file__, __line__, "Problem occured on line number " &
568 //ascharacter(sequence_file%currentLineNum() ) &
569 //" of file "//dquote(sfilename) )
570
571 fragments_sequence(icount)%sim_random_number = asfloat(ssubstring)
572
573 ! read in simulation selected set (fragment set selected by HWB)
574 call chomp(srecord, ssubstring, sequence_file%sDelimiters )
575
576 if ( len_trim(ssubstring) == 0 ) &
577 call die( "Missing selected fragment set number in the fragments sequence file", &
578 __file__, __line__, "Problem occured on line number " &
579 //ascharacter(sequence_file%currentLineNum() ) &
580 //" of file "//dquote(sfilename) )
581
582 fragments_sequence(icount)%sim_selected_set = asint(ssubstring)
583
584 enddo
585
586 max_rain_gage_number = maxval(fragments_sequence(:)%sim_rainfall_zone,1)
587 max_simulation_number = maxval(fragments_sequence(:)%sim_number,1)
588
589 ! idea here is that if we are reading in a sequence file, there is a good chance
590 ! that the users is running multiple simulations; this will allow for a
591 ! separate pointer to be established for each rain gage/simulation number combination
592 ! as well as a means to keep the random value sequences separate by simulation
593
594 if ( allocated(current_fragments)) deallocate(current_fragments, stat=istat, &
595 errmsg=error_str)
596 call assert( istat == 0, "Problem deallocating memory, stat="//ascharacter(istat) &
597 //"; msg: "//trim(error_str), __file__, __line__ )
598
599 allocate(current_fragments(max_rain_gage_number, max_simulation_number), stat=istat, &
600 errmsg=error_str)
601 call assert( istat == 0, "Problem allocating memory, stat="//ascharacter(istat) &
602 //"; msg: "//trim(error_str), __file__, __line__ )
603
604
605 if ( allocated(random_values)) deallocate(random_values, stat=istat, errmsg=error_str)
606 call assert( istat == 0, "Problem deallocating memory, stat="//ascharacter(istat) &
607 //"; msg: "//trim(error_str), __file__, __line__ )
608
609 allocate(random_values(max_rain_gage_number, max_simulation_number), stat=istat, &
610 errmsg=error_str )
611 call assert( istat == 0, "Problem allocating memory, stat="//ascharacter(istat) &
612 //"; msg: "//trim(error_str), __file__, __line__ )
613
614 call logs%write("### Summary of fragment sequence sets in memory ###", &
615 iloglevel=log_debug, ilinesbefore=1, ilinesafter=1, lecho=false )
616 call logs%write("sim number | rainfall zone | month | year | selected set ")
617 call logs%write("----------- | ---------- | ------------ | ------------|------------")
618 do iindex=1, ubound( fragments_sequence, 1)
619 write (sbuf0, fmt="(i10)") fragments_sequence( iindex )%sim_number
620 write (sbuf1, fmt="(i10)") fragments_sequence( iindex )%sim_rainfall_zone
621 write (sbuf2, fmt="(i12)") fragments_sequence( iindex )%sim_month
622 write (sbuf3, fmt="(i10)") fragments_sequence( iindex )%sim_year
623 write (sbuf4, fmt="(i10)") fragments_sequence( iindex )%sim_selected_set
624
625 write (sbuf5, fmt="(a,' | ', a,' | ', a,' | ',a,' | ',a)") &
626 adjustl(sbuf0), adjustl(sbuf1), adjustl(sbuf2), adjustl(sbuf3), adjustl(sbuf4)
627 call logs%write( trim( sbuf5 ) )
628 end do
629
630 end subroutine read_fragments_sequence
631
632!--------------------------------------------------------------------------------------------------
633
634 !> Update rainfall fragments on daily basis.
635 !!
636 !! If called when lShuffle is TRUE:
637 !! 1) update random values
638 !! 2) random values are used to select the next active fragment set
639 !! for the current RainGageZone
640 !!
641 !! *Each* time the routine is called, the appropriate fragment is
642 !! selected from the current active fragment set and is assigned
643 !! to all cells that share a common RainGageZone
644
645 subroutine update_fragments( lShuffle )
646
647 logical (c_bool), intent(in) :: lShuffle
648
649 ! [ LOCALS ]
650 integer (c_int) :: rain_zone
651 integer (c_int) :: iMaxRainZones
652 integer (c_int) :: iMonth
653 integer (c_int) :: iDay
654 integer (c_int) :: iYearOfSimulation
655
656 integer (c_int) :: iNumberOfFragments
657 integer (c_int) :: iStartRecord
658 integer (c_int) :: iEndRecord
659 integer (c_int) :: iTargetRecord
660 integer (c_int) :: iUBOUND_FRAGMENTS
661 integer (c_int) :: iUBOUND_CURRENT_FRAGMENTS
662
663
664 imaxrainzones = maxval(fragments%iRainGageZone)
665 imonth = sim_dt%curr%iMonth
666 iday = sim_dt%curr%iDay
667 iyearofsimulation=sim_dt%iYearOfSimulation
668
669 ! equal the number of fragments are in memory
670 iubound_fragments = ubound( fragments, 1)
671
672 ! should equal the number of rainfall gages in model domain
673 iubound_current_fragments = ubound( current_fragments, 1)
674
675 ! if by chance a mismatch in shape-to-grid results in an active cell with *NO* valid
676 ! rain gage ID, we need to set the entire array to zero to quash any spurious values getting in
677 fragment_value = 0.0_c_float
678
679 do rain_zone = 1, imaxrainzones
680
681 if ( lshuffle ) then
682 ! find next fragment *record*
683
684 ! update the module variable RANDOM_VALUES
686
687 istartrecord = fragments_sets( rain_zone )%iStartRecord(imonth)
688 inumberoffragments = fragments_sets(rain_zone)%iNumberOfFragments(imonth)
689 iendrecord = istartrecord + inumberoffragments - 1
690 itargetrecord = istartrecord &
691 + int(random_values(rain_zone, simulation_number) &
692 * real( inumberoffragments ))
693
694 if ( ( rain_zone > iubound_current_fragments ) .or. ( itargetrecord > iubound_fragments ) &
695 .or. ( rain_zone < 1 ) .or. ( itargetrecord < 1) ) then
696 call logs%write("Error detected in method of fragments routine; dump of current" &
697 //" variables follows:", ilinesbefore=1)
698 call logs%write("rain_zone : "//ascharacter(rain_zone), itab=3 )
699 call logs%write("simulation_number : "//ascharacter(rain_zone), itab=3 )
700 call logs%write("iStartRecord : "//ascharacter(istartrecord), itab=3 )
701 call logs%write("iNumberOfFragments: "//ascharacter(inumberoffragments), itab=3 )
702 call logs%write("iEndRecord : "//ascharacter(iendrecord), itab=3 )
703 call logs%write("iTargetRecord : "//ascharacter(itargetrecord), itab=3 )
704 call logs%write("ubound(CURRENT_FRAGMENTS, 1): "//ascharacter(iubound_current_fragments), &
705 itab=3 )
706 call logs%write("ubound(FRAGMENTS, 1): "//ascharacter(iubound_fragments), itab=3 )
707 call logs%write("RANDOM_VALUES(rain_zone,SIMULATION_NUMBER): " &
708 //ascharacter(random_values(rain_zone,simulation_number)), itab=3 )
709 call die( "Miscalculation in target record: calculated record index is out of bounds", &
710 __file__, __line__ )
711 endif
712
713 ! reassign fragment pointer for this rain zone to the newly selected record
714 current_fragments(rain_zone, simulation_number)%pFragment => fragments( itargetrecord )
715
716 write(lu_fragments_echo,fmt="(4(i5,','),f10.6,',',i5,',',30(f8.3,','),f8.3)") &
718 fragments( itargetrecord)%iMonth, &
719 fragments( itargetrecord)%iRainGageZone, &
720 iyearofsimulation, &
721 random_values(rain_zone, simulation_number), &
722 fragments( itargetrecord)%iFragmentSet, &
723 fragments( itargetrecord)%fFragmentValue
724
725 ! call LOGS%write( trim(sBuf), iLogLevel=LOG_DEBUG, lEcho=FALSE )
726
727 endif
728
729 if ( ( current_fragments( rain_zone, simulation_number )%pFragment%fFragmentValue( iday ) < 0.0 ) &
730 .or. ( current_fragments( rain_zone, simulation_number )%pFragment%fFragmentValue( iday ) > 1.0 ) ) then
731
732 call logs%write("Error detected in method of fragments routine; dump of current variables" &
733 //" follows:", ilinesbefore=1, iloglevel=log_all )
734 call logs%write("rain_zone:"//ascharacter(rain_zone), itab=3 )
735 call logs%write("iDay: "//ascharacter(iday), itab=3 )
736 call logs%write("iRainGageZone: "//ascharacter(fragments( itargetrecord)%iRainGageZone), itab=3 )
737 call logs%write("iFragmentSet: "//ascharacter(fragments( itargetrecord)%iFragmentSet), itab=3 )
738 call logs%write("fFragmentValue: "//ascharacter(fragments( itargetrecord)%fFragmentValue(iday) ), itab=3 )
739
740 endif
741
742 ! call LOGS%write("frag: "//asCharacter(rain_zone)//" day: "//asCharacter(iDay) &
743 ! //" value: "//asCharacter( CURRENT_FRAGMENTS( rain_zone )%pFragment%fFragmentValue( iDay ) ), &
744 ! lEcho=FALSE )
745
746 ! now place current days' fragment value into the matching cells
747 where ( rain_gage_id == rain_zone )
748
749 fragment_value = current_fragments( rain_zone, simulation_number )%pFragment%fFragmentValue( iday )
750
751 endwhere
752
753 enddo
754
755 end subroutine update_fragments
756
757!--------------------------------------------------------------------------------------------------
758
760
761 ! [ LOCALS ]
762 integer (c_int) :: iIndex, iIndex2
763 logical (c_bool) :: lSequenceSelection
764
765 if ( random_fragment_sequences ) then
766
767 do iindex2=1,size(random_values,1)
768
769 !call random_number( RANDOM_VALUES )
771
772 enddo
773
774 else
775
776 random_values(:,simulation_number) = -9999999.9
777
778 do iindex=1, size(fragments_sequence%sim_month, 1)
779
780 lsequenceselection = ( fragments_sequence(iindex)%sim_month == sim_dt%curr%iMonth ) &
781 .and. ( fragments_sequence(iindex)%sim_year == sim_dt%iYearOfSimulation ) &
782 .and. ( fragments_sequence(iindex)%sim_number == simulation_number )
783
784 if ( .not. lsequenceselection ) cycle
785
786 do iindex2=1,size(random_values,1)
787
788 if ( fragments_sequence( iindex )%sim_rainfall_zone == iindex2 ) then
789
790 random_values( iindex2, simulation_number ) = fragments_sequence( iindex )%sim_random_number
791 exit
792
793 endif
794
795 enddo
796
797 enddo
798
799 endif
800
801 if (any( random_values(:, simulation_number) < 0.0 ) ) then
802
803 call logs%write("Error detected in method of fragments routine - random values " &
804 //"not found in sequence file for rainfall zone(s):", ilinesbefore=1)
805 do iindex=1,size(random_values, 1)
806 if ( random_values(iindex, simulation_number) < 0.0 ) &
807 call logs%write("simulation number, rainfall zone: " &
808 //trim(ascharacter(simulation_number))//", "//trim(ascharacter(iindex)), itab=3 )
809 enddo
810
811 endif
812
813 end subroutine update_random_values
814
815!--------------------------------------------------------------------------------------------------
816
818
819 use ieee_exceptions, only : ieee_invalid, &
820 ieee_divide_by_zero, &
821 ieee_overflow, &
822 ieee_set_halting_mode, &
823 ieee_get_halting_mode
824 use ieee_arithmetic, only : ieee_is_nan
825
826 logical (c_bool), intent(in) :: lactive(:,:)
827
828 ! [ LOCALS ]
829 logical (c_bool), save :: lfirstcall = true
830
831 type (data_catalog_entry_t), pointer :: prainfall_adjust_factor
832 logical :: old_invalid, old_div0, old_overflow
833
834 ! attempting to keep code from choking on NaN comparisons during
835 ! file initialization
836 call ieee_get_halting_mode(ieee_invalid, old_invalid)
837 call ieee_get_halting_mode(ieee_divide_by_zero, old_div0)
838 call ieee_get_halting_mode(ieee_overflow, old_overflow)
839
840 ! Mask traps before calling into NetCDF/HDF5:
841 call ieee_set_halting_mode(ieee_invalid, .false.)
842 call ieee_set_halting_mode(ieee_divide_by_zero, .false.)
843 call ieee_set_halting_mode(ieee_overflow, .false.)
844
845 !! if it is the first day of the month, update the rainfall adjustment factor grid
846 !! and update the fragments
847 if ( sim_dt%curr%iDay == 1 .or. lfirstcall ) then
848
849 ! locate the data structure associated with the gridded rainfall adjustment factor
850 prainfall_adjust_factor => dat%find("RAINFALL_ADJUST_FACTOR")
851
852 if ( .not. associated(prainfall_adjust_factor) ) &
853 call die("A RAINFALL_ADJUST_FACTOR grid must be supplied in order to make use" &
854 //" of this option.", __file__, __line__)
855
856 call prainfall_adjust_factor%getvalues( sim_dt%curr )
857
858 ! map the 2D array of RAINFALL_ADJUST_FACTOR values to the vector of active cells
859 rainfall_adjust_factor = pack( prainfall_adjust_factor%pGrdBase%rData, lactive )
860
861 call assert(.not. any(ieee_is_nan(rainfall_adjust_factor)), &
862 smessage="NaN detected in rainfall adjustment factor grid.")
863
864 call update_fragments( lshuffle = true)
865 lfirstcall = false
866
867 else
868
869 call update_fragments( lshuffle = false )
870
871 endif
872
873 ! Restore your preferred behavior afterwards:
874 call ieee_set_halting_mode(ieee_invalid, old_invalid)
875 call ieee_set_halting_mode(ieee_divide_by_zero, old_div0)
876 call ieee_set_halting_mode(ieee_overflow, old_overflow)
877
879
880!--------------------------------------------------------------------------------------------------
881
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
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.
type(dict_t), public cf_dict
subroutine, public die(smessage, smodule, iline, shints, scalledby, icalledbyline)
Provides support for input and output of gridded ASCII data, as well as for creation and destruction ...
Definition grid.F90:8
type(logfile_t), public logs
Definition logfiles.F90:62
Module precipitation__method_of_fragments provides support for creating synthetic daily precipitation...
type(fragments_sequence_t), dimension(:), allocatable, public fragments_sequence
Array of fragment sequence sets.
real(c_float), dimension(:), allocatable, public rainfall_adjust_factor
Module variable that holds the rainfall adjustment factor.
subroutine, public precipitation_method_of_fragments_calculate(lactive)
subroutine update_fragments(lshuffle)
Update rainfall fragments on daily basis.
subroutine, public precipitation_method_of_fragments_initialize(lactive)
Initialize method of fragments.
logical(c_bool) random_fragment_sequences
Module variable detemining whether fragment sequences are chosen at random or selected from an extern...
type(ptr_fragments_t), dimension(:,:), allocatable current_fragments
Subset of rainfall fragments file pointing to the currently active fragments.
subroutine process_fragment_sets()
after fragments file has been read in, iterate over a set of rainfall fragments
integer(c_int), public simulation_number
Module variable indicating which "simulation number" is active Only has meaning if the rainfall fragm...
integer(c_int), dimension(:), allocatable, public rain_gage_id
Module variable that holds the rainfall gage (zone) number.
real(c_double), dimension(:,:), allocatable random_values
Module variable that holds a sequence of random numbers associated with the selection of the fragment...
type(fragments_set_t), dimension(:), allocatable, public fragments_sets
Array of fragments sets; fragments sets include indices to the start record associated with the fragm...
real(c_float), dimension(:), allocatable, public fragment_value
Module variable that holds the current day's rainfall fragment value.
logical(c_bool), dimension(:), allocatable sequence_selection
Module level variable used to create subsets of the FRAGMENT_SEQUENCES file.
type(fragments_t), dimension(:), allocatable, target, public fragments
Array of all fragments read in from the rainfall fragments file.
subroutine normalize_february_fragment_sequence(icount)
eliminate rainfall on the 29th day of February; bump up all other values to ensure sum = 1
type(date_range_t), public sim_dt
Data structure that holds a single line of data from the input rainfall fragments file.
Data structure to hold the current active rainfall fragments for a particular rain gage zone.
Data structure to hold static (pre-calculated) fragment selection numbers.