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

Contents of /trunk/IOIPSL/calendar.f

Parent Directory Parent Directory | Revision Log Revision Log


Revision 35 - (show annotations)
Tue Jun 8 15:37:21 2010 UTC (14 years ago) by guez
Original Path: trunk/libf/IOIPSL/calendar.f90
File size: 20427 byte(s)
Created intermediary variable for meridional wind in "calfis". Removed
unused variables.

Removed argument "firstcal" of "physiq", made it a local
variable. Removed unused argument "v" of "phytrac".

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

  ViewVC Help
Powered by ViewVC 1.1.21