6 ! Routines in this file are shared by io_grib1 and io_grib2
9 !*****************************************************************************
11 SUBROUTINE get_dims(MemoryOrder, Start, End, ndim, x_start, x_end, y_start, &
12 y_end, z_start, z_end)
14 CHARACTER (LEN=*) ,INTENT(IN) :: MemoryOrder
15 INTEGER ,INTENT(OUT) :: ndim,x_start,x_end,y_start
16 INTEGER ,INTENT(OUT) :: y_end,z_start,z_end
17 integer ,dimension(*),intent(in) :: Start, End
18 CHARACTER (LEN=1) :: char
20 CHARACTER (LEN=3) :: MemoryOrderLcl
30 ! Note: Need to add "char == 'S'" for boundary conditions
35 ! Fix for out-of-bounds references
37 do idx=1,len_trim(MemoryOrder)
38 MemoryOrderLcl(idx:idx) = MemoryOrder(idx:idx)
41 ! First, do the special boundary cases. These do not seem to
43 if ((MemoryOrderLcl(1:3) .eq. 'XSZ') &
44 .or. (MemoryOrderLcl(1:3) .eq. 'XEZ')) then
52 else if ((MemoryOrderLcl(1:3) .eq. 'YSZ') .or. &
53 (MemoryOrderLcl(1:3) .eq. 'YEZ')) then
61 else if ((MemoryOrderLcl(1:2) .eq. 'YS') .or. &
62 (MemoryOrderLcl(1:2) .eq. 'YE')) then
68 else if ((MemoryOrderLcl(1:2) .eq. 'XS') .or. &
69 (MemoryOrderLcl(1:2) .eq. 'XE')) then
75 else if ((MemoryOrderLcl(1:1) .eq. 'C') .or. (MemoryOrderLcl(1:1) .eq. 'c')) then
76 ! This is for "non-decomposed" fields
85 do idx=1,len_trim(MemoryOrderLcl)
86 char = MemoryOrderLcl(idx:idx)
87 if ((char == 'X') .or. (char == 'x')) then
91 else if ((char == 'Y') .or. (char == 'y')) then
95 else if ((char == 'Z') .or. (char == 'z')) then
99 else if (char == '0') then
100 ! Do nothing, this indicates field is a scalar.
103 call wrf_message('Invalid Dimension in get_dims: '//char)
108 END SUBROUTINE get_dims
110 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
112 SUBROUTINE geth_idts (ndate, odate, idts)
116 ! From 2 input mdates ('YYYY-MM-DD HH:MM:SS.ffff'),
117 ! compute the time difference.
119 ! on entry - ndate - the new hdate.
120 ! odate - the old hdate.
122 ! on exit - idts - the change in time in seconds.
124 CHARACTER (LEN=*) , INTENT(INOUT) :: ndate, odate
125 REAL , INTENT(OUT) :: idts
129 ! yrnew - indicates the year associated with "ndate"
130 ! yrold - indicates the year associated with "odate"
131 ! monew - indicates the month associated with "ndate"
132 ! moold - indicates the month associated with "odate"
133 ! dynew - indicates the day associated with "ndate"
134 ! dyold - indicates the day associated with "odate"
135 ! hrnew - indicates the hour associated with "ndate"
136 ! hrold - indicates the hour associated with "odate"
137 ! minew - indicates the minute associated with "ndate"
138 ! miold - indicates the minute associated with "odate"
139 ! scnew - indicates the second associated with "ndate"
140 ! scold - indicates the second associated with "odate"
142 ! mday - a list assigning the number of days in each month
144 CHARACTER (LEN=24) :: tdate
145 INTEGER :: olen, nlen
146 INTEGER :: yrnew, monew, dynew, hrnew, minew, scnew
147 INTEGER :: yrold, moold, dyold, hrold, miold, scold
148 INTEGER :: mday(12), i, newdys, olddys
149 LOGICAL :: npass, opass
151 CHARACTER (LEN=300) :: wrf_err_message
154 IF (odate.GT.ndate) THEN
163 ! Assign the number of days in a months
178 ! Break down old hdate into parts
185 READ(odate(1:4), '(I4)') yrold
186 READ(odate(6:7), '(I2)') moold
187 READ(odate(9:10), '(I2)') dyold
189 READ(odate(12:13),'(I2)') hrold
191 READ(odate(15:16),'(I2)') miold
193 READ(odate(18:19),'(I2)') scold
198 ! Break down new hdate into parts
205 READ(ndate(1:4), '(I4)') yrnew
206 READ(ndate(6:7), '(I2)') monew
207 READ(ndate(9:10), '(I2)') dynew
209 READ(ndate(12:13),'(I2)') hrnew
211 READ(ndate(15:16),'(I2)') minew
213 READ(ndate(18:19),'(I2)') scnew
218 ! Check that the dates make sense.
223 ! Check that the month of NDATE makes sense.
225 IF ((monew.GT.12).or.(monew.LT.1)) THEN
226 PRINT*, 'GETH_IDTS: Month of NDATE = ', monew
230 ! Check that the month of ODATE makes sense.
232 IF ((moold.GT.12).or.(moold.LT.1)) THEN
233 PRINT*, 'GETH_IDTS: Month of ODATE = ', moold
237 ! Check that the day of NDATE makes sense.
240 ! ...... For all months but February
241 IF ((dynew.GT.mday(monew)).or.(dynew.LT.1)) THEN
242 PRINT*, 'GETH_IDTS: Day of NDATE = ', dynew
245 ELSE IF (monew.eq.2) THEN
246 ! ...... For February
247 IF ((dynew.GT.ndfeb(yrnew)).OR.(dynew.LT.1)) THEN
248 PRINT*, 'GETH_IDTS: Day of NDATE = ', dynew
253 ! Check that the day of ODATE makes sense.
256 ! ...... For all months but February
257 IF ((dyold.GT.mday(moold)).or.(dyold.LT.1)) THEN
258 PRINT*, 'GETH_IDTS: Day of ODATE = ', dyold
261 ELSE IF (moold.eq.2) THEN
262 ! ....... For February
263 IF ((dyold.GT.ndfeb(yrold)).or.(dyold.LT.1)) THEN
264 PRINT*, 'GETH_IDTS: Day of ODATE = ', dyold
269 ! Check that the hour of NDATE makes sense.
271 IF ((hrnew.GT.23).or.(hrnew.LT.0)) THEN
272 PRINT*, 'GETH_IDTS: Hour of NDATE = ', hrnew
276 ! Check that the hour of ODATE makes sense.
278 IF ((hrold.GT.23).or.(hrold.LT.0)) THEN
279 PRINT*, 'GETH_IDTS: Hour of ODATE = ', hrold
283 ! Check that the minute of NDATE makes sense.
285 IF ((minew.GT.59).or.(minew.LT.0)) THEN
286 PRINT*, 'GETH_IDTS: Minute of NDATE = ', minew
290 ! Check that the minute of ODATE makes sense.
292 IF ((miold.GT.59).or.(miold.LT.0)) THEN
293 PRINT*, 'GETH_IDTS: Minute of ODATE = ', miold
297 ! Check that the second of NDATE makes sense.
299 IF ((scnew.GT.59).or.(scnew.LT.0)) THEN
300 PRINT*, 'GETH_IDTS: SECOND of NDATE = ', scnew
304 ! Check that the second of ODATE makes sense.
306 IF ((scold.GT.59).or.(scold.LT.0)) THEN
307 PRINT*, 'GETH_IDTS: Second of ODATE = ', scold
311 IF (.not. npass) THEN
312 WRITE( wrf_err_message , * ) &
313 'module_date_time: geth_idts: Bad NDATE: ', ndate(1:nlen)
314 CALL wrf_error_fatal ( TRIM ( wrf_err_message ) )
317 IF (.not. opass) THEN
318 WRITE( wrf_err_message , * ) &
319 'module_date_time: geth_idts: Bad ODATE: ', odate(1:olen)
320 CALL wrf_error_fatal ( TRIM ( wrf_err_message ) )
323 ! Date Checks are completed. Continue.
325 ! Compute number of days from 1 January ODATE, 00:00:00 until ndate
326 ! Compute number of hours from 1 January ODATE, 00:00:00 until ndate
327 ! Compute number of minutes from 1 January ODATE, 00:00:00 until ndate
330 DO i = yrold, yrnew - 1
331 newdys = newdys + (365 + (ndfeb(i)-28))
334 IF (monew .GT. 1) THEN
335 mday(2) = ndfeb(yrnew)
337 newdys = newdys + mday(i)
342 newdys = newdys + dynew-1
344 ! Compute number of hours from 1 January ODATE, 00:00:00 until odate
345 ! Compute number of minutes from 1 January ODATE, 00:00:00 until odate
349 IF (moold .GT. 1) THEN
350 mday(2) = ndfeb(yrold)
352 olddys = olddys + mday(i)
357 olddys = olddys + dyold-1
359 ! Determine the time difference in seconds
361 idts = (newdys - olddys) * 86400
362 idts = idts + (hrnew - hrold) * 3600
363 idts = idts + (minew - miold) * 60
364 idts = idts + (scnew - scold)
366 IF (isign .eq. -1) THEN
373 END SUBROUTINE geth_idts
375 !*****************************************************************************
377 SUBROUTINE get_vert_stag(VarName,Stagger,vert_stag)
379 character (LEN=*) :: VarName
380 character (LEN=*) :: Stagger
383 if ((index(Stagger,'Z') > 0) .or. (VarName .eq. 'DNW') &
384 .or.(VarName .eq. 'RDNW')) then
391 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
393 FUNCTION ndfeb ( year ) RESULT (num_days)
395 ! Compute the number of days in February for the given year
402 num_days = 28 ! By default, February has 28 days ...
403 IF (MOD(year,4).eq.0) THEN
404 num_days = 29 ! But every four years, it has 29 days ...
405 IF (MOD(year,100).eq.0) THEN
406 num_days = 28 ! Except every 100 years, when it has 28 days ...
407 IF (MOD(year,400).eq.0) THEN
408 num_days = 29 ! Except every 400 years, when it has 29 days.
415 !*****************************************************************************
417 SUBROUTINE get_dimvals(MemoryOrder,x,y,z,dims)
420 CHARACTER (LEN=*) ,INTENT(IN) :: MemoryOrder
421 INTEGER ,INTENT(IN) :: x,y,z
422 INTEGER, DIMENSION(*),INTENT(OUT) :: dims
424 CHARACTER (LEN=1) :: char
425 CHARACTER (LEN=3) :: MemoryOrderLcl
431 ! Fix for out-of-bounds references
433 do idx=1,len_trim(MemoryOrder)
434 MemoryOrderLcl(idx:idx) = MemoryOrder(idx:idx)
438 ! Note: Need to add "char == 'S'" for boundary conditions
441 if ((MemoryOrderLcl(1:3) .eq. 'XSZ') &
442 .or. (MemoryOrderLcl(1:3) .eq. 'XEZ')) then
446 else if ((MemoryOrderLcl(1:3) .eq. 'YSZ') .or. &
447 (MemoryOrderLcl(1:3) .eq. 'YEZ')) then
451 else if ((MemoryOrderLcl(1:2) .eq. 'YS') .or. &
452 (MemoryOrderLcl(1:2) .eq. 'YE')) then
456 else if ((MemoryOrderLcl(1:2) .eq. 'XS') .or. &
457 (MemoryOrderLcl(1:2) .eq. 'XE')) then
461 else if ((MemoryOrderLcl(1:1) .eq. 'C') .or. &
462 (MemoryOrderLcl(1:1) .eq. 'c')) then
463 ! Non-decomposed field
468 do idx=1,len_trim(MemoryOrderLcl)
469 char = MemoryOrderLcl(idx:idx)
470 if ((char == 'X') .or. (char == 'x')) then
472 else if ((char == 'Y') .or. (char == 'y')) then
474 else if ((char == 'Z') .or. (char == 'z')) then
476 else if (char == '0') then
477 ! This is a scalar, do nothing.
479 call wrf_message ('Invalid Dimension in get_dimvals: '//char)
484 END SUBROUTINE get_dimvals
486 !*****************************************************************************
488 SUBROUTINE get_soil_layers(VarName,soil_layers)
490 character (LEN=*) :: VarName
491 logical :: soil_layers
493 if ((VarName .eq. 'ZS') .or. (VarName .eq. 'DZS') &
494 .or.(VarName .eq. 'TSLB') .or. (VarName .eq. 'SMOIS') &
495 .or. (VarName .eq. 'SH2O') .or. (VarName .eq. 'KEEPFR3DFLAG') &
496 .or. (VarName .eq. 'SMFR3D')) then
499 soil_layers = .false.
503 !*****************************************************************************
505 SUBROUTINE Transpose_grib(MemoryOrder, di, FieldType, Field, &
506 Start1, End1, Start2, End2, Start3, End3, data, zidx, numrows, numcols)
510 #include "wrf_io_flags.h"
512 CHARACTER (LEN=*),INTENT(IN) :: MemoryOrder
513 INTEGER ,INTENT(IN) :: Start1,End1,Start2,End2,Start3,End3
514 INTEGER ,INTENT(IN) :: di
515 integer ,intent(inout) :: &
516 Field(di,Start1:End1,Start2:End2,Start3:End3)
517 INTEGER ,intent(in) :: FieldType
518 real ,intent(in) :: data(*)
519 INTEGER ,INTENT(IN) :: zidx, numcols, numrows
520 INTEGER, DIMENSION(3) :: dims
522 LOGICAL :: logicaltype
523 CHARACTER (LEN=1000) :: msg
525 if ((FieldType == WRF_REAL) .or. (FieldType == WRF_DOUBLE)) then
528 call get_dimvals(MemoryOrder,col,row,zidx,dims)
529 Field(1:di,dims(1),dims(2),dims(3)) = &
530 TRANSFER(data((row-1)*numcols+col),Field,1)
533 else if (FieldType == WRF_INTEGER) then
536 call get_dimvals(MemoryOrder,col,row,zidx,dims)
537 Field(1:di,dims(1),dims(2),dims(3)) = data((row-1)*numcols+col)
541 write (msg,*)'Reading of type ',FieldType,'from grib data not supported'
542 call wrf_message(msg)
546 ! This following seciton is for the logical type. This caused some problems
547 ! on certain platforms.
549 ! else if (FieldType == WRF_LOGICAL) then
552 ! call get_dimvals(MemoryOrder,col,row,zidx,dims)
553 ! Field(1:di,dims(1),dims(2),dims(3)) = &
554 ! TRANSFER(data((row-1)*numcols+col),logicaltype,1)
561 !*****************************************************************************
563 SUBROUTINE Transpose1D_grib(MemoryOrder, di, FieldType, Field, &
564 Start1, End1, Start2, End2, Start3, End3, data, nelems)
568 #include "wrf_io_flags.h"
570 CHARACTER (LEN=*),INTENT(IN) :: MemoryOrder
571 INTEGER ,INTENT(IN) :: Start1,End1,Start2,End2,Start3,End3
572 INTEGER ,INTENT(IN) :: di
573 integer ,intent(inout) :: &
574 Field(di,Start1:End1,Start2:End2,Start3:End3)
575 INTEGER ,intent(in) :: FieldType
576 real ,intent(in) :: data(*)
577 LOGICAL :: logicaltype
578 CHARACTER (LEN=1000) :: msg
579 integer :: elemnum,nelems
581 if ((FieldType == WRF_REAL) .or. (FieldType == WRF_DOUBLE)) then
583 Field(1:di,elemnum,1,1) = TRANSFER(data(elemnum),Field,1)
585 else if (FieldType == WRF_INTEGER) then
587 Field(1:di,elemnum,1,1) = TRANSFER(data(elemnum),Field,1)
590 write (msg,*)'Reading of type ',FieldType,'from grib1 data not supported'
591 call wrf_message(msg)
595 ! This following seciton is for the logical type. This caused some problems
596 ! on certain platforms.
598 ! else if (FieldType == WRF_LOGICAL) then
601 ! call get_dimvals(MemoryOrder,col,row,zidx,dims)
602 ! Field(1:di,dims(1),dims(2),dims(3)) = &
603 ! TRANSFER(data((row-1)*numcols+col),logicaltype,1)
608 end SUBROUTINE Transpose1D_grib
610 !*****************************************************************************
612 ! Takes a starting date (startTime) in WRF format (yyyy-mm-dd_hh:mm:ss),
613 ! adds an input number of seconds to the time, and outputs a new date
614 ! (endTime) in WRF format.
616 !*****************************************************************************
618 subroutine advance_wrf_time(startTime, addsecs, endTime)
621 integer , intent(in) :: addsecs
622 character (len=*), intent(in) :: startTime
623 character (len=*), intent(out) :: endTime
624 integer :: syear,smonth,sday,shour,smin,ssec
625 integer :: days_in_month(12)
627 read(startTime,'(I4.4,1X,I2.2,1X,I2.2,1X,I2.2,1X,I2.2,1X,I2.2)') &
628 syear,smonth,sday,shour,smin,ssec
630 ssec = ssec + addsecs
632 do while (ssec .ge. 60)
637 do while (smin .ge. 60)
642 do while (shour .ge. 24)
648 days_in_month(1) = 31
649 if (((mod(syear,4) .eq. 0) .and. (mod(syear,100) .ne. 0)) &
650 .or. (mod(syear,400) .eq. 0)) then
651 days_in_month(2) = 29
653 days_in_month(2) = 28
655 days_in_month(3) = 31
656 days_in_month(4) = 30
657 days_in_month(5) = 31
658 days_in_month(6) = 30
659 days_in_month(7) = 31
660 days_in_month(8) = 31
661 days_in_month(9) = 30
662 days_in_month(10) = 31
663 days_in_month(11) = 30
664 days_in_month(12) = 31
667 do while (sday .gt. days_in_month(smonth))
668 sday = sday - days_in_month(smonth)
670 if (smonth .gt. 12) then
677 write(endTime,'(I4.4,A,I2.2,A,I2.2,A,I2.2,A,I2.2,A,I2.2)') &
678 syear,'-',smonth,'-',sday,'_',shour,':',smin,':',ssec