/[lmdze]/trunk/libf/IOIPSL/calendar.f90
ViewVC logotype

Contents of /trunk/libf/IOIPSL/calendar.f90

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations)
Tue Apr 6 17:52:58 2010 UTC (14 years, 2 months ago) by guez
File size: 20425 byte(s)
Split "stringop.f90" into single-procedure files. Gathered files in directory
"IOIPSL/Stringop".

Split "flincom.f90" into "flincom.f90" and "flinget.f90". Removed
unused procedures from module "flincom". Removed unused argument
"filename" of procedure "flinopen_nozoom".

Removed unused files.

Split "grid_change.f90" into "grid_change.f90" and
"gr_phy_write_3d.f90".

Removed unused procedures from modules "calendar", "ioipslmpp",
"grid_atob", "gath_cpl" and "getincom". Removed unused procedures in
files "ppm3d.f" and "thermcell.f".

Split "mathelp.f90" into "mathelp.f90" and "mathop.f90".

Removed unused variable "dpres" of module "comvert".

Use argument "itau" instead of local variables "iadvtr" and "first" to
control algorithm in procedure "fluxstokenc".

Removed unused arguments of procedure "integrd".

Removed useless computations at the end of procedure "leapfrog".

Merged common block "matrfil" into module "parafilt".

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