MODULE module_quilt_outbuf_ops ! !
! This module contains routines and data structures used by the I/O quilt 
! servers to assemble fields ("quilting") and write them to disk.  
!
!
INTEGER, PARAMETER :: tabsize = 1000 INTEGER :: num_entries TYPE outrec CHARACTER*80 :: VarName, DateStr, MemoryOrder, Stagger, DimNames(3) INTEGER :: ndim INTEGER, DIMENSION(3) :: DomainStart, DomainEnd INTEGER :: FieldType REAL, POINTER, DIMENSION(:,:,:) :: rptr INTEGER, POINTER, DIMENSION(:,:,:) :: iptr END TYPE outrec TYPE(outrec), DIMENSION(tabsize) :: outbuf_table CONTAINS SUBROUTINE init_outbuf ! !
! This routine re-initializes module data structures.  
!
!
IMPLICIT NONE INTEGER i DO i = 1, tabsize outbuf_table(i)%VarName = "" outbuf_table(i)%DateStr = "" outbuf_table(i)%MemoryOrder = "" outbuf_table(i)%Stagger = "" outbuf_table(i)%DimNames(1) = "" outbuf_table(i)%DimNames(2) = "" outbuf_table(i)%DimNames(3) = "" outbuf_table(i)%ndim = 0 NULLIFY( outbuf_table(i)%rptr ) NULLIFY( outbuf_table(i)%iptr ) ENDDO num_entries = 0 END SUBROUTINE init_outbuf SUBROUTINE write_outbuf ( DataHandle , io_form_arg ) ! !
! This routine writes all of the records stored in outbuf_table to the 
! file referenced by DataHandle using format specified by io_form_arg.  
! This routine calls the package-specific I/O routines to accomplish 
! the write.  
! It then re-initializes module data structures.  
!
!
USE module_state_description IMPLICIT NONE #include "wrf_io_flags.h" INTEGER , INTENT(IN) :: DataHandle, io_form_arg INTEGER :: ii,ds1,de1,ds2,de2,ds3,de3 INTEGER :: Comm, IOComm, DomainDesc ! dummy INTEGER :: Status CHARACTER*80 :: mess Comm = 0 ; IOComm = 0 ; DomainDesc = 0 DO ii = 1, num_entries WRITE(mess,*)'writing ', & TRIM(outbuf_table(ii)%DateStr)," ", & TRIM(outbuf_table(ii)%VarName)," ", & TRIM(outbuf_table(ii)%MemoryOrder) ds1 = outbuf_table(ii)%DomainStart(1) ; de1 = outbuf_table(ii)%DomainEnd(1) ds2 = outbuf_table(ii)%DomainStart(2) ; de2 = outbuf_table(ii)%DomainEnd(2) ds3 = outbuf_table(ii)%DomainStart(3) ; de3 = outbuf_table(ii)%DomainEnd(3) SELECT CASE ( io_form_arg ) #ifdef NETCDF CASE ( IO_NETCDF ) IF ( outbuf_table(ii)%FieldType .EQ. WRF_FLOAT ) THEN CALL ext_ncd_write_field ( DataHandle , & TRIM(outbuf_table(ii)%DateStr), & TRIM(outbuf_table(ii)%VarName), & outbuf_table(ii)%rptr(ds1:de1,ds2:de2,ds3:de3), & outbuf_table(ii)%FieldType, & !* Comm, IOComm, DomainDesc , & TRIM(outbuf_table(ii)%MemoryOrder), & TRIM(outbuf_table(ii)%Stagger), & !* outbuf_table(ii)%DimNames , & !* outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & Status ) ELSE IF ( outbuf_table(ii)%FieldType .EQ. WRF_INTEGER ) THEN CALL ext_ncd_write_field ( DataHandle , & TRIM(outbuf_table(ii)%DateStr), & TRIM(outbuf_table(ii)%VarName), & outbuf_table(ii)%iptr(ds1:de1,ds2:de2,ds3:de3), & outbuf_table(ii)%FieldType, & !* Comm, IOComm, DomainDesc , & TRIM(outbuf_table(ii)%MemoryOrder), & TRIM(outbuf_table(ii)%Stagger), & !* outbuf_table(ii)%DimNames , & !* outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & Status ) ENDIF #endif #ifdef YYY CASE ( IO_YYY ) IF ( outbuf_table(ii)%FieldType .EQ. WRF_FLOAT ) THEN CALL ext_yyy_write_field ( DataHandle , & TRIM(outbuf_table(ii)%DateStr), & TRIM(outbuf_table(ii)%VarName), & outbuf_table(ii)%rptr(ds1:de1,ds2:de2,ds3:de3), & outbuf_table(ii)%FieldType, & !* Comm, IOComm, DomainDesc , & TRIM(outbuf_table(ii)%MemoryOrder), & TRIM(outbuf_table(ii)%Stagger), & !* outbuf_table(ii)%DimNames , & !* outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & Status ) ELSE IF ( outbuf_table(ii)%FieldType .EQ. WRF_INTEGER ) THEN CALL ext_yyy_write_field ( DataHandle , & TRIM(outbuf_table(ii)%DateStr), & TRIM(outbuf_table(ii)%VarName), & outbuf_table(ii)%iptr(ds1:de1,ds2:de2,ds3:de3), & outbuf_table(ii)%FieldType, & !* Comm, IOComm, DomainDesc , & TRIM(outbuf_table(ii)%MemoryOrder), & TRIM(outbuf_table(ii)%Stagger), & !* outbuf_table(ii)%DimNames , & !* outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & Status ) ENDIF #endif #ifdef GRIB1 CASE ( IO_GRIB1 ) IF ( outbuf_table(ii)%FieldType .EQ. WRF_FLOAT ) THEN CALL ext_gr1_write_field ( DataHandle , & TRIM(outbuf_table(ii)%DateStr), & TRIM(outbuf_table(ii)%VarName), & outbuf_table(ii)%rptr(ds1:de1,ds2:de2,ds3:de3), & outbuf_table(ii)%FieldType, & !* Comm, IOComm, DomainDesc , & TRIM(outbuf_table(ii)%MemoryOrder), & TRIM(outbuf_table(ii)%Stagger), & !* outbuf_table(ii)%DimNames , & !* outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & Status ) ELSE IF ( outbuf_table(ii)%FieldType .EQ. WRF_INTEGER ) THEN CALL ext_gr1_write_field ( DataHandle , & TRIM(outbuf_table(ii)%DateStr), & TRIM(outbuf_table(ii)%VarName), & outbuf_table(ii)%iptr(ds1:de1,ds2:de2,ds3:de3), & outbuf_table(ii)%FieldType, & !* Comm, IOComm, DomainDesc , & TRIM(outbuf_table(ii)%MemoryOrder), & TRIM(outbuf_table(ii)%Stagger), & !* outbuf_table(ii)%DimNames , & !* outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & Status ) ENDIF #endif #ifdef GRIB2 CASE ( IO_GRIB2 ) IF ( outbuf_table(ii)%FieldType .EQ. WRF_FLOAT ) THEN CALL ext_gr2_write_field ( DataHandle , & TRIM(outbuf_table(ii)%DateStr), & TRIM(outbuf_table(ii)%VarName), & outbuf_table(ii)%rptr(ds1:de1,ds2:de2,ds3:de3), & outbuf_table(ii)%FieldType, & !* Comm, IOComm, DomainDesc , & TRIM(outbuf_table(ii)%MemoryOrder), & TRIM(outbuf_table(ii)%Stagger), & !* outbuf_table(ii)%DimNames , & !* outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & Status ) ELSE IF ( outbuf_table(ii)%FieldType .EQ. WRF_INTEGER ) THEN CALL ext_gr2_write_field ( DataHandle , & TRIM(outbuf_table(ii)%DateStr), & TRIM(outbuf_table(ii)%VarName), & outbuf_table(ii)%iptr(ds1:de1,ds2:de2,ds3:de3), & outbuf_table(ii)%FieldType, & !* Comm, IOComm, DomainDesc , & TRIM(outbuf_table(ii)%MemoryOrder), & TRIM(outbuf_table(ii)%Stagger), & !* outbuf_table(ii)%DimNames , & !* outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & Status ) ENDIF #endif #ifdef INTIO CASE ( IO_INTIO ) IF ( outbuf_table(ii)%FieldType .EQ. WRF_FLOAT ) THEN CALL ext_int_write_field ( DataHandle , & TRIM(outbuf_table(ii)%DateStr), & TRIM(outbuf_table(ii)%VarName), & outbuf_table(ii)%rptr(ds1:de1,ds2:de2,ds3:de3), & outbuf_table(ii)%FieldType, & !* Comm, IOComm, DomainDesc , & TRIM(outbuf_table(ii)%MemoryOrder), & TRIM(outbuf_table(ii)%Stagger), & !* outbuf_table(ii)%DimNames , & !* outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & Status ) ELSE IF ( outbuf_table(ii)%FieldType .EQ. WRF_INTEGER ) THEN CALL ext_int_write_field ( DataHandle , & TRIM(outbuf_table(ii)%DateStr), & TRIM(outbuf_table(ii)%VarName), & outbuf_table(ii)%iptr(ds1:de1,ds2:de2,ds3:de3), & outbuf_table(ii)%FieldType, & !* Comm, IOComm, DomainDesc , & TRIM(outbuf_table(ii)%MemoryOrder), & TRIM(outbuf_table(ii)%Stagger), & !* outbuf_table(ii)%DimNames , & !* outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & outbuf_table(ii)%DomainStart, & outbuf_table(ii)%DomainEnd, & Status ) ENDIF #endif CASE DEFAULT END SELECT IF ( ASSOCIATED( outbuf_table(ii)%rptr) ) DEALLOCATE(outbuf_table(ii)%rptr) IF ( ASSOCIATED( outbuf_table(ii)%iptr) ) DEALLOCATE(outbuf_table(ii)%iptr) NULLIFY( outbuf_table(ii)%rptr ) NULLIFY( outbuf_table(ii)%iptr ) ENDDO CALL init_outbuf END SUBROUTINE write_outbuf END MODULE module_quilt_outbuf_ops ! don't let other programs see the definition of this; type mismatches ! on inbuf will result; may want to make a module program at some point SUBROUTINE store_patch_in_outbuf( inbuf_r, inbuf_i, DateStr, VarName , FieldType, MemoryOrder, Stagger, DimNames, & DomainStart , DomainEnd , & MemoryStart , MemoryEnd , & PatchStart , PatchEnd ) ! !
! This routine does the "output quilting".  
!
! It stores a patch in the appropriate location in a domain-sized array 
! within an element of the outbuf_table data structure.  DateStr, VarName, and 
! MemoryOrder are used to uniquely identify which element of outbuf_table is 
! associated with this array.  If no element is associated, then this routine 
! first assigns an unused element and allocates space within that element for 
! the globally-sized array.  This routine also stores DateStr, VarName, 
! FieldType, MemoryOrder, Stagger, DimNames, DomainStart, and DomainEnd within 
! the same element of outbuf.  
!
!
USE module_quilt_outbuf_ops IMPLICIT NONE #include "wrf_io_flags.h" INTEGER , INTENT(IN) :: FieldType REAL , DIMENSION(*) , INTENT(IN) :: inbuf_r INTEGER , DIMENSION(*) , INTENT(IN) :: inbuf_i INTEGER , DIMENSION(3) , INTENT(IN) :: DomainStart , DomainEnd , MemoryStart , MemoryEnd , PatchStart , PatchEnd CHARACTER*(*) , INTENT(IN) :: DateStr , VarName, MemoryOrder , Stagger, DimNames(3) ! Local CHARACTER*120 mess INTEGER :: l,m,n,ii,jj LOGICAL :: found ! Find the VarName if it's in the buffer already ii = 1 found = .false. DO WHILE ( .NOT. found .AND. ii .LE. num_entries ) !TBH: need to test other attributes too! IF ( TRIM(VarName) .EQ. TRIM(outbuf_table(ii)%VarName) ) THEN IF ( TRIM(DateStr) .EQ. TRIM(outbuf_table(ii)%DateStr) ) THEN IF ( TRIM(MemoryOrder) .EQ. TRIM(outbuf_table(ii)%MemoryOrder) ) THEN found = .true. ELSE CALL wrf_error_fatal("store_patch_in_outbuf: memory order disagreement") ENDIF ELSE CALL wrf_error_fatal("store_patch_in_outbuf: multiple dates in buffer") ENDIF ELSE ii = ii + 1 ENDIF ENDDO IF ( .NOT. found ) THEN num_entries = num_entries + 1 IF ( FieldType .EQ. WRF_FLOAT ) THEN ALLOCATE( outbuf_table(num_entries)%rptr(DomainStart(1):DomainEnd(1), & DomainStart(2):DomainEnd(2),DomainStart(3):DomainEnd(3)) ) ELSE IF ( FieldType .EQ. WRF_INTEGER ) THEN ALLOCATE( outbuf_table(num_entries)%iptr(DomainStart(1):DomainEnd(1), & DomainStart(2):DomainEnd(2),DomainStart(3):DomainEnd(3)) ) ELSE write(mess,*)"store_patch_in_outbuf: unsupported type ", FieldType CALL wrf_error_fatal(mess) ENDIF outbuf_table(num_entries)%VarName = TRIM(VarName) outbuf_table(num_entries)%DateStr = TRIM(DateStr) outbuf_table(num_entries)%MemoryOrder = TRIM(MemoryOrder) outbuf_table(num_entries)%Stagger = TRIM(Stagger) outbuf_table(num_entries)%DimNames(1) = TRIM(DimNames(1)) outbuf_table(num_entries)%DimNames(2) = TRIM(DimNames(2)) outbuf_table(num_entries)%DimNames(3) = TRIM(DimNames(3)) outbuf_table(num_entries)%DomainStart = DomainStart outbuf_table(num_entries)%DomainEnd = DomainEnd outbuf_table(num_entries)%FieldType = FieldType ii = num_entries ENDIF jj = 1 IF ( FieldType .EQ. WRF_FLOAT ) THEN DO n = PatchStart(3),PatchEnd(3) DO m = PatchStart(2),PatchEnd(2) DO l = PatchStart(1),PatchEnd(1) outbuf_table(ii)%rptr(l,m,n) = inbuf_r(jj) jj = jj + 1 ENDDO ENDDO ENDDO ENDIF IF ( FieldType .EQ. WRF_INTEGER ) THEN DO n = PatchStart(3),PatchEnd(3) DO m = PatchStart(2),PatchEnd(2) DO l = PatchStart(1),PatchEnd(1) outbuf_table(ii)%iptr(l,m,n) = inbuf_i(jj) jj = jj + 1 ENDDO ENDDO ENDDO ENDIF RETURN END SUBROUTINE store_patch_in_outbuf !call add_to_bufsize_for_field( VarName, hdrbufsize+chunksize ) SUBROUTINE add_to_bufsize_for_field( VarName, Nbytes ) ! !
! This routine is a wrapper for C routine add_to_bufsize_for_field_c() that 
! is used to accumulate buffer sizes.  Buffer size Nbytes is added to the 
! curent buffer size for the buffer named VarName.  Any buffer space 
! associated with VarName is freed.  If a buffer named VarName does not exist, 
! a new one is assigned and its size is set to Nbytes.  
!
!
USE module_quilt_outbuf_ops IMPLICIT NONE CHARACTER*(*) , INTENT(IN) :: VarName INTEGER , INTENT(IN) :: Nbytes ! Local CHARACTER*120 mess INTEGER :: i, ierr INTEGER :: VarNameAsInts( 256 ) VarNameAsInts( 1 ) = len(trim(VarName)) DO i = 2, len(trim(VarName)) + 1 VarNameAsInts( i ) = ICHAR( VarName(i-1:i-1) ) ENDDO CALL add_to_bufsize_for_field_c ( VarNameAsInts, Nbytes ) RETURN END SUBROUTINE add_to_bufsize_for_field SUBROUTINE store_piece_of_field( inbuf, VarName, Nbytes ) ! !
! This routine is a wrapper for C routine store_piece_of_field_c() that 
! is used to store pieces of a field in an internal buffer.  Nbytes bytes of 
! buffer inbuf are appended to the end of the internal buffer named VarName.  
! An error occurs if either an internal buffer named VarName does not exist or 
! if there are fewer than Nbytes bytes left in the internal buffer.  
!
!
USE module_quilt_outbuf_ops IMPLICIT NONE INTEGER , INTENT(IN) :: Nbytes INTEGER , DIMENSION(*) , INTENT(IN) :: inbuf CHARACTER*(*) , INTENT(IN) :: VarName ! Local CHARACTER*120 mess INTEGER :: i, ierr INTEGER :: VarNameAsInts( 256 ) VarNameAsInts( 1 ) = len(trim(VarName)) DO i = 2, len(trim(VarName)) + 1 VarNameAsInts( i ) = ICHAR( VarName(i-1:i-1) ) ENDDO CALL store_piece_of_field_c ( inbuf, VarNameAsInts, Nbytes, ierr ) IF ( ierr .NE. 0 ) CALL wrf_error_fatal ( "store_piece_of_field" ) RETURN END SUBROUTINE store_piece_of_field SUBROUTINE retrieve_pieces_of_field( outbuf, VarName, obufsz, Nbytes_tot, lret ) ! !
! This routine is a wrapper for C routine retrieve_pieces_of_field_c() that 
! is used to extract the entire contents (i.e. all previously stored pieces of 
! fields) of the next internal buffer.  The name associated with this internal 
! buffer is returned in VarName.  The number of bytes read is returned in 
! Nbytes_tot.  Bytes are stored in outbuf whose size (in bytes) is obufsz.  
! If there are more than obufsz bytes left in the next internal buffer, then 
! only obufsz bytes are returned and the rest are discarded (probably an error 
! in the making!).  The internal buffer is then freed.  Flag lret is set to 
! .TRUE. iff there are more fields left to extract.  
!
!
USE module_quilt_outbuf_ops IMPLICIT NONE INTEGER , INTENT(IN) :: obufsz INTEGER , INTENT(OUT) :: Nbytes_tot INTEGER , DIMENSION(*) , INTENT(OUT) :: outbuf CHARACTER*(*) , INTENT(OUT) :: VarName LOGICAL :: lret ! true if more, false if not ! Local CHARACTER*120 mess INTEGER :: i, iret INTEGER :: VarNameAsInts( 256 ) CALL retrieve_pieces_of_field_c ( outbuf, VarNameAsInts, obufsz, Nbytes_tot, iret ) IF ( iret .NE. 0 ) THEN lret = .FALSE. ELSE lret = .TRUE. VarName = ' ' DO i = 2, VarNameAsInts(1) + 1 VarName(i-1:i-1) = CHAR(VarNameAsInts( i )) ENDDO ENDIF RETURN END SUBROUTINE retrieve_pieces_of_field