MOM6
mom_cap_time.F90
Go to the documentation of this file.
1 !> This was originally share code in CIME, but required CIME as a
2 !! dependency to build the MOM cap. The options here for setting
3 !! a restart alarm are useful for all caps, so a second step is to
4 !! determine if/how these could be offered more generally in a
5 !! shared library. For now we really want the MOM cap to only
6 !! depend on MOM and ESMF/NUOPC.
8 
9 ! !USES:
10 use esmf , only : esmf_time, esmf_clock, esmf_calendar, esmf_alarm
11 use esmf , only : esmf_timeget, esmf_timeset
12 use esmf , only : esmf_timeinterval, esmf_timeintervalset
13 use esmf , only : esmf_clockget, esmf_alarmcreate
14 use esmf , only : esmf_success, esmf_logwrite, esmf_logmsg_info
15 use esmf , only : esmf_logseterror, esmf_logfounderror, esmf_logerr_passthru
16 use esmf , only : esmf_rc_arg_bad
17 use esmf , only : operator(<), operator(/=), operator(+), operator(-), operator(*) , operator(>=)
18 use esmf , only : operator(<=), operator(>), operator(==)
19 
20 implicit none; private
21 
22 public :: alarminit ! initialize an alarm
23 
24 private :: timeinit
25 private :: date2ymd
26 
27 ! Clock and alarm options
28 character(len=*), private, parameter :: &
29  optnone = "none" , &
30  optnever = "never" , &
31  optnsteps = "nsteps" , &
32  optnstep = "nstep" , &
33  optnseconds = "nseconds" , &
34  optnsecond = "nsecond" , &
35  optnminutes = "nminutes" , &
36  optnminute = "nminute" , &
37  optnhours = "nhours" , &
38  optnhour = "nhour" , &
39  optndays = "ndays" , &
40  optnday = "nday" , &
41  optnmonths = "nmonths" , &
42  optnmonth = "nmonth" , &
43  optnyears = "nyears" , &
44  optnyear = "nyear" , &
45  optmonthly = "monthly" , &
46  optyearly = "yearly" , &
47  optdate = "date" , &
48  optifdays0 = "ifdays0" , &
49  optglccouplingperiod = "glc_coupling_period"
50 
51 ! Module data
52 integer, parameter :: secperday = 86400 ! Seconds per day
53 character(len=*), parameter :: u_file_u = &
54  __file__
55 
56 contains
57 
58 !> Setup an alarm in a clock. The ringtime sent to AlarmCreate
59 !! MUST be the next alarm time. If you send an arbitrary but
60 !! proper ringtime from the past and the ring interval, the alarm
61 !! will always go off on the next clock advance and this will cause
62 !! serious problems. Even if it makes sense to initialize an alarm
63 !! with some reference time and the alarm interval, that reference
64 !! time has to be advance forward to be >= the current time.
65 !! In the logic below we set an appropriate "NextAlarm" and then
66 !! we make sure to advance it properly based on the ring interval.
67 subroutine alarminit( clock, alarm, option, &
68  opt_n, opt_ymd, opt_tod, RefTime, alarmname, rc)
69  type(esmf_clock) , intent(inout) :: clock !< ESMF clock
70  type(esmf_alarm) , intent(inout) :: alarm !< ESMF alarm
71  character(len=*) , intent(in) :: option !< alarm option
72  integer , optional , intent(in) :: opt_n !< alarm freq
73  integer , optional , intent(in) :: opt_ymd !< alarm ymd
74  integer , optional , intent(in) :: opt_tod !< alarm tod (sec)
75  type(esmf_time) , optional , intent(in) :: reftime !< ref time
76  character(len=*) , optional , intent(in) :: alarmname !< alarm name
77  integer , intent(inout) :: rc !< Return code
78 
79  ! local variables
80  type(esmf_calendar) :: cal ! calendar
81  integer :: lymd ! local ymd
82  integer :: ltod ! local tod
83  integer :: cyy,cmm,cdd,csec ! time info
84  integer :: nyy,nmm,ndd,nsec ! time info
85  character(len=64) :: lalarmname ! local alarm name
86  logical :: update_nextalarm ! update next alarm
87  type(esmf_time) :: currtime ! Current Time
88  type(esmf_time) :: nextalarm ! Next restart alarm time
89  type(esmf_timeinterval) :: alarminterval ! Alarm interval
90  character(len=*), parameter :: subname = '(AlarmInit): '
91  !-------------------------------------------------------------------------------
92 
93  rc = esmf_success
94 
95  lalarmname = 'alarm_unknown'
96  if (present(alarmname)) lalarmname = trim(alarmname)
97  ltod = 0
98  if (present(opt_tod)) ltod = opt_tod
99  lymd = -1
100  if (present(opt_ymd)) lymd = opt_ymd
101 
102  ! verify parameters
103  if (trim(option) == optnsteps .or. trim(option) == optnstep .or. &
104  trim(option) == optnseconds .or. trim(option) == optnsecond .or. &
105  trim(option) == optnminutes .or. trim(option) == optnminute .or. &
106  trim(option) == optnhours .or. trim(option) == optnhour .or. &
107  trim(option) == optndays .or. trim(option) == optnday .or. &
108  trim(option) == optnmonths .or. trim(option) == optnmonth .or. &
109  trim(option) == optnyears .or. trim(option) == optnyear .or. &
110  trim(option) == optifdays0) then
111  if (.not. present(opt_n)) then
112  call esmf_logseterror(esmf_rc_arg_bad, &
113  msg=subname//trim(option)//' requires opt_n', &
114  line=__line__, &
115  file=__file__, rctoreturn=rc)
116  return
117  endif
118  if (opt_n <= 0) then
119  call esmf_logseterror(esmf_rc_arg_bad, &
120  msg=subname//trim(option)//' invalid opt_n', &
121  line=__line__, &
122  file=__file__, rctoreturn=rc)
123  return
124  endif
125  endif
126 
127  call esmf_clockget(clock, currtime=currtime, rc=rc)
128  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
129  line=__line__, &
130  file=__file__)) &
131  return
132 
133  call esmf_timeget(currtime, yy=cyy, mm=cmm, dd=cdd, s=csec, rc=rc )
134  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
135  line=__line__, &
136  file=__file__)) &
137  return
138 
139  call esmf_timeget(currtime, yy=nyy, mm=nmm, dd=ndd, s=nsec, rc=rc )
140  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
141  line=__line__, &
142  file=__file__)) &
143  return
144 
145  ! initial guess of next alarm, this will be updated below
146  if (present(reftime)) then
147  nextalarm = reftime
148  else
149  nextalarm = currtime
150  endif
151 
152  ! Determine calendar
153  call esmf_clockget(clock, calendar=cal, rc=rc)
154  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
155  line=__line__, &
156  file=__file__)) &
157  return
158 
159  ! Determine inputs for call to create alarm
160  selectcase (trim(option))
161 
162  case (optnone, optnever)
163  call esmf_timeintervalset(alarminterval, yy=9999, rc=rc)
164  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
165  line=__line__, &
166  file=__file__)) &
167  return
168  call esmf_timeset( nextalarm, yy=9999, mm=12, dd=1, s=0, calendar=cal, rc=rc )
169  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
170  line=__line__, &
171  file=__file__)) &
172  return
173  update_nextalarm = .false.
174 
175  case (optdate)
176  if (.not. present(opt_ymd)) then
177  call esmf_logseterror(esmf_rc_arg_bad, &
178  msg=subname//trim(option)//' requires opt_ymd', &
179  line=__line__, &
180  file=__file__, rctoreturn=rc)
181  return
182  endif
183  if (lymd < 0 .or. ltod < 0) then
184  call esmf_logseterror(esmf_rc_arg_bad, &
185  msg=subname//trim(option)//'opt_ymd, opt_tod invalid', &
186  line=__line__, &
187  file=__file__, rctoreturn=rc)
188  return
189  endif
190  call esmf_timeintervalset(alarminterval, yy=9999, rc=rc)
191  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
192  line=__line__, &
193  file=__file__)) &
194  return
195  call timeinit(nextalarm, lymd, cal, tod=ltod, desc="optDate", rc=rc)
196  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
197  line=__line__, &
198  file=__file__)) &
199  return
200  update_nextalarm = .false.
201 
202  case (optifdays0)
203  if (.not. present(opt_ymd)) then
204  call esmf_logseterror(esmf_rc_arg_bad, &
205  msg=subname//trim(option)//' requires opt_ymd', &
206  line=__line__, &
207  file=__file__, rctoreturn=rc)
208  return
209  endif
210  call esmf_timeintervalset(alarminterval, mm=1, rc=rc)
211  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
212  line=__line__, &
213  file=__file__)) &
214  return
215  call esmf_timeset( nextalarm, yy=cyy, mm=cmm, dd=opt_n, s=0, calendar=cal, rc=rc )
216  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
217  line=__line__, &
218  file=__file__)) &
219  return
220  update_nextalarm = .true.
221 
222  case (optnsteps, optnstep)
223  call esmf_clockget(clock, timestep=alarminterval, rc=rc)
224  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
225  line=__line__, &
226  file=__file__)) &
227  return
228  alarminterval = alarminterval * opt_n
229  update_nextalarm = .true.
230 
231  case (optnseconds, optnsecond)
232  call esmf_timeintervalset(alarminterval, s=1, rc=rc)
233  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
234  line=__line__, &
235  file=__file__)) &
236  return
237  alarminterval = alarminterval * opt_n
238  update_nextalarm = .true.
239 
240  case (optnminutes, optnminute)
241  call esmf_timeintervalset(alarminterval, s=60, rc=rc)
242  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
243  line=__line__, &
244  file=__file__)) &
245  return
246  alarminterval = alarminterval * opt_n
247  update_nextalarm = .true.
248 
249  case (optnhours, optnhour)
250  call esmf_timeintervalset(alarminterval, s=3600, rc=rc)
251  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
252  line=__line__, &
253  file=__file__)) &
254  return
255  alarminterval = alarminterval * opt_n
256  update_nextalarm = .true.
257 
258  case (optndays, optnday)
259  call esmf_timeintervalset(alarminterval, d=1, rc=rc)
260  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
261  line=__line__, &
262  file=__file__)) &
263  return
264  alarminterval = alarminterval * opt_n
265  update_nextalarm = .true.
266 
267  case (optnmonths, optnmonth)
268  call esmf_timeintervalset(alarminterval, mm=1, rc=rc)
269  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
270  line=__line__, &
271  file=__file__)) &
272  return
273  alarminterval = alarminterval * opt_n
274  update_nextalarm = .true.
275 
276  case (optmonthly)
277  call esmf_timeintervalset(alarminterval, mm=1, rc=rc)
278  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
279  line=__line__, &
280  file=__file__)) &
281  return
282  call esmf_timeset( nextalarm, yy=cyy, mm=cmm, dd=1, s=0, calendar=cal, rc=rc )
283  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
284  line=__line__, &
285  file=__file__)) &
286  return
287  update_nextalarm = .true.
288 
289  case (optnyears, optnyear)
290  call esmf_timeintervalset(alarminterval, yy=1, rc=rc)
291  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
292  line=__line__, &
293  file=__file__)) &
294  return
295  alarminterval = alarminterval * opt_n
296  update_nextalarm = .true.
297 
298  case (optyearly)
299  call esmf_timeintervalset(alarminterval, yy=1, rc=rc)
300  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
301  line=__line__, &
302  file=__file__)) &
303  return
304  call esmf_timeset( nextalarm, yy=cyy, mm=1, dd=1, s=0, calendar=cal, rc=rc )
305  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
306  line=__line__, &
307  file=__file__)) &
308  return
309  update_nextalarm = .true.
310 
311  case default
312  call esmf_logseterror(esmf_rc_arg_bad, &
313  msg=subname//' unknown option: '//trim(option), &
314  line=__line__, &
315  file=__file__, rctoreturn=rc)
316  return
317 
318  end select
319 
320  ! --------------------------------------------------------------------------------
321  ! --- AlarmInterval and NextAlarm should be set ---
322  ! --------------------------------------------------------------------------------
323 
324  ! --- advance Next Alarm so it won't ring on first timestep for
325  ! --- most options above. go back one alarminterval just to be careful
326 
327  if (update_nextalarm) then
328  nextalarm = nextalarm - alarminterval
329  do while (nextalarm <= currtime)
330  nextalarm = nextalarm + alarminterval
331  enddo
332  endif
333 
334  alarm = esmf_alarmcreate( name=lalarmname, clock=clock, ringtime=nextalarm, ringinterval=alarminterval, rc=rc)
335  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
336  line=__line__, &
337  file=__file__)) &
338  return
339 
340 end subroutine alarminit
341 
342 !> Creates the ESMF_Time object corresponding to the given input time,
343 !! given in YMD (Year Month Day) and TOD (Time-of-day) format. Sets
344 !! the time by an integer as YYYYMMDD and integer seconds in the day.
345 subroutine timeinit( Time, ymd, cal, tod, desc, logunit, rc)
346  type(esmf_time) , intent(inout) :: time !< ESMF time
347  integer , intent(in) :: ymd !< year, month, day YYYYMMDD
348  type(esmf_calendar) , intent(in) :: cal !< ESMF calendar
349  integer , intent(in), optional :: tod !< time of day in [sec]
350  character(len=*) , intent(in), optional :: desc !< description of time to set
351  integer , intent(in), optional :: logunit!< Unit for stdout output
352  integer , intent(out), optional :: rc !< Return code
353 
354  ! local varaibles
355  integer :: yr, mon, day ! Year, month, day as integers
356  integer :: ltod ! local tod
357  character(len=256) :: ldesc ! local desc
358  character(len=*), parameter :: subname = '(TimeInit) '
359  !-------------------------------------------------------------------------------
360 
361  ltod = 0
362  if (present(tod)) ltod = tod
363  ldesc = ''
364  if (present(desc)) ldesc = desc
365 
366  if ( (ymd < 0) .or. (ltod < 0) .or. (ltod > secperday) )then
367  if (present(logunit)) then
368  write(logunit,*) subname//': ERROR yymmdd is a negative number or '// &
369  'time-of-day out of bounds', ymd, ltod
370  endif
371  call esmf_logseterror(esmf_rc_arg_bad, &
372  msg=subname//' yymmdd is negative or time-of-day out of bounds ', &
373  line=__line__, &
374  file=__file__, rctoreturn=rc)
375  return
376  endif
377 
378  call date2ymd (ymd,yr,mon,day)
379 
380  call esmf_timeset( time, yy=yr, mm=mon, dd=day, s=ltod, calendar=cal, rc=rc )
381  if (esmf_logfounderror(rctocheck=rc, msg=esmf_logerr_passthru, &
382  line=__line__, &
383  file=__file__)) &
384  return
385 
386 end subroutine timeinit
387 
388 !> Converts a coded-date (yyyymmdd) into calendar year,month,day.
389 subroutine date2ymd (date, year, month, day)
390  integer, intent(in) :: date !< coded-date (yyyymmdd)
391  integer, intent(out) :: year,month,day !< calendar year,month,day
392 
393  ! local variables
394  integer :: tdate ! temporary date
395  character(*),parameter :: subname = "(date2ymd)"
396  !-------------------------------------------------------------------------------
397 
398  tdate = abs(date)
399  year = int(tdate/10000)
400  if (date < 0) then
401  year = -year
402  endif
403  month = int( mod(tdate,10000)/ 100)
404  day = mod(tdate, 100)
405 
406 end subroutine date2ymd
407 
408 end module mom_cap_time
mom_cap_time::optnminute
character(len= *), parameter, private optnminute
Definition: mom_cap_time.F90:28
mom_cap_time::optnmonth
character(len= *), parameter, private optnmonth
Definition: mom_cap_time.F90:28
mom_cap_time::optyearly
character(len= *), parameter, private optyearly
Definition: mom_cap_time.F90:28
mom_cap_time::optnsecond
character(len= *), parameter, private optnsecond
Definition: mom_cap_time.F90:28
mom_cap_time::optndays
character(len= *), parameter, private optndays
Definition: mom_cap_time.F90:28
mom_cap_time::optnever
character(len= *), parameter, private optnever
Definition: mom_cap_time.F90:28
mom_cap_time::optnhours
character(len= *), parameter, private optnhours
Definition: mom_cap_time.F90:28
mom_cap_time::timeinit
subroutine, private timeinit(Time, ymd, cal, tod, desc, logunit, rc)
Creates the ESMF_Time object corresponding to the given input time, given in YMD (Year Month Day) and...
Definition: mom_cap_time.F90:346
mom_cap_time::secperday
integer, parameter secperday
Definition: mom_cap_time.F90:52
mom_cap_time::optnmonths
character(len= *), parameter, private optnmonths
Definition: mom_cap_time.F90:28
mom_cap_time::optnsteps
character(len= *), parameter, private optnsteps
Definition: mom_cap_time.F90:28
mom_cap_time::u_file_u
character(len= *), parameter u_file_u
Definition: mom_cap_time.F90:53
mom_cap_time::optmonthly
character(len= *), parameter, private optmonthly
Definition: mom_cap_time.F90:28
mom_cap_time::optnday
character(len= *), parameter, private optnday
Definition: mom_cap_time.F90:28
mom_cap_time::optnminutes
character(len= *), parameter, private optnminutes
Definition: mom_cap_time.F90:28
mom_cap_time::optnone
character(len= *), parameter, private optnone
Definition: mom_cap_time.F90:28
mom_cap_time::alarminit
subroutine, public alarminit(clock, alarm, option, opt_n, opt_ymd, opt_tod, RefTime, alarmname, rc)
Setup an alarm in a clock. The ringtime sent to AlarmCreate MUST be the next alarm time....
Definition: mom_cap_time.F90:69
mom_cap_time::optnyear
character(len= *), parameter, private optnyear
Definition: mom_cap_time.F90:28
mom_cap_time::optnyears
character(len= *), parameter, private optnyears
Definition: mom_cap_time.F90:28
mom_cap_time::optnstep
character(len= *), parameter, private optnstep
Definition: mom_cap_time.F90:28
mom_cap_time::optdate
character(len= *), parameter, private optdate
Definition: mom_cap_time.F90:28
mom_cap_time::date2ymd
subroutine, private date2ymd(date, year, month, day)
Converts a coded-date (yyyymmdd) into calendar year,month,day.
Definition: mom_cap_time.F90:390
mom_cap_time::optifdays0
character(len= *), parameter, private optifdays0
Definition: mom_cap_time.F90:28
mom_cap_time
This was originally share code in CIME, but required CIME as a dependency to build the MOM cap....
Definition: mom_cap_time.F90:7
mom_cap_time::optnseconds
character(len= *), parameter, private optnseconds
Definition: mom_cap_time.F90:28
mom_cap_time::optglccouplingperiod
character(len= *), parameter, private optglccouplingperiod
Definition: mom_cap_time.F90:28
mom_cap_time::optnhour
character(len= *), parameter, private optnhour
Definition: mom_cap_time.F90:28