Line data Source code
1 : !------------------------------------------------------------------------------
2 : ! Harmonized Emissions Component (HEMCO) !
3 : !------------------------------------------------------------------------------
4 : !BOP
5 : !
6 : ! !MODULE: hco_timeshift_mod.F90
7 : !
8 : ! !DESCRIPTION: Module hco\_timeshift\_mod.F90 contains routines to shift the
9 : ! file reference time by a given value. Time stamps shifts can be provided as
10 : ! optional fifth element to the time stamp attribute in the HEMCO configuration
11 : ! file.
12 : !\\
13 : !\\
14 : ! For instance, consider the case where 3-hourly averages are provided in
15 : ! individual files with centered time stamps, e.g.: file.yyyymmdd\_0130z.nc,
16 : ! file.yyyymmdd\_0430z.nc, ..., file.yyymmdd\_2230z.nc
17 : ! To read these files *at the beginning* of their time intervals, the time
18 : ! stamp can be shifted by 90 minutes, e.g. the file name, variable, and time
19 : ! attribute section reads:
20 : ! ... file.\$yyyy$mm$dd\_\$hh\$mnz.nc VARNAME 2000-2016/1-12/1-31/0-23/+90minutes ...
21 : !\\
22 : !\\
23 : ! At time 00z, HEMCO will then read file 0130z and keep using this file until
24 : ! 03z, when it switches to file 0430z. Similarly, it is possible to shift the
25 : ! file reference time by any number of years, months, days, or hours. Time
26 : ! shifts can be forward or backward in time (use - sign to shift backwards).
27 : !\\
28 : !\\
29 : ! This module contains subroutines to determine the time to be shifted (stored
30 : ! in filedata variable tshift) and shifts the desired reference time as needed.
31 : !\\
32 : !\\
33 : ! !INTERFACE:
34 : !
35 : MODULE HCO_TIMESHIFT_MOD
36 : !
37 : ! !USES:
38 : !
39 : USE HCO_Error_Mod
40 : USE HCO_State_Mod, ONLY : HCO_State
41 :
42 : IMPLICIT NONE
43 : PRIVATE
44 : !
45 : ! !PUBLIC MEMBER FUNCTIONS:
46 : !
47 : PUBLIC :: TimeShift_Set
48 : PUBLIC :: TimeShift_Apply
49 : !
50 : ! !REMARKS:
51 : !
52 : ! !REVISION HISTORY:
53 : ! 29 Feb 2016 - C. Keller - Initial version
54 : ! See https://github.com/geoschem/hemco for complete history
55 : !EOP
56 : !------------------------------------------------------------------------------
57 : !BOC
58 : !
59 : ! !PRIVATE TYPES:
60 : !
61 : CONTAINS
62 : !EOC
63 : !------------------------------------------------------------------------------
64 : ! Harmonized Emissions Component (HEMCO) !
65 : !------------------------------------------------------------------------------
66 : !BOP
67 : !
68 : ! !IROUTINE: TimeShift_Set
69 : !
70 : ! !DESCRIPTION: Subroutine TimeShift\_Set sets the time shift values. The
71 : ! time shift attribute tshift contains two entries: the first entry denotes
72 : ! the number of months to be shifted (integer value), while the second entry
73 : ! denotes then number of seconds to be shifted.
74 : !\\
75 : !\\
76 : ! !INTERFACE:
77 : !
78 0 : SUBROUTINE TimeShift_Set( HcoConfig, Dta, shift, RC )
79 : !
80 : ! !USES:
81 : !
82 : USE HCO_TYPES_MOD, ONLY : ListCont
83 : USE HCO_TYPES_MOD, ONLY : FileData
84 : USE HCO_TYPES_MOD, ONLY : ConfigObj
85 : !
86 : ! !INPUT/OUTPUT PARAMETERS:
87 : !
88 : TYPE(ConfigObj), POINTER :: HcoConfig ! HEMCO config
89 : TYPE(FileData), POINTER :: Dta ! file container
90 : CHARACTER(LEN=*), INTENT(IN ) :: shift ! time shift
91 : INTEGER, INTENT(INOUT) :: RC ! Return code
92 : !
93 : ! !REVISION HISTORY:
94 : ! 29 Feb 2016 - C. Keller - Initial version
95 : ! See https://github.com/geoschem/hemco for complete history
96 : !EOP
97 : !------------------------------------------------------------------------------
98 : !BOC
99 : !
100 : ! !LOCAL VARIABLES:
101 : !
102 : INTEGER :: SHFT, IDX
103 : CHARACTER(LEN=255) :: MSG
104 : CHARACTER(LEN=255) :: iShift
105 : CHARACTER(LEN=255) :: tShift
106 : CHARACTER(LEN=255), PARAMETER :: LOC = 'TimeShift_Set (hco_timeshift_mod.F90)'
107 :
108 : !======================================================================
109 : ! TimeShift_Set begins here!
110 : !======================================================================
111 :
112 : ! Assume success until otherwise
113 0 : RC = HCO_SUCCESS
114 :
115 : ! Init
116 0 : Dta%tShift(:) = 0.0_hp
117 :
118 : ! Mirror variable
119 0 : iShift = TRIM(ADJUSTL(Shift))
120 :
121 : ! Parse time iShift and write to desired slot:
122 0 : IDX = INDEX( TRIM(iShift), 'year' )
123 0 : IF( IDX < 0 ) IDX = INDEX( TRIM(iShift), 'yr' )
124 0 : IF ( IDX > 1 ) THEN
125 0 : READ( iShift(1:(IDX-1)), * ) SHFT
126 0 : Dta%tShift(1) = Dta%tShift(1) + SHFT
127 0 : WRITE(tShift,*) Dta%tShift(1), ' years'
128 : ENDIF
129 :
130 0 : IDX = INDEX( TRIM(iShift), 'month' )
131 0 : IF( IDX < 0 ) IDX = INDEX( TRIM(iShift), 'mt' )
132 0 : IF ( IDX > 1 ) THEN
133 0 : READ( iShift(1:(IDX-1)), * ) SHFT
134 0 : Dta%tShift(2) = Dta%tShift(2) + SHFT
135 0 : WRITE(tShift,*) Dta%tShift(2), ' months'
136 : ENDIF
137 :
138 0 : IDX = INDEX( TRIM(iShift), 'day' )
139 0 : IF( IDX < 0 ) IDX = INDEX( TRIM(iShift), 'dy' )
140 0 : IF ( IDX > 1 ) THEN
141 0 : READ( iShift(1:(IDX-1)), * ) SHFT
142 0 : Dta%tShift(3) = Dta%tShift(3) + SHFT
143 0 : WRITE(tShift,*) Dta%tShift(3), ' days'
144 : ENDIF
145 :
146 0 : IDX = INDEX( TRIM(iShift), 'hour' )
147 0 : IF( IDX < 0 ) IDX = INDEX( TRIM(iShift), 'hr' )
148 0 : IF ( IDX > 1 ) THEN
149 0 : READ( iShift(1:(IDX-1)), * ) SHFT
150 0 : Dta%tShift(4) = Dta%tShift(4) + SHFT
151 0 : WRITE(tShift,*) Dta%tShift(4), ' hours'
152 : ENDIF
153 :
154 0 : IDX = INDEX( TRIM(iShift), 'min' )
155 0 : IF( IDX < 0 ) IDX = INDEX( TRIM(iShift), 'mn' )
156 0 : IF ( IDX > 1 ) THEN
157 0 : READ( iShift(1:(IDX-1)), * ) SHFT
158 0 : Dta%tShift(5) = Dta%tShift(5) + SHFT
159 0 : WRITE(tShift,*) Dta%tShift(5), ' minutes'
160 : ENDIF
161 :
162 0 : IDX = INDEX( TRIM(iShift), 'sec' )
163 0 : IF ( IDX > 1 ) THEN
164 0 : READ( iShift(1:(IDX-1)), * ) SHFT
165 0 : Dta%tShift(6) = Dta%tShift(6) + SHFT
166 0 : WRITE(tShift,*) Dta%tShift(6), ' seconds'
167 : ENDIF
168 :
169 : ! Error: cannot shift data if we use weekday data
170 : IF ( Dta%tShift(1) /= 0 .OR. Dta%tShift(2) /= 0 .or. &
171 : Dta%tShift(3) /= 0 .OR. Dta%tShift(4) /= 0 .or. &
172 0 : Dta%tShift(5) /= 0 .OR. Dta%tShift(6) /= 0 ) THEN
173 0 : IF ( Dta%ncDys(1) == -10 .OR. &
174 : ( Dta%ncDys(1) == 1 .AND. Dta%ncDys(2) == 7 ) ) THEN
175 0 : WRITE(MSG,*) 'Time shift not supported for weekday data: ', &
176 0 : TRIM(Dta%ncFile)
177 0 : CALL HCO_ERROR( MSG, RC, THISLOC=LOC )
178 0 : RETURN
179 : ENDIF
180 : ENDIF
181 :
182 : ! verbose mode
183 0 : IF ( HCO_IsVerb( HcoConfig%Err ) ) THEN
184 0 : WRITE(MSG,*) 'Will shift time stamp of field ', TRIM(Dta%ncPara), &
185 0 : ': ', TRIM(tShift)
186 0 : CALL HCO_MSG(HcoConfig%Err,MSG)
187 : ENDIF
188 :
189 0 : RC = HCO_SUCCESS
190 :
191 0 : END SUBROUTINE TimeShift_Set
192 : !EOC
193 : !------------------------------------------------------------------------------
194 : ! Harmonized Emissions Component (HEMCO) !
195 : !------------------------------------------------------------------------------
196 : !BOP
197 : !
198 : ! !IROUTINE: TimeShift_Apply
199 : !
200 : ! !DESCRIPTION: Subroutine TimeShift\_Apply shifts the reference time
201 : ! (provided through arguments yr, mt, dy, hr, and mn, by the time shift
202 : ! specified in the HEMCO configuration file (if specified at all).
203 : !\\
204 : !\\
205 : ! !INTERFACE:
206 : !
207 0 : SUBROUTINE TimeShift_Apply( HcoState, Lct, &
208 : yr, mt, dy, hr, mn, RC )
209 : !
210 : ! !USES:
211 : !
212 : USE HCO_Julday_Mod
213 : USE HCO_TYPES_MOD, ONLY : ListCont
214 : !
215 : ! !INPUT/OUTPUT PARAMETERS:
216 : !
217 : TYPE(HCO_State), POINTER :: HcoState ! Hemco state
218 : TYPE(ListCont), POINTER :: Lct ! List container
219 : INTEGER, INTENT(INOUT) :: yr ! year
220 : INTEGER, INTENT(INOUT) :: mt ! month
221 : INTEGER, INTENT(INOUT) :: dy ! day
222 : INTEGER, INTENT(INOUT) :: hr ! hour
223 : INTEGER, INTENT(INOUT) :: mn ! minute
224 : INTEGER, INTENT(INOUT) :: RC ! Return code
225 : !
226 : ! !REVISION HISTORY:
227 : ! 29 Feb 2016 - C. Keller - Initial version
228 : ! See https://github.com/geoschem/hemco for complete history
229 : !EOP
230 : !------------------------------------------------------------------------------
231 : !BOC
232 : !
233 : ! !LOCAL VARIABLES:
234 : !
235 : INTEGER :: nYr, nMt, nDy, nHr, nMn
236 : INTEGER :: oYr, oMt, oDy, oHr, oMn
237 : INTEGER :: SHFT, IDX
238 : INTEGER :: YYYYMMDD, HHMMSS
239 : REAL(dp) :: TimeShift, DAY, UTC, JD
240 :
241 : CHARACTER(LEN=255) :: MSG
242 : CHARACTER(LEN=255), PARAMETER :: LOC = 'TimeShift_Apply (hco_timeshift_mod.F90)'
243 :
244 : !======================================================================
245 : ! TimeShift_Apply begins here!
246 : !======================================================================
247 :
248 : ! Assume success until otherwise
249 0 : RC = HCO_SUCCESS
250 :
251 : ! Nothing to do if time shift is zero
252 : IF ( Lct%Dct%Dta%tShift(1) == 0 .AND. &
253 : Lct%Dct%Dta%tShift(2) == 0 .AND. &
254 : Lct%Dct%Dta%tShift(3) == 0 .AND. &
255 : Lct%Dct%Dta%tShift(4) == 0 .AND. &
256 0 : Lct%Dct%Dta%tShift(5) == 0 .AND. &
257 0 : Lct%Dct%Dta%tShift(6) == 0 ) RETURN
258 :
259 : ! Mirror values
260 0 : nYr = MAX(Yr,1)
261 0 : nMt = MAX(Mt,1)
262 0 : nDy = MAX(Dy,1)
263 0 : nHr = MAX(Hr,0)
264 0 : nMn = MAX(Mn,0)
265 :
266 : ! Archive original values
267 0 : oYr = nYr
268 0 : oMt = nMt
269 0 : oDy = nDy
270 0 : oHr = nHr
271 0 : oMn = nMn
272 :
273 : ! Apply minute time shift
274 0 : IF ( ABS(Lct%Dct%Dta%tShift(5)) > 0 ) THEN
275 0 : nMn = nMn + Lct%Dct%Dta%tShift(5)
276 : ENDIF
277 :
278 : ! Make sure new minute value is within 0-59 and adjust hour accordingly
279 0 : IF ( nMn > 59 ) THEN
280 0 : DO WHILE ( nMn > 59 )
281 0 : nMn = nMn - 60
282 0 : nHr = nHr + 1
283 : ENDDO
284 0 : ELSEIF( nMn < 0 ) THEN
285 0 : DO WHILE ( nMn < 1 )
286 0 : nMn = nMn + 60
287 0 : nHr = nHr - 1
288 : ENDDO
289 : ENDIF
290 :
291 : ! Apply hour time shift
292 0 : IF ( ABS(Lct%Dct%Dta%tShift(4)) > 0 ) THEN
293 0 : nHr = nHr + Lct%Dct%Dta%tShift(4)
294 : ENDIF
295 :
296 : ! Make sure new hour value is within 0-23 and adjust day accordingly
297 0 : IF ( nHr > 23 ) THEN
298 0 : DO WHILE ( nHr > 23 )
299 0 : nHr = nHr - 24
300 0 : nDy = nDy + 1
301 : ENDDO
302 0 : ELSEIF( nHr < 0 ) THEN
303 0 : DO WHILE ( nHr < 1 )
304 0 : nHr = nHr + 24
305 0 : nDy = nDy - 1
306 : ENDDO
307 : ENDIF
308 :
309 : ! Apply day time shift
310 0 : IF ( ABS(Lct%Dct%Dta%tShift(3)) > 0 ) THEN
311 0 : nDy = nDy + Lct%Dct%Dta%tShift(3)
312 : ENDIF
313 :
314 : ! Make sure new day is within ndays in month and adjust month accordingly
315 0 : IF ( nDy > 28 .AND. oMt == 2 .AND. MOD( oYr, 4 ) /= 0 ) THEN
316 0 : nDy = nDy - 28
317 0 : nMt = nMt + 1
318 0 : ELSEIF ( nDy > 29 .AND. oMt == 2 .AND. MOD( oYr, 4 ) == 0) THEN
319 0 : nDy = nDy - 29
320 0 : nMt = nMt + 1
321 0 : ELSEIF ( nDy > 30 .AND. &
322 : ( oMt == 4 .OR. oMt == 6 .OR. oMt == 9 .OR. oMt == 11 ) ) THEN
323 0 : nDy = nDy - 30
324 0 : nMt = nMt + 1
325 0 : ELSEIF ( nDy > 31 .AND. &
326 : ( oMt == 1 .OR. oMt == 3 .OR. oMt == 5 .OR. oMt == 7 .OR. &
327 : oMt == 8 .OR. oMt == 10 .OR. oMt == 12 ) ) THEN
328 0 : nDy = nDy - 31
329 0 : nMt = nMt + 1
330 0 : ELSEIF ( nDy <= 0 ) THEN
331 0 : IF ( oMt == 3 ) THEN
332 0 : IF ( MOD( oYr, 4 ) == 0 ) THEN
333 0 : nDy = nDy + 29
334 : ELSE
335 0 : nDy = nDy + 28
336 : ENDIF
337 0 : nMt = nMt - 1
338 0 : ELSEIF ( oMt == 5 .OR. oMt == 7 .OR. oMt == 10 .OR. oMt == 12 ) THEN
339 0 : nDy = nDy + 30
340 0 : nMt = nMt - 1
341 : ELSEIF ( oMt == 1. .OR. oMt == 2 .OR. oMt == 4 .OR. oMt == 6 .OR. &
342 0 : oMt == 8 .OR. oMt == 9 .OR. oMt == 11 ) THEN
343 0 : nDy = nDy + 31
344 0 : nMt = nMt - 1
345 : ENDIF
346 : ENDIF
347 :
348 : ! Apply month time shift
349 0 : IF ( ABS(Lct%Dct%Dta%tShift(2)) > 0 ) THEN
350 0 : nMt = nMt + Lct%Dct%Dta%tShift(2)
351 : ENDIF
352 :
353 : ! Make sure new month is within 1-12 and adjust year accordingly
354 0 : IF ( nMt > 12 ) THEN
355 0 : DO WHILE ( nMt > 12 )
356 0 : nMt = nMt - 12
357 0 : nYr = nYr + 1
358 : ENDDO
359 0 : ELSEIF( nMt <= 0 ) THEN
360 0 : DO WHILE ( nMt < 1 )
361 0 : nMt = nMt + 12
362 0 : nYr = nYr - 1
363 : ENDDO
364 : ENDIF
365 :
366 : ! Apply year time shift
367 0 : IF ( ABS(Lct%Dct%Dta%tShift(1)) > 0 ) THEN
368 0 : nYr = nYr + Lct%Dct%Dta%tShift(1)
369 : ENDIF
370 :
371 : ! Eventually cap time shift for the same day.
372 0 : IF ( HcoState%Options%TimeShiftCap ) THEN
373 : IF ( ( nYr < oYr ) .OR. &
374 0 : ( nMt < oMt .AND. nYr == oYr ) .OR. &
375 : ( nDy < oDy .AND. nMt == oMt ) ) THEN
376 0 : nYr = oYr
377 0 : nMt = oMt
378 0 : nDy = oDy
379 0 : nHr = 0
380 0 : nMn = 0
381 0 : IF ( HCO_IsVerb( HcoState%Config%Err ) ) THEN
382 0 : MSG = 'Options set to cap time shift - set to low bound'
383 0 : CALL HCO_MSG(HcoState%Config%Err,MSG)
384 : ENDIF
385 0 : ELSEIF ( nYr > oYr .OR. nMt > oMt .OR. nDy > oDy ) THEN
386 0 : nYr = oYr
387 0 : nMt = oMt
388 0 : nDy = oDy
389 0 : nHr = 23
390 0 : nMn = 59
391 0 : IF ( HCO_IsVerb( HcoState%Config%Err ) ) THEN
392 0 : MSG = 'Options set to cap time shift - set to high bound'
393 0 : CALL HCO_MSG(HcoState%Config%Err,MSG)
394 : ENDIF
395 : ENDIF
396 : ENDIF
397 :
398 : ! verbose mode
399 0 : IF ( HCO_IsVerb( HcoState%Config%Err ) ) THEN
400 0 : WRITE(MSG,*) 'Adjusted time stamp of field ', TRIM(Lct%Dct%cName)
401 0 : CALL HCO_MSG(HcoState%Config%Err,MSG)
402 0 : WRITE(MSG,*) 'Time shift (YMDhms): ', Lct%Dct%Dta%tShift
403 0 : CALL HCO_MSG(HcoState%Config%Err,MSG)
404 0 : WRITE(MSG,'(a27,i4.4,a1,i2.2,a1,i2.2,a1,i2.2,a1,i2.2)') 'Original Yr/Mt/Dy-Hr:Mn = ',oYr,'/',oMt,'/',oDy,'-',oHr,':',oMn
405 0 : CALL HCO_MSG(HcoState%Config%Err,MSG)
406 : ENDIF
407 :
408 : ! Add back to output values
409 0 : Yr = nYr
410 0 : Mt = nMt
411 0 : Dy = nDy
412 0 : Hr = nHr
413 0 : Mn = nMn
414 :
415 : ! verbose mode
416 0 : IF ( HCO_IsVerb( HcoState%Config%Err ) ) THEN
417 0 : WRITE(MSG,'(a27,i4.4,a1,i2.2,a1,i2.2,a1,i2.2,a1,i2.2)') 'Adjusted Yr/Mt/Dy-Hr:Mn = ',Yr,'/',Mt,'/',Dy,'-',Hr,':',Mn
418 0 : CALL HCO_MSG(HcoState%Config%Err,MSG)
419 : ENDIF
420 :
421 : ! Return w/ success
422 0 : RC = HCO_SUCCESS
423 :
424 : END SUBROUTINE TimeShift_Apply
425 : !EOC
426 : END MODULE HCO_TIMESHIFT_MOD
|