/[lmdze]/trunk/IOIPSL/calendar.f
ViewVC logotype

Annotation of /trunk/IOIPSL/calendar.f

Parent Directory Parent Directory | Revision Log Revision Log


Revision 91 - (hide annotations)
Wed Mar 26 17:18:58 2014 UTC (10 years, 2 months ago) by guez
File size: 15912 byte(s)
Removed unused variables lock_startdate and time_stamp of module
calendar.

Noticed that physiq does not change the surface pressure. So removed
arguments ps and dpfi of subroutine addfi. dpfi was always 0. The
computation of ps in addfi included some averaging at the poles. In
principle, this does not change ps but in practice it does because of
finite numerical precision. So the results of the simulation are
changed. Removed arguments ps and dpfi of calfis. Removed argument
d_ps of physiq.

du at the poles is not computed by dudv1, so declare only the
corresponding latitudes in dudv1. caldyn passes only a section of the
array dudyn as argument.

Removed variable niadv of module iniadvtrac_m.

Declared arguments of exner_hyb as assumed-shape arrays and made all
other horizontal sizes in exner_hyb dynamic. This allows the external
program test_disvert to use exner_hyb at a single horizontal position.

1 guez 30 MODULE calendar
2 guez 36
3     ! From IOIPSL/src/calendar.f90, version 2.0 2004/04/05 14:47:47
4    
5 guez 62 ! This is the calendar used to do all calculations on time. Three
6     ! types of calendars are possible:
7 guez 36
8 guez 62 ! - Gregorian:
9     ! The normal calendar. The time origin for the julian day in this
10     ! case is 24 Nov -4713.
11    
12     ! - No leap:
13     ! A 365 day year without leap years. The origin for the julian days
14     ! is in this case 1 Jan 0.
15    
16     ! - xxxd:
17     ! Year of xxx days with months of equal length. The origin for the
18     ! julian days is then also 1 Jan 0.
19    
20     ! As one can see it is difficult to go from one calendar to the
21     ! other. All operations involving julian days will be wrong. This
22     ! calendar will lock as soon as possible the length of the year and
23     ! forbid any further modification.
24    
25     ! For the non leap-year calendar the method is still brute force.
26     ! We need to find an integer series which takes care of the length
27     ! of the various month. (Jan)
28    
29     USE strlowercase_m, ONLY: strlowercase
30     USE errioipsl, ONLY: histerr
31    
32     IMPLICIT NONE
33    
34 guez 30 PRIVATE
35 guez 62 PUBLIC ymds2ju, ju2ymds, isittime, ioconf_calendar, itau2date, lock_unan, &
36     calendar_used, un_an, un_jour
37 guez 30
38 guez 62 REAL, PARAMETER:: un_jour = 86400. ! one day in seconds
39    
40     ! Description of calendar
41    
42     CHARACTER(LEN=20):: calendar_used = "gregorian"
43     LOGICAL:: lock_unan = .FALSE.
44     REAL:: un_an = 365.2425 ! one year in days
45     INTEGER:: mon_len(12) = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
46    
47     CHARACTER(LEN=3), PARAMETER:: cal(12) = (/'JAN', 'FEB', 'MAR', 'APR', &
48     'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'/)
49    
50     REAL, SAVE:: start_day, start_sec
51    
52 guez 30 CONTAINS
53    
54 guez 62 SUBROUTINE ymds2ju (year, month, day, sec, julian)
55 guez 30
56 guez 62 INTEGER, INTENT(IN):: year, month, day
57     REAL, INTENT(IN):: sec
58     REAL, INTENT(OUT):: julian
59 guez 30
60 guez 62 INTEGER:: julian_day
61     REAL:: julian_sec
62 guez 30
63 guez 62 !--------------------------------------------------------------------
64 guez 30
65 guez 62 CALL ymds2ju_internal(year, month, day, sec, julian_day, julian_sec)
66 guez 36 julian = julian_day + julian_sec / un_jour
67 guez 62
68 guez 30 END SUBROUTINE ymds2ju
69    
70     !===
71    
72 guez 62 SUBROUTINE ymds2ju_internal (year, month, day, sec, julian_day, julian_sec)
73 guez 30
74 guez 62 ! Converts year, month, day and seconds into a julian day
75 guez 30
76 guez 62 ! In 1968 in a letter to the editor of Communications of the ACM
77     ! (CACM, volume 11, number 10, October 1968, p.657) Henry F. Fliegel
78     ! and Thomas C. Van Flandern presented such an algorithm.
79 guez 30
80 guez 62 ! See also: http://www.magnet.ch/serendipity/hermetic/cal_stud/jdn.htm
81 guez 30
82 guez 62 ! In the case of the Gregorian calendar we have chosen to use
83     ! the Lilian day numbers. This is the day counter which starts
84     ! on the 15th October 1582.
85     ! This is the day at which Pope Gregory XIII introduced the
86     ! Gregorian calendar.
87     ! Compared to the true Julian calendar, which starts some
88     ! 7980 years ago, the Lilian days are smaler and are dealt with
89     ! easily on 32 bit machines. With the true Julian days you can only
90     ! the fraction of the day in the real part to a precision of
91     ! a 1/4 of a day with 32 bits.
92 guez 30
93 guez 62 INTEGER, INTENT(IN):: year, month, day
94     REAL, INTENT(IN):: sec
95 guez 30
96 guez 62 INTEGER, INTENT(OUT):: julian_day
97     REAL, INTENT(OUT):: julian_sec
98    
99     INTEGER:: jd, m, y, d, ml
100     !--------------------------------------------------------------------
101 guez 30 lock_unan = .TRUE.
102    
103     m = month
104     y = year
105     d = day
106    
107 guez 62 ! We deduce the calendar from the length of the year as it
108     ! is faster than an INDEX on the calendar variable.
109 guez 30
110 guez 62 ! Gregorian
111 guez 30 IF ( (un_an > 365.0).AND.(un_an < 366.0) ) THEN
112     jd = (1461*(y+4800+INT(( m-14 )/12)))/4 &
113     & +(367*(m-2-12*(INT(( m-14 )/12))))/12 &
114     & -(3*((y+4900+INT((m-14)/12))/100))/4 &
115     & +d-32075
116     jd = jd-2299160
117 guez 62 ! No leap or All leap
118 guez 30 ELSE IF (ABS(un_an-365.0) <= EPSILON(un_an) .OR. &
119     & ABS(un_an-366.0) <= EPSILON(un_an)) THEN
120     ml = SUM(mon_len(1:m-1))
121     jd = y*INT(un_an)+ml+(d-1)
122 guez 62 ! Calendar with regular month
123 guez 30 ELSE
124     ml = INT(un_an)/12
125     jd = y*INT(un_an)+(m-1)*ml+(d-1)
126     ENDIF
127    
128     julian_day = jd
129     julian_sec = sec
130 guez 62
131 guez 30 END SUBROUTINE ymds2ju_internal
132 guez 62
133 guez 30 !===
134    
135 guez 62 SUBROUTINE ju2ymds (julian, year, month, day, sec)
136 guez 30
137 guez 62 REAL, INTENT(IN):: julian
138 guez 30
139 guez 62 INTEGER, INTENT(OUT):: year, month, day
140     REAL, INTENT(OUT):: sec
141    
142     INTEGER:: julian_day
143     REAL:: julian_sec
144     !--------------------------------------------------------------------
145 guez 30 julian_day = INT(julian)
146     julian_sec = (julian-julian_day)*un_jour
147    
148 guez 62 CALL ju2ymds_internal(julian_day, julian_sec, year, month, day, sec)
149    
150 guez 30 END SUBROUTINE ju2ymds
151 guez 62
152 guez 30 !===
153    
154 guez 62 SUBROUTINE ju2ymds_internal (julian_day, julian_sec, year, month, day, sec)
155 guez 30
156 guez 62 ! This subroutine computes from the julian day the year,
157     ! month, day and seconds
158 guez 30
159 guez 62 ! In 1968 in a letter to the editor of Communications of the ACM
160     ! (CACM, volume 11, number 10, October 1968, p.657) Henry F. Fliegel
161     ! and Thomas C. Van Flandern presented such an algorithm.
162 guez 30
163 guez 62 ! See also: http://www.magnet.ch/serendipity/hermetic/cal_stud/jdn.htm
164 guez 30
165 guez 62 ! In the case of the Gregorian calendar we have chosen to use
166     ! the Lilian day numbers. This is the day counter which starts
167     ! on the 15th October 1582. This is the day at which Pope
168     ! Gregory XIII introduced the Gregorian calendar.
169     ! Compared to the true Julian calendar, which starts some 7980
170     ! years ago, the Lilian days are smaler and are dealt with easily
171     ! on 32 bit machines. With the true Julian days you can only the
172     ! fraction of the day in the real part to a precision of a 1/4 of
173     ! a day with 32 bits.
174 guez 30
175 guez 62 INTEGER, INTENT(IN):: julian_day
176     REAL, INTENT(IN):: julian_sec
177    
178     INTEGER, INTENT(OUT):: year, month, day
179     REAL, INTENT(OUT):: sec
180    
181     INTEGER:: l, n, i, jd, j, d, m, y, ml
182     INTEGER:: add_day
183     !--------------------------------------------------------------------
184 guez 30 lock_unan = .TRUE.
185    
186     jd = julian_day
187     sec = julian_sec
188     IF (sec > un_jour) THEN
189     add_day = INT(sec/un_jour)
190     sec = sec-add_day*un_jour
191     jd = jd+add_day
192     ENDIF
193    
194 guez 62 ! Gregorian
195 guez 30 IF ( (un_an > 365.0).AND.(un_an < 366.0) ) THEN
196     jd = jd+2299160
197    
198     l = jd+68569
199     n = (4*l)/146097
200     l = l-(146097*n+3)/4
201     i = (4000*(l+1))/1461001
202     l = l-(1461*i)/4+31
203     j = (80*l)/2447
204     d = l-(2447*j)/80
205     l = j/11
206     m = j+2-(12*l)
207     y = 100*(n-49)+i+l
208 guez 62 ! No leap or All leap
209 guez 30 ELSE IF (ABS(un_an-365.0) <= EPSILON(un_an) .OR. &
210     & ABS(un_an-366.0) <= EPSILON(un_an) ) THEN
211     y = jd/INT(un_an)
212     l = jd-y*INT(un_an)
213     m = 1
214     ml = 0
215     DO WHILE (ml+mon_len(m) <= l)
216     ml = ml+mon_len(m)
217     m = m+1
218     ENDDO
219     d = l-ml+1
220 guez 62 ! others
221 guez 30 ELSE
222     ml = INT(un_an)/12
223     y = jd/INT(un_an)
224     l = jd-y*INT(un_an)
225     m = (l/ml)+1
226     d = l-(m-1)*ml+1
227     ENDIF
228    
229     day = d
230     month = m
231     year = y
232 guez 62
233 guez 30 END SUBROUTINE ju2ymds_internal
234 guez 62
235 guez 30 !===
236    
237 guez 62 REAL FUNCTION itau2date (itau, date0, deltat)
238 guez 30
239 guez 62 ! This function transforms itau into a date. The date whith which
240     ! the time axis is going to be labeled
241 guez 30
242 guez 62 ! INPUT
243     ! itau: current time step
244     ! date0: Date at which itau was equal to 0
245     ! deltat: time step between itau s
246    
247     ! OUTPUT
248     ! itau2date: Date for the given itau
249    
250     INTEGER:: itau
251     REAL:: date0, deltat
252     !--------------------------------------------------------------------
253 guez 30 itau2date = REAL(itau)*deltat/un_jour+date0
254 guez 62
255 guez 30 END FUNCTION itau2date
256 guez 62
257 guez 30 !===
258 guez 62
259 guez 30 SUBROUTINE isittime &
260 guez 62 & (itau, date0, dt, freq, last_action, last_check, do_action)
261 guez 30
262 guez 62 ! This subroutine checks the time has come for a given action.
263     ! This is computed from the current time-step(itau).
264     ! Thus we need to have the time delta (dt), the frequency
265     ! of the action (freq) and the last time it was done
266     ! (last_action in units of itau).
267     ! In order to extrapolate when will be the next check we need
268     ! the time step of the last call (last_check).
269 guez 30
270 guez 62 ! The test is done on the following condition:
271     ! the distance from the current time to the time for the next
272     ! action is smaller than the one from the next expected
273     ! check to the next action.
274     ! When the test is done on the time steps simplifactions make
275     ! it more difficult to read in the code.
276     ! For the real time case it is easier to understand !
277 guez 30
278 guez 62 INTEGER, INTENT(IN):: itau
279     REAL, INTENT(IN):: dt, freq
280     INTEGER, INTENT(IN):: last_action, last_check
281     REAL, INTENT(IN):: date0
282 guez 30
283 guez 62 LOGICAL, INTENT(OUT):: do_action
284    
285     REAL:: dt_action, dt_check
286     REAL:: date_last_act, date_next_check, date_next_act, &
287     & date_now, date_mp1, date_mpf
288     INTEGER:: year, month, monthp1, day, next_check_itau, next_act_itau
289     INTEGER:: yearp, dayp
290     REAL:: sec, secp
291     LOGICAL:: check = .FALSE.
292     !--------------------------------------------------------------------
293 guez 30 IF (check) THEN
294 guez 62 WRITE(*, *) &
295     & "isittime 1.0 ", itau, date0, dt, freq, last_action, last_check
296 guez 30 ENDIF
297    
298     IF (last_check >= 0) THEN
299     dt_action = (itau-last_action)*dt
300     dt_check = (itau-last_check)*dt
301     next_check_itau = itau+(itau-last_check)
302    
303 guez 62 !- We are dealing with frequencies in seconds and thus operation
304     !- can be done on the time steps.
305 guez 30
306     IF (freq > 0) THEN
307     IF (ABS(dt_action-freq) <= ABS(dt_action+dt_check-freq)) THEN
308     do_action = .TRUE.
309     ELSE
310     do_action = .FALSE.
311     ENDIF
312    
313 guez 62 !--- Here we deal with frequencies in month and work on julian days.
314 guez 30
315     ELSE
316 guez 62 date_now = itau2date (itau, date0, dt)
317     date_last_act = itau2date (last_action, date0, dt)
318     CALL ju2ymds (date_last_act, year, month, day, sec)
319 guez 35 monthp1 = month - freq
320 guez 30 yearp = year
321    
322 guez 62 !--- Here we compute what logically should be the next month
323 guez 30
324     IF (month >= 13) THEN
325     yearp = year+1
326     monthp1 = monthp1-12
327     ENDIF
328 guez 62 CALL ymds2ju (year, monthp1, day, sec, date_mpf)
329 guez 30
330 guez 62 !--- But it could be that because of a shorter month or a bad
331     !--- starting date that we end up further than we should be.
332     !--- Thus we compute the first day of the next month.
333     !--- We can not be beyond this date and if we are close
334     !--- then we will take it as it is better.
335 guez 30
336     monthp1 = month+ABS(freq)
337     yearp=year
338     IF (monthp1 >= 13) THEN
339     yearp = year+1
340     monthp1 = monthp1 -12
341     ENDIF
342     dayp = 1
343     secp = 0.0
344 guez 62 CALL ymds2ju (yearp, monthp1, dayp, secp, date_mp1)
345 guez 30
346 guez 62 !--- If date_mp1 is smaller than date_mpf or only less than 4 days
347     !--- larger then we take it. This needed to ensure that short month
348     !--- like February do not mess up the thing !
349 guez 30
350     IF (date_mp1-date_mpf < 4.) THEN
351     date_next_act = date_mp1
352     ELSE
353     date_next_act = date_mpf
354     ENDIF
355 guez 62 date_next_check = itau2date (next_check_itau, date0, dt)
356 guez 30
357 guez 62 !--- Transform the dates into time-steps for the needed precisions.
358 guez 30
359     next_act_itau = &
360     & last_action+INT((date_next_act-date_last_act)*(un_jour/dt))
361 guez 62
362 guez 30 IF ( ABS(itau-next_act_itau) &
363     & <= ABS( next_check_itau-next_act_itau)) THEN
364     do_action = .TRUE.
365     IF (check) THEN
366 guez 62 WRITE(*, *) &
367     & 'ACT-TIME: itau, next_act_itau, next_check_itau: ', &
368     & itau, next_act_itau, next_check_itau
369     CALL ju2ymds (date_now, year, month, day, sec)
370     WRITE(*, *) 'ACT-TIME: y, m, d, s: ', year, month, day, sec
371     WRITE(*, *) &
372     & 'ACT-TIME: date_mp1, date_mpf: ', date_mp1, date_mpf
373 guez 30 ENDIF
374     ELSE
375     do_action = .FALSE.
376     ENDIF
377     ENDIF
378    
379     IF (check) THEN
380 guez 62 WRITE(*, *) "isittime 2.0 ", &
381     & date_next_check, date_next_act, ABS(dt_action-freq), &
382     & ABS(dt_action+dt_check-freq), dt_action, dt_check, &
383     & next_check_itau, do_action
384 guez 30 ENDIF
385     ELSE
386     do_action=.FALSE.
387     ENDIF
388 guez 62
389 guez 30 END SUBROUTINE isittime
390 guez 62
391 guez 30 !===
392 guez 62
393 guez 30 SUBROUTINE ioconf_calendar (str)
394    
395 guez 62 ! This routine allows to configure the calendar to be used.
396     ! This operation is only allowed once and the first call to
397     ! ymds2ju or ju2ymsd will lock the current configuration.
398     ! the argument to ioconf_calendar can be any of the following:
399     ! - gregorian: This is the gregorian calendar (default here)
400     ! - noleap: A calendar without leap years = 365 days
401     ! - xxxd: A calendar of xxx days (has to be a modulo of 12)
402     ! with 12 month of equal length
403 guez 30
404 guez 62 CHARACTER(LEN=*), INTENT(IN):: str
405 guez 30
406 guez 62 INTEGER:: leng, ipos
407     CHARACTER(LEN=10):: str10
408     !--------------------------------------------------------------------
409    
410 guez 30 ! 1.0 Clean up the sring !
411    
412     CALL strlowercase (str)
413    
414     IF (.NOT.lock_unan) THEN
415 guez 62
416 guez 30 lock_unan=.TRUE.
417 guez 62
418 guez 30 SELECT CASE(str)
419     CASE('gregorian')
420     calendar_used = 'gregorian'
421     un_an = 365.2425
422 guez 62 mon_len(:)=(/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
423 guez 30 CASE('standard')
424     calendar_used = 'gregorian'
425     un_an = 365.2425
426 guez 62 mon_len(:)=(/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
427 guez 30 CASE('proleptic_gregorian')
428     calendar_used = 'gregorian'
429     un_an = 365.2425
430 guez 62 mon_len(:)=(/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
431 guez 30 CASE('noleap')
432     calendar_used = 'noleap'
433     un_an = 365.0
434 guez 62 mon_len(:)=(/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
435 guez 30 CASE('365_day')
436     calendar_used = 'noleap'
437     un_an = 365.0
438 guez 62 mon_len(:)=(/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
439 guez 30 CASE('365d')
440     calendar_used = 'noleap'
441     un_an = 365.0
442 guez 62 mon_len(:)=(/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
443 guez 30 CASE('all_leap')
444     calendar_used = 'all_leap'
445     un_an = 366.0
446 guez 62 mon_len(:)=(/31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
447 guez 30 CASE('366_day')
448     calendar_used = 'all_leap'
449     un_an = 366.0
450 guez 62 mon_len(:)=(/31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
451 guez 30 CASE('366d')
452     calendar_used = 'all_leap'
453     un_an = 366.0
454 guez 62 mon_len(:)=(/31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
455 guez 30 CASE DEFAULT
456 guez 62 ipos = INDEX(str, 'd')
457 guez 30 IF (ipos == 4) THEN
458 guez 62 READ(str(1:3), '(I3)') leng
459     IF ( (MOD(leng, 12) == 0).AND.(leng > 1) ) THEN
460 guez 30 calendar_used = str
461     un_an = leng
462     mon_len(:) = leng
463     ELSE
464 guez 62 CALL histerr (3, 'ioconf_calendar', &
465 guez 30 & 'The length of the year as to be a modulo of 12', &
466     & 'so that it can be divided into 12 month of equal length', &
467     & str)
468     ENDIF
469     ELSE
470 guez 62 CALL histerr (3, 'ioconf_calendar', &
471     & 'Unrecognized input, please ceck the man pages.', str, ' ')
472 guez 30 ENDIF
473     END SELECT
474     ELSE
475 guez 62 WRITE(str10, '(f10.4)') un_an
476     CALL histerr (2, 'ioconf_calendar', &
477 guez 30 & 'The calendar was already used or configured. You are not', &
478     & 'allowed to change it again. '// &
479 guez 62 & 'The following length of year is used:', str10)
480 guez 30 ENDIF
481 guez 62
482 guez 30 END SUBROUTINE ioconf_calendar
483    
484     END MODULE calendar

  ViewVC Help
Powered by ViewVC 1.1.21