Soil Water Balance (SWB2)
Loading...
Searching...
No Matches
logfiles.F90
Go to the documentation of this file.
1module logfiles
2
3 use version_control, only : swb_version, git_commit_hash_string, &
4 git_branch_string, compile_date, compile_time, &
5 compilation_timestamp
6 use iso_c_binding, only : c_bool, c_int
7 use iso_fortran_env, only : output_unit
8 implicit none
9
10 private
11
12 public :: logfile_t
13
14 enum, bind(c)
15 enumerator :: dt_year = 1, dt_month = 2, dt_day = 3, dt_diff_fm_utc = 4, &
17 end enum
18
20
21 enum, bind(c)
22 enumerator :: log_none = 0, log_general = 1, log_debug = 2, log_all = 3
23 end enum
24
26 character (len=:), allocatable :: spathname
27 character (len=:), allocatable :: sfileprefix
28 character (len=256) :: sfilename(2)
29 logical (c_bool) :: lisopen(2) = .false._c_bool
30 integer (c_int) :: iunitnum(2) = -999
31 integer (c_int) :: istat(2)
32 integer (c_int) :: iloglevel = log_general
33
34 contains
35
36 procedure, private :: initialize_logfiles_sub
37 generic :: initialize => initialize_logfiles_sub
38
39 procedure, private :: write_to_logfiles_sub
40 generic :: write => write_to_logfiles_sub
41
42 procedure, private :: set_log_level_sub
43 generic :: set_loglevel => set_log_level_sub
44
45 procedure, private :: set_screen_echo_sub
46 generic :: set_echo => set_screen_echo_sub
47
48 procedure, private :: open_files_write_access_sub
49 generic :: open => open_files_write_access_sub
50
51 procedure, private :: close_files_sub
52 generic :: close => close_files_sub
53
54 procedure, private :: make_prefix_sub
55 generic :: make_prefix => make_prefix_sub
56
57 procedure, private :: set_output_directory_name_sub
58 generic :: set_output_directory => set_output_directory_name_sub
59
60 end type logfile_t
61
62 type (logfile_t), public :: logs
63
64 integer (c_int) :: current_log_level = log_general
65 logical (c_bool) :: current_log_echo = .false._c_bool
66 logical (c_bool), parameter :: true = .true._c_bool
67 character (len=:), allocatable :: logfile_directory_name
68
69contains
70
71 subroutine set_output_directory_name_sub( this, sDirName )
72
73 class(logfile_t) :: this
74 character (len=*), intent(in) :: sDirName
75
76 logfile_directory_name = trim(sdirname)
77
79
80!--------------------------------------------------------------------------------------------------
81
82 subroutine set_log_level_sub( this, iLogLevel )
83
84 class(logfile_t) :: this
85 integer (c_int), intent(in) :: iLogLevel
86
87 current_log_level = iloglevel
88
89 end subroutine set_log_level_sub
90
91!--------------------------------------------------------------------------------------------------
92
93 subroutine set_screen_echo_sub( this, lEcho )
94
95 class(logfile_t) :: this
96 logical (c_bool), intent(in) :: lEcho
97
98 current_log_echo = lecho
99
100 end subroutine set_screen_echo_sub
101
102!--------------------------------------------------------------------------------------------------
103
104 subroutine initialize_logfiles_sub(this, iLogLevel, sFilePrefix, lWrite_SWB_Info )
105
106 class(logfile_t) :: this
107 integer (c_int), intent(in), optional :: iLogLevel
108 character (len=*), intent(in), optional :: sFilePrefix
109 logical (c_bool), intent(in), optional :: lWrite_SWB_Info
110
111 ! [ LOCALS ]
112 integer (c_int) :: iLogLevel_l
113 logical (c_bool) :: lWrite_SWB_Info_l
114
115 if ( present( lwrite_swb_info) ) then
116 lwrite_swb_info_l = lwrite_swb_info
117 else
118 lwrite_swb_info_l = .true._c_bool
119 endif
120
121 if (present(iloglevel) ) then
122 iloglevel_l = iloglevel
123 else
124 iloglevel_l = log_general
125 endif
126
127 if ( present( sfileprefix) ) then
128 this%sFilePrefix = sfileprefix
129 else
130 call this%make_prefix()
131 endif
132
133 this%iLogLevel = iloglevel_l
134 call this%open( lwrite_swb_info=lwrite_swb_info_l )
135
136 end subroutine initialize_logfiles_sub
137
138!--------------------------------------------------------------------------------------------------
139
140 subroutine open_files_write_access_sub(this, lWrite_SWB_Info )
141
142 class(logfile_t), intent(inout) :: this
143 logical (c_bool), intent(in), optional :: lWrite_SWB_Info
144
145 ! [ LOCALS ]
146 integer (c_int) :: iIndex
147 character (len=:), allocatable :: sFilename
148 character (len=:), allocatable :: sDatetime
149 character (len=12) :: sDescriptor(2) = [ " ", "_DEBUG " ]
150 logical (c_bool) :: lWrite_SWB_Info_l
151
152 if ( present( lwrite_swb_info) ) then
153 lwrite_swb_info_l = lwrite_swb_info
154 else
155 lwrite_swb_info_l = .true._c_bool
156 endif
157
158 if ( this%iLogLevel /= log_none ) then
159
160 do iindex = 1, min(this%iLogLevel, 2)
161
162 sfilename = trim(logfile_directory_name)//trim(this%sFilePrefix)//trim(sdescriptor(iindex))//".md"
163
164 if (.not. this%lIsOpen(iindex) ) then
165
166 open(newunit=this%iUnitNum(iindex), file=sfilename, iostat=this%iStat(iindex), action='WRITE', encoding='UTF-8')
167 if (this%iStat(iindex) /= 0) then
168 write(unit=output_unit, fmt="(a)") "Failed to open logfile "//'"'//trim(sfilename)//'".'
169 stop
170 endif
171
172 if (this%iStat(iindex) == 0) this%lIsOpen(iindex) = .true._c_bool
173
174 sdatetime = make_timestamp()
175
176 if ( lwrite_swb_info_l ) then
177
178 write(this%iUnitNum(iindex), fmt="(a)") "# USGS Soil Water Balance Code run log #"
179 write(this%iUnitNum(iindex), fmt="(a,/)") repeat("-", 80)
180 write(this%iUnitNum(iindex), fmt="(a,/)") "## Model run started on "//sdatetime//" ##"
181 write(this%iUnitNum(iindex), fmt="(a)") "## SWB version "//swb_version//" compiled on " &
182 //compilation_timestamp//" ##"
183 write(this%iUnitNum(iindex), fmt="(a,/)") "Git branch and commit hash: " &
184 //trim( git_branch_string)//" "//trim(git_commit_hash_string)
185
186 endif
187
188 else
189
190 stop( "Failed to open file logfile." )
191
192 endif
193
194 enddo
195
196 endif
197
198
199 end subroutine open_files_write_access_sub
200
201!--------------------------------------------------------------------------------------------------
202
203 subroutine close_files_sub(this)
204
205 class(logfile_t) :: this
206
207 ! [ LOCALS ]
208 integer (c_int) :: iIndex
209
210 do iindex = 1,2
211
212 if (this%lIsOpen(iindex) ) then
213
214 flush ( unit=this%iUnitNum(iindex) )
215 close ( unit=this%iUnitNum(iindex) )
216
217 endif
218
219 enddo
220
221 end subroutine close_files_sub
222
223!--------------------------------------------------------------------------------------------------
224
225 subroutine make_prefix_sub(this)
226
227 class(logfile_t) :: this
228
229 ! [ LOCALS ]
230 integer (c_int) :: iValues(8)
231 character (len=2) :: sHour
232 character (len=2) :: sMinutes
233 character (len=2) :: sSeconds
234
235 character (len=2) :: sDay
236 character (len=2) :: sMonth
237 character (len=4) :: sYear
238
239 call date_and_time( values = ivalues )
240
241 write(shour, fmt="(i0.2)") ivalues( dt_hour )
242 write(sminutes, fmt="(i0.2)") ivalues( dt_minutes )
243 write(sseconds, fmt="(i0.2)") ivalues( dt_seconds )
244 write(smonth, fmt="(i0.2)") ivalues( dt_month )
245 write(sday, fmt="(i0.2)") ivalues( dt_day )
246 write(syear, fmt="(i0.4)") ivalues( dt_year )
247
248 this%sFilePrefix = "SWB_LOGFILE__"//syear//smonth//sday//"_" &
249 //shour//sminutes//sseconds
250
251 end subroutine make_prefix_sub
252
253!--------------------------------------------------------------------------------------------------
254
255 subroutine write_to_logfiles_sub(this, sMessage, iTab, iLinesBefore, &
256 iLinesAfter, iLogLevel, lEcho )
257
258 class(logfile_t) :: this
259 character (len=*), intent(in) :: sMessage
260 integer (c_int), intent(in), optional :: iTab
261 integer (c_int), intent(in), optional :: iLinesBefore
262 integer (c_int), intent(in), optional :: iLinesAfter
263 integer (c_int), intent(in), optional :: iLogLevel
264 logical (c_bool), intent(in), optional :: lEcho
265
266 ! [ LOCALS ]
267 integer (c_int) :: iTab_l
268 integer (c_int) :: iLinesBefore_l
269 integer (c_int) :: iLinesAfter_l
270
271 if (present(iloglevel) ) call this%set_loglevel( iloglevel )
272 if (present(lecho) ) call this%set_echo( lecho )
273
274 if (present(itab) ) then
275 itab_l = itab
276 else
277 itab_l = 1
278 endif
279
280 if (present(ilinesbefore) ) then
281 ilinesbefore_l = ilinesbefore
282 else
283 ilinesbefore_l = 0
284 endif
285
286 if (present(ilinesafter) ) then
287 ilinesafter_l = ilinesafter
288 else
289 ilinesafter_l = 0
290 endif
291
292 if ( current_log_echo ) then
293
294 call writemultiline(smessagetext=smessage, ilu=output_unit, &
295 itab=itab_l, ilinesbefore=ilinesbefore_l, ilinesafter=ilinesafter_l )
296
297 endif
298
299 select case ( current_log_level )
300
301 case ( log_general )
302
303 if ( this%iLogLevel >= log_general ) &
304 call writemultiline(smessagetext=smessage, ilu=this%iUnitNum( log_general ), &
305 itab=itab_l, ilinesbefore=ilinesbefore_l, ilinesafter=ilinesafter_l )
306
307 case ( log_debug )
308
309 if ( this%iLogLevel >= log_debug ) &
310 call writemultiline(smessagetext=smessage, ilu=this%iUnitNum( log_debug ), &
311 itab=itab_l, ilinesbefore=ilinesbefore_l, ilinesafter=ilinesafter_l )
312
313 case ( log_all )
314
315 if ( this%iLogLevel >= log_general ) &
316 call writemultiline(smessagetext=smessage, ilu=this%iUnitNum( log_general ), &
317 itab=itab_l, ilinesbefore=ilinesbefore_l, ilinesafter=ilinesafter_l )
318
319 if ( this%iLogLevel >= log_debug ) &
320 call writemultiline(smessagetext=smessage, ilu=this%iUnitNum( log_debug ), &
321 itab=itab_l, ilinesbefore=ilinesbefore_l, ilinesafter=ilinesafter_l )
322
323 case default
324
325 end select
326
327 end subroutine write_to_logfiles_sub
328
329!--------------------------------------------------------------------------------------------------
330
331 !> Write multiple lines of output to Fortran logical unit
332 !> @details Writes one or more lines of an input text string to a Fortran
333 !> logical unit number. To output multiple lines, insert a tilde (~) at
334 !> each point in the text string where a carriage return is desired.
335 !> @param[in] sMessageText Character string that contains the message to be written.
336 !> @param[in] iLU Integer value of the Fortran logical unit number to write to.
337 subroutine writemultiline(sMessageText, iLU, iTab, iLinesBefore, iLinesAfter)
338
339 ! [ ARGUMENTS ]
340 character (len=*), intent(in) :: sMessageText
341 integer (c_int), intent(in) :: iLU
342 integer (c_int), intent(in) :: iTab
343 integer (c_int), intent(in) :: iLinesBefore
344 integer (c_int), intent(in) :: iLinesAfter
345
346
347 ! [ LOCALS ]
348 character (len=len(sMessageText) ) :: sRecord
349 character (len=256) :: sItem
350 logical (c_bool) :: lFileOpen
351 character (len=12) :: sFmt
352 integer (c_int) :: iIndex
353
354 inquire (unit=ilu, opened=lfileopen)
355
356 srecord = trim(smessagetext)
357
358 if (lfileopen) then
359
360 if ( ilinesbefore > 0 ) then
361 do iindex=1, ilinesbefore
362 write(unit=ilu, fmt="(a,2x)" ) ""
363 enddo
364 endif
365
366 do
367
368 ! break up string with '~' as delimiter
369 call split(srecord, sitem)
370 write(sfmt, fmt="('(t',i0,' ,a)')") itab
371 if(len_trim(sitem) == 0) exit
372 write(unit=ilu,fmt=trim(sfmt) ) trim(sitem)//" "
373 enddo
374
375 if ( ilinesafter > 0 ) then
376 do iindex=1, ilinesafter
377 write(unit=ilu,fmt="(a,2x)" ) ""
378 enddo
379 endif
380
381 flush(ilu)
382
383 endif
384
385 end subroutine writemultiline
386
387!--------------------------------------------------------------------------------------------------
388
389 subroutine split(sText1, sText2)
390
391 character (len=*), intent(inout) :: sText1
392 character (len=*), intent(inout) :: sText2
393
394 ! [ LOCALS ]
395 character (len=1) :: sDelimiter
396 integer (c_int) :: iIndex
397
398 sdelimiter = "~"
399
400 stext1 = adjustl(stext1)
401
402 iindex = scan( string = stext1, set = sdelimiter )
403
404 if (iindex == 0) then
405 ! no delimiter found; return string as was supplied originally
406 stext2 = stext1
407 stext1 = ""
408 else
409 ! delimiters were found; split and return the chunks of text
410 stext2 = trim( stext1(1:iindex-1) )
411 stext1 = trim( stext1(iindex + 1:) )
412 endif
413
414 end subroutine split
415
416!--------------------------------------------------------------------------------------------------
417
418 function dquote(sText1) result(sText)
419
420 character (len=*), intent(in) :: stext1
421 character (len=len_trim(sText1)+2) :: stext
422
423 stext = '"'//trim(stext1)//'"'
424
425 end function dquote
426
427!--------------------------------------------------------------------------------------------------
428
429 function make_timestamp() result(sDatetime)
430
431 character (len=:), allocatable :: sdatetime
432
433 ! [ LOCALS ]
434 integer (c_int) :: ivalues(8)
435 character (len=2) :: shour
436 character (len=2) :: sminutes
437 character (len=2) :: sseconds
438
439 character (len=2) :: sday
440 character (len=2) :: smonth
441 character (len=4) :: syear
442 character (len=9) :: smonthname
443
444 character (len=9), parameter :: months(12) = &
445 ["January ", "February ", "March ", "April ", "May ", "June ", "July ", &
446 "August ", "September", "October ", "November ", "December "]
447
448 call date_and_time( values = ivalues )
449
450 write(shour, fmt="(i0.2)") ivalues( dt_hour )
451 write(sminutes, fmt="(i0.2)") ivalues( dt_minutes )
452 write(sseconds, fmt="(i0.2)") ivalues( dt_seconds )
453 write(smonth, fmt="(i0.2)") ivalues( dt_month )
454 write(sday, fmt="(i0.2)") ivalues( dt_day )
455 write(syear, fmt="(i0.4)") ivalues( dt_year )
456
457 smonthname = months( ivalues( dt_month ) )
458
459 sdatetime = trim(smonthname)//" "//sday//" "//syear//" "//shour//":"//sminutes//":"//sseconds
460
461 end function make_timestamp
462
463end module logfiles
character(len=len_trim(stext1)+2) function dquote(stext1)
Definition logfiles.F90:419
subroutine set_log_level_sub(this, iloglevel)
Definition logfiles.F90:83
type(logfile_t), public logs
Definition logfiles.F90:62
subroutine write_to_logfiles_sub(this, smessage, itab, ilinesbefore, ilinesafter, iloglevel, lecho)
Definition logfiles.F90:257
subroutine open_files_write_access_sub(this, lwrite_swb_info)
Definition logfiles.F90:141
subroutine initialize_logfiles_sub(this, iloglevel, sfileprefix, lwrite_swb_info)
Definition logfiles.F90:105
character(len=:) function, allocatable make_timestamp()
Definition logfiles.F90:430
subroutine make_prefix_sub(this)
Definition logfiles.F90:226
subroutine set_output_directory_name_sub(this, sdirname)
Definition logfiles.F90:72
subroutine set_screen_echo_sub(this, lecho)
Definition logfiles.F90:94
@ log_general
Definition logfiles.F90:22
subroutine close_files_sub(this)
Definition logfiles.F90:204
logical(c_bool) current_log_echo
Definition logfiles.F90:65
@ dt_diff_fm_utc
Definition logfiles.F90:15
@ dt_milliseconds
Definition logfiles.F90:15
subroutine writemultiline(smessagetext, ilu, itab, ilinesbefore, ilinesafter)
Write multiple lines of output to Fortran logical unit.
Definition logfiles.F90:338
integer(c_int) current_log_level
Definition logfiles.F90:64
character(len=:), allocatable logfile_directory_name
Definition logfiles.F90:67
logical(c_bool), parameter true
Definition logfiles.F90:66
subroutine split(stext1, stext2)
Definition logfiles.F90:390