Soil Water Balance (SWB2)
Loading...
Searching...
No Matches
parameters.F90
Go to the documentation of this file.
2
3 use iso_c_binding, only : c_int, c_float, c_double, c_bool
4 use datetime, only : datetime_t
5 use exceptions
7 use logfiles
8 use fstring
10 use dictionary
12 implicit none
13
14 private
15
16 !! module to provide a single POC for storage and retrieval of parameter scalars and vectors
17 !! need to provide a method for storing, finding, and retrieving parameters.
18 !! dictionary: keyword, string_list
19
20 !! first create list of files. parse through each file, adding to the param dictionary.
21 !! once complete, allow other modules to interrogate the dictionary. return matches in the
22 !! data type required for the parameter. once all params are in place, the data structures can be
23 !! deallocated.
24
25 type, public :: parameters_t
26
27 type (fstring_list_t) :: filenames
28 type (fstring_list_t) :: delimiters
29 type (fstring_list_t) :: comment_chars
30 integer (c_int) :: count = 0
31
32 contains
33
35 generic :: add_file => add_filename_to_list_sub
36
38 generic :: add_parameters => add_to_param_list_sub
39
42
48
49 generic :: get_parameters => get_parameter_values_int, &
54
55 procedure :: grep_name => grep_parameter_name
56
57
58 ! other functionality:
59 ! * retrieve parameter list:
60 ! 1) input = single string
61 ! 2) input = string list
62 ! * basic error checking re: number of params in list
63
64
65
66 end type parameters_t
67
68 type (parameters_t), public :: params
69 type (dict_t), public :: params_dict
70
71 integer (c_int), parameter :: max_table_record_len = 2048
72
73contains
74
75 subroutine add_filename_to_list_sub( this, sFilename, sDelimiters, sCommentChars )
76
77 class(parameters_t) :: this
78 character (len=*), intent(in) :: sFilename
79 character (len=*), intent(in), optional :: sDelimiters
80 character (len=*), intent(in), optional :: sCommentChars
81
82 ! [ LOCALS ]
83 character (len=:), allocatable :: sDelimiters_
84 character (len=:), allocatable :: sCommentChars_
85
86 if ( present(scommentchars) ) then
87 scommentchars_ = scommentchars
88 else
89 scommentchars_ = comment_characters
90 endif
91
92 if (present(sdelimiters) ) then
93 sdelimiters_ = sdelimiters
94 else
95 sdelimiters_ = tab
96 endif
97
98 this%count = this%count + 1
99
100 call this%filenames%append( sfilename )
101 call this%delimiters%append( sdelimiters_ )
102 call this%comment_chars%append( scommentchars_ )
103
104 end subroutine add_filename_to_list_sub
105
106!--------------------------------------------------------------------------------------------------
107
108 subroutine munge_files_and_add_to_param_list_sub(this, comment_chars, delimiters)
109
110 class(parameters_t) :: this
111 character (len=*), intent(in), optional :: comment_chars
112 character (len=*), intent(in), optional :: delimiters
113
114 ! [ LOCALS ]
115 integer (c_int) :: iFileIndex, iColIndex, iTempIndex
116 integer (c_int) :: iStat
117 type (ASCII_FILE_T) :: DF
118 type (DICT_ENTRY_T), pointer :: pDict
119 type (DICT_ENTRY_T), pointer :: pCurrentDict
120 integer (c_int) :: iNumberOfHeaderLines
121 character (len=:), allocatable :: sNumberOfHeaderLines
122 character (len=256) :: column_name
123 character (len=256) :: tempstr2
124 character (len=256) :: qualified_column_name
125 character (len=256) :: filename1
126 character (len=:), allocatable :: comment_chars_
127 character (len=:), allocatable :: delimiters_
128 logical (c_bool), allocatable :: skip_this_column(:)
129 type (FSTRING_LIST_T) :: unique_file_list
130 integer (kind=c_int) :: row_indx
131 integer (c_int) :: number_of_columns
132 character (len=MAX_TABLE_RECORD_LEN) :: sRecord, sItem
133
134 if ( present(comment_chars) ) then
135 comment_chars_ = trim(comment_chars)
136 else
137 comment_chars_ = comment_characters
138 endif
139
140 if ( present(delimiters) ) then
141 delimiters_ = trim(delimiters)
142 else
143 delimiters_ = tab
144 endif
145
146 !
147 ! proper way to screen for duplicate filenames is further down in loop
148 !
149 !unique_file_list = this%filenames%unique()
150 !if ( unique_file_list%get(1) .ne. '<NA>' ) then
151
152 if ( this%filenames%get(1) .ne. '<NA>' ) then
153
154 do ifileindex = 1, this%filenames%count
155
156 filename1 = this%filenames%get(ifileindex)
157
158 ! if this filename has already been seen and processed, ignore and move on to next filename
159 if ( unique_file_list%count_matching(filename1) > 0 ) cycle
160
161 call unique_file_list%append(filename1)
162
163 ! open the file associated with current file index value
164 call df%open(sfilename = filename1, &
165 scommentchars = comment_chars_, &
166 sdelimiters = delimiters_ )
167
168 ! obtain the headers from the file
169 df%slColNames = df%readHeader()
170
171 number_of_columns = df%slColNames%count
172
173 call logs%write( "Number of columns in file: "//ascharacter( number_of_columns ), itab=35)
174
175 !call DF%slColNames%print()
176
177 if (allocated(skip_this_column)) deallocate(skip_this_column)
178 allocate(skip_this_column(number_of_columns))
179 skip_this_column = false
180
181 ! loop over each column header
182 do icolindex = 1, df%slColNames%count
183
184 column_name = df%slColNames%get(icolindex)
185
186 if ( params_dict%key_already_in_use( column_name ) ) then
187
188 skip_this_column( icolindex ) = true
189
190 call warn("Column name "//squote(column_name)//" already in use. Data in this column will be ignored." &
191 //" [filename = "//squote(filename1)//"]")
192
193 ! Dec 2019: let try eliminating duplicates from the dictionary altogether
194
195 ! ! add dictionary entry to dictionary, tack "DUP" on end of name
196 ! tempstr = trim(adjustl(tempstr))//"_DUP"
197 ! ! update the string list to reflect duplicate entry
198
199 ! call DF%slColNames%replace( iColIndex, tempstr )
200 ! call pDict%add_key( asUppercase( tempstr ) )
201 ! call PARAMS_DICT%add_entry( pDict )
202
203 else
204
205 ! create and allocate memory for dictionary entry
206 pdict => null()
207 allocate( pdict, stat=istat )
208 call assert(istat == 0, "Failed to allocate memory for dictionary object", &
209 __file__, __line__ )
210
211 ! first add the key to the dictionary entry,
212 ! then add dictionary entry to dictionary
213 call pdict%add_key( column_name )
214 call params_dict%add_entry( pdict )
215
216 endif
217
218 enddo
219
220 row_indx = 0
221
222 ! now read in the remainder of the file
223 do while ( .not. df%isEOF() )
224
225 ! read in next line of file
226 srecord = df%readLine()
227
228 ! skip blank lines
229 if ( len_trim(srecord) == 0 ) cycle
230
231 row_indx = row_indx + 1
232
233 ! loop over each column header
234 do icolindex = 1, df%slColNames%count
235
236 ! break off next column of data for the current record
237 call chomp(srecord, sitem, this%delimiters%get(ifileindex) )
238
239 if ( skip_this_column(icolindex) ) cycle
240
241 column_name = df%slColNames%get(icolindex)
242
243 ! find pointer associated with header name
244 ! (inefficient, but should be OK for small # of columns)
245 pcurrentdict => params_dict%get_entry( column_name )
246
247 if ( associated( pcurrentdict )) then
248
249 ! if not null, it means that we were able to return a pointer
250 ! associated with the current column heading
251 call pcurrentdict%add_value( sitem )
252
253 else
254
255 call warn("Internal programming error: null pointer detected" &
256 //" -- was trying to find pointer associated with column "//dquote(df%slColNames%get(icolindex)), &
257 __file__, __line__)
258
259 endif
260
261 enddo
262
263 enddo
264
265 deallocate(skip_this_column)
266
267 call df%close()
268
269 enddo
270
271 endif
272
274
275!--------------------------------------------------------------------------------------------------
276
277 subroutine add_to_param_list_sub(this, sKey, sValues, iValues, fValues, dValues, lValues)
278
279 class(parameters_t) :: this
280 character (len=*), intent(in) :: sKey
281 character (len=*), intent(in), optional :: sValues(:)
282 integer (c_int), intent(in), optional :: iValues(:)
283 real (c_float), intent(in), optional :: fValues(:)
284 real (c_double), intent(in), optional :: dValues(:)
285 logical (c_bool), intent(in), optional :: lValues(:)
286
287 ! [ LOCALS ]
288 integer (c_int) :: iStat
289 type (DICT_ENTRY_T), pointer :: pDict
290 integer (c_int) :: iIndex
291 type (DICT_ENTRY_T), pointer :: pCurrentDict
292 character (len=MAX_TABLE_RECORD_LEN) :: sRecord, sItem
293
294
295 pcurrentdict => null()
296 pcurrentdict => params_dict%get_entry( skey )
297
298 if ( .not. associated( pcurrentdict )) then
299
300 ! if key does not currently exist, make a new entry with this key value
301 allocate( pcurrentdict, stat=istat )
302
303 call assert(istat == 0, "Failed to allocate memory for dictionary object", &
304 __file__, __line__ )
305
306 ! add dictionary entry to dictionary
307 call pcurrentdict%add_key( skey )
308 call params_dict%add_entry( pcurrentdict )
309
310 endif
311
312 if ( present( svalues ) ) then
313
314 do iindex = lbound(svalues,1), ubound(svalues,1)
315
316 call pcurrentdict%add_value( svalues( iindex ) )
317
318 enddo
319
320 else if ( present ( ivalues ) ) then
321
322 do iindex = lbound(ivalues,1), ubound(ivalues,1)
323
324 call pcurrentdict%add_value( ivalues( iindex ) )
325
326 enddo
327
328 else if ( present ( fvalues ) ) then
329
330 do iindex = lbound(fvalues,1), ubound(fvalues,1)
331
332 call pcurrentdict%add_value( fvalues( iindex ) )
333
334 enddo
335
336 else if ( present ( dvalues ) ) then
337
338 do iindex = lbound(dvalues,1), ubound(dvalues,1)
339
340 call pcurrentdict%add_value( dvalues( iindex ) )
341
342 enddo
343
344 else if ( present ( lvalues ) ) then
345
346 do iindex = lbound(lvalues,1), ubound(lvalues,1)
347
348 call pcurrentdict%add_value( lvalues( iindex ) )
349
350 enddo
351
352 endif
353
354 end subroutine add_to_param_list_sub
355
356!--------------------------------------------------------------------------------------------------
357
358 function grep_parameter_name( this, sKey, lFatal ) result( slList )
359
360 class(parameters_t) :: this
361 character (len=*), intent(in) :: skey
362 logical (c_bool), intent(in), optional :: lfatal
363 type ( fstring_list_t ) :: sllist
364
365 ! [ LOCALS ]
366 logical (c_bool) :: lfatal_l
367
368 if ( present (lfatal) ) then
369 lfatal_l = lfatal
370 else
371 lfatal_l = false
372 endif
373
374 sllist = params_dict%grep_keys( asuppercase( skey ) )
375
376 if ( lfatal_l ) then
377
378 if ( sllist%get(1) .strequal. "<NA>" ) &
379 call warn( "Failed to find a lookup table column whose name contains " &
380 //dquote( skey )//".", lfatal = lfatal_l )
381
382 endif
383
384 end function grep_parameter_name
385
386!--------------------------------------------------------------------------------------------------
387
388 subroutine get_parameter_values_logical( this, lValues, slKeys, sKey, lFatal )
389
390 class(parameters_t) :: this
391 logical (c_bool), intent(in out), allocatable :: lValues(:)
392 type (FSTRING_LIST_T), intent(in out), optional :: slKeys
393 character (len=*), intent(in ), optional :: sKey
394 logical (c_bool), intent(in), optional :: lFatal
395
396 ! [ LOCALS ]
397 logical (c_bool) :: lFatal_l
398
399 if ( present (lfatal) ) then
400 lfatal_l = lfatal
401 else
402 lfatal_l = false
403 endif
404
405 if ( present( slkeys) ) then
406
407 call params_dict%get_values( slkeys=slkeys, lvalues=lvalues, &
408 is_fatal=lfatal_l )
409
410! if ( any( iValues <= iTINYVAL ) ) &
411! call warn( "Failed to find a lookup table column named " &
412! //dQuote( slKeys%list_all() )//".", lFatal = lFatal_l )
413
414 else if ( present( skey) ) then
415
416 call params_dict%get_values( skey=skey, lvalues=lvalues )
417
418! if ( any( iValues <= iTINYVAL ) ) &
419! call warn( "Failed to find a lookup table column named " &
420! //dQuote( sKey )//".", lFatal = lFatal_l )
421
422 endif
423
424 end subroutine get_parameter_values_logical
425
426!--------------------------------------------------------------------------------------------------
427
428 subroutine get_parameter_values_datetime( this, dtValues, slKeys, sKey, lFatal )
429
430 class(parameters_t) :: this
431 type (DATETIME_T), intent(in out), allocatable :: dtValues(:)
432 type (FSTRING_LIST_T), intent(in out), optional :: slKeys
433 character (len=*), intent(in ), optional :: sKey
434 logical (c_bool), intent(in), optional :: lFatal
435
436 ! [ LOCALS ]
437 logical (c_bool) :: lFatal_l
438 type (FSTRING_LIST_T) :: slValues
439 integer (c_int) :: n
440 integer (c_int) :: istat
441
442 if ( present (lfatal) ) then
443 lfatal_l = lfatal
444 else
445 lfatal_l = false
446 endif
447
448 if ( present( slkeys) ) then
449
450 call params_dict%get_values( slkeys=slkeys, slstring=slvalues, is_fatal=lfatal_l )
451
452 else if ( present( skey) ) then
453
454 call params_dict%get_values( skey=skey, slstring=slvalues )
455
456 endif
457
458 allocate(dtvalues(slvalues%count), stat=istat)
459
460 do n=1, slvalues%count
461 call dtvalues(n)%parseDate(slvalues%get(n))
462 enddo
463
464 end subroutine get_parameter_values_datetime
465
466 !--------------------------------------------------------------------------------------------------
467
468 subroutine get_parameter_values_string_list( this, slValues, slKeys, sKey, lFatal )
469
470 class(parameters_t) :: this
471 type (FSTRING_LIST_T), intent(out) :: slValues
472 type (FSTRING_LIST_T), intent(inout), optional :: slKeys
473 character (len=*), intent(in ), optional :: sKey
474 logical (c_bool), intent(in), optional :: lFatal
475
476 ! [ LOCALS ]
477 logical (c_bool) :: lFatal_l
478
479 if ( present (lfatal) ) then
480 lfatal_l = lfatal
481 else
482 lfatal_l = false
483 endif
484
485 if ( present( slkeys) ) then
486
487 call params_dict%get_values( slkeys=slkeys, slstring=slvalues, &
488 is_fatal=lfatal_l )
489
490 if ( slvalues%get(1) .strequal. "<NA>" ) then
491 call warn( "Failed to find a lookup table column named " &
492 //dquote( slkeys%list_all() )//".", lfatal = lfatal_l )
493 end if
494
495 else if ( present( skey) ) then
496
497 call params_dict%get_values( skey=skey, slstring=slvalues )
498
499 if ( slvalues%get(1) .strequal. "<NA>" ) then
500 call warn( "Failed to find a lookup table column named " &
501 //dquote( skey )//".", lfatal = lfatal_l )
502 end if
503
504 endif
505
507
508!--------------------------------------------------------------------------------------------------
509
510 subroutine get_parameter_values_int( this, iValues, slKeys, sKey, lFatal )
511
512 class(parameters_t) :: this
513 integer (c_int), intent(out), allocatable :: iValues(:)
514 type (FSTRING_LIST_T), intent(in out), optional :: slKeys
515 character (len=*), intent(in ), optional :: sKey
516 logical (c_bool), intent(in), optional :: lFatal
517
518 ! [ LOCALS ]
519 logical (c_bool) :: lFatal_l
520
521 if ( present (lfatal) ) then
522 lfatal_l = lfatal
523 else
524 lfatal_l = false
525 endif
526
527 if ( present( slkeys) ) then
528
529 call params_dict%get_values( slkeys=slkeys, ivalues=ivalues, &
530 is_fatal=lfatal_l )
531
532 if ( any( ivalues <= itinyval ) ) &
533 call warn( "Failed to find a lookup table column named " &
534 //dquote( slkeys%list_all() )//".", lfatal = lfatal_l )
535
536 else if ( present( skey) ) then
537
538 call params_dict%get_values( skey=skey, ivalues=ivalues, &
539 is_fatal=lfatal_l )
540
541 if ( any( ivalues <= itinyval ) ) &
542 call warn( "Failed to find a lookup table column named " &
543 //dquote( skey )//".", lfatal = lfatal_l )
544
545 endif
546
547 end subroutine get_parameter_values_int
548
549!--------------------------------------------------------------------------------------------------
550
551 subroutine get_parameter_values_float( this, fValues, slKeys, sKey, lFatal )
552
553 class(parameters_t) :: this
554 real (c_float), intent(in out), allocatable :: fValues(:)
555 type (FSTRING_LIST_T), intent(in out), optional :: slKeys
556 character (len=*), intent(in ), optional :: sKey
557 logical (c_bool), intent(in), optional :: lFatal
558
559 ! [ LOCALS ]
560 logical (c_bool) :: lFatal_l
561
562 if ( present (lfatal) ) then
563 lfatal_l = lfatal
564 else
565 lfatal_l = false
566 endif
567
568 if ( present( slkeys) ) then
569
570 call params_dict%get_values( slkeys=slkeys, fvalues=fvalues )
571
572 if ( any( fvalues <= ftinyval ) ) &
573 call warn( "Failed to find a lookup table column named " &
574 //dquote( slkeys%list_all() )//".", lfatal = lfatal_l )
575
576 else if ( present( skey) ) then
577
578 call params_dict%get_values( skey=skey, fvalues=fvalues, &
579 is_fatal=lfatal_l )
580
581 if ( any( fvalues <= ftinyval ) ) &
582 call warn( "Failed to find a lookup table column named " &
583 //dquote( skey )//".", lfatal = lfatal_l )
584
585 endif
586
587 end subroutine get_parameter_values_float
588
589!--------------------------------------------------------------------------------------------------
590
591 subroutine get_parameter_table_float( this, fValues, sPrefix, iNumRows, lFatal )
592
593 use fstring
594
595 class(parameters_t) :: this
596 real (c_float), intent(in out), allocatable :: fValues(:,:)
597 character (len=*), intent(in) :: sPrefix
598 integer (c_int), intent(in) :: iNumRows
599 logical (c_bool), intent(in), optional :: lFatal
600
601 ! [ LOCALS ]
602 integer (c_int) :: iIndex
603 integer (c_int) :: iStat
604 character (len=256) :: sText
605 integer (c_int) :: iNumCols
606 type (FSTRING_LIST_T) :: slList
607 real (c_float), allocatable :: fTempVal(:)
608 logical (c_bool) :: lFatal_l
609
610 if ( present (lfatal) ) then
611 lfatal_l = lfatal
612 else
613 lfatal_l = false
614 endif
615
616 sllist = params%grep_name( sprefix )
617
618 inumcols = sllist%count
619
620 if ( inumcols == 0 ) then
621
622 call warn( "Failed to find a lookup table column named " &
623 //dquote( sprefix )//".", lfatal = lfatal_l )
624
625 else
626
627 allocate( ftempval( inumrows ), stat=istat )
628 call assert( istat == 0, "Problem allocating memory.", __file__, __line__ )
629
630 allocate( fvalues( inumrows, inumcols ), stat=istat )
631 call assert( istat == 0, "Problem allocating memory." &
632 //"~iNumCols: "//ascharacter(inumcols)//"; iNumRows: "//ascharacter(inumrows) &
633 //" sPrefix: "//dquote(sprefix), __file__, __line__ )
634
635 do iindex = 1, inumcols
636
637 stext = trim( sllist%get( iindex ) )
638 call params_dict%get_values( skey=stext, fvalues=ftempval, &
639 is_fatal=lfatal_l )
640
641 call assert( size( ftempval, 1) == size( fvalues, 1), &
642 "Mismatch in array size. Dictionary key: "//squote( stext ) &
643 //" expected size: "//ascharacter( size( fvalues, 1) ) &
644 //" size of items in dictionary: " &
645 //ascharacter( size( ftempval, 1) ) )
646
647 fvalues(:,iindex) = ftempval
648 enddo
649
650 endif
651
652 end subroutine get_parameter_table_float
653
654end module parameters
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
integer(c_int), parameter, public itinyval
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)
character(len=1), parameter, public tab
Definition fstring.F90:171
character(len=3), parameter, public comment_characters
Definition fstring.F90:176
type(logfile_t), public logs
Definition logfiles.F90:62
subroutine get_parameter_values_logical(this, lvalues, slkeys, skey, lfatal)
type(parameters_t), public params
subroutine get_parameter_table_float(this, fvalues, sprefix, inumrows, lfatal)
subroutine add_to_param_list_sub(this, skey, svalues, ivalues, fvalues, dvalues, lvalues)
subroutine munge_files_and_add_to_param_list_sub(this, comment_chars, delimiters)
type(dict_t), public params_dict
subroutine get_parameter_values_string_list(this, slvalues, slkeys, skey, lfatal)
integer(c_int), parameter max_table_record_len
type(fstring_list_t) function grep_parameter_name(this, skey, lfatal)
subroutine get_parameter_values_int(this, ivalues, slkeys, skey, lfatal)
subroutine get_parameter_values_datetime(this, dtvalues, slkeys, skey, lfatal)
subroutine add_filename_to_list_sub(this, sfilename, sdelimiters, scommentchars)
subroutine get_parameter_values_float(this, fvalues, slkeys, skey, lfatal)