!* The HDF5 WRF IO module was written by the the HDF Group at NCSA, the     *
!* National Center for Supercomputing Applications.                         *
!*     HDF Group                                                            *
!*     National Center for Supercomputing Applications                      *
!*     University of Illinois at Urbana-Champaign                           *
!*     605 E. Springfield, Champaign IL 61820                               *
!*     http://hdf.ncsa.uiuc.edu/                                            *
!*                                                                          *
!* Copyright 2004 by the Board of Trustees, University of Illinois,         *
!*                                                                          *
!* Redistribution or use of this IO module, with or without modification,   *
!* is permitted for any purpose, including commercial  purposes.            *
!*                                                                          *
!* This software is an unsupported prototype.  Use at your own risk.        *
!*     http://hdf.ncsa.uiuc.edu/apps/WRF-ROMS                               *
!*                                                                          *
!* This work was funded by the MEAD expedition at the National Center       *
!* for Supercomputing Applications, NCSA.  For more information see:        *
!*     http://www.ncsa.uiuc.edu/expeditions/MEAD                            *
!*                                                                          *
!*                                                                          *
!****************************************************************************/
!
!##################################################################
!######                                                      ######
!######     This file was modified specifically for          ######
!######                 WRF boundary file                    ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!
!-----------------------------------------------------------------------
!
!  Changes:
!
!     1. HDF5IOWRITE_bdy write dataset independently based on a flag
!        - IOFlag, which is passed in from ext_phdf5_write_bdy.
!     2. ext_phdf5_write_bdy is the same as ext_phdf5_write_field except
!        that it passes an extra LOGICAL dummy parameter, IOFlag.
!     3. Set no_par = .FALSE. i.e. does not support compact data storage
!       
!-----------------------------------------------------------------------


subroutine HDF5IOWRITE_bdy(DataHandle,Comm,DateStr,Length,DomainStart,DomainEnd & 2,9
     ,PatchStart,PatchEnd,MemoryOrder &
     ,WrfDType,FieldType,groupID,TimeIndex &
     ,DimRank ,DatasetName,XField,IOFlag,Status)

  use wrf_phdf5_data
  use ext_phdf5_support_routines
  use HDF5
  implicit none
  include 'mpif.h'
  include 'wrf_status_codes.h'

  integer                     ,intent(in)     :: DataHandle
  integer                     ,intent(inout)  :: Comm
  character*(*)               ,intent(in)     :: DateStr
  integer,dimension(NVarDims) ,intent(in)     :: Length

  integer,dimension(NVarDims) ,intent(in)     :: DomainStart
  integer,dimension(NVarDims) ,intent(in)     :: DomainEnd
  integer,dimension(NVarDims) ,intent(in)     :: PatchStart
  integer,dimension(NVarDims) ,intent(in)     :: PatchEnd

  character*(*)               ,intent(in)     :: MemoryOrder

  integer                     ,intent(in)     :: WrfDType
  integer(hid_t)              ,intent(in)     :: FieldType
  integer(hid_t)              ,intent(in)     :: groupID
  integer                     ,intent(in)     :: TimeIndex

  integer,dimension(*)        ,intent(in)     :: DimRank
  character (*)               ,intent(in)     :: DatasetName
  integer,dimension(*)        ,intent(inout)  :: XField
  LOGICAL,                     INTENT(IN)     :: IOFlag
  integer                     ,intent(out)    :: Status

  integer(hid_t)                              :: dset_id
  integer                                     :: NDim
  integer,dimension(NVarDims)                 :: VStart
  integer,dimension(NVarDims)                 :: VCount
  character (3)                               :: Mem0
  character (3)                               :: UCMem0
  type(wrf_phdf5_data_handle) ,pointer         :: DH

  ! attribute defination
  integer(hid_t)                              :: dimaspace_id  ! DimRank dataspace id
  integer(hid_t)                              :: dimattr_id    ! DimRank attribute id
  integer(hsize_t) ,dimension(1)              :: dim_space
  INTEGER(HID_T)                              :: dspace_id     ! Raw Data memory Dataspace id
  INTEGER(HID_T)                              :: fspace_id     ! Raw Data file Dataspace id
  INTEGER(HID_T)                              :: crp_list      ! chunk  identifier
  integer(hid_t)                              :: h5_atypeid    ! for fieldtype,memorder attribute
  integer(hid_t)                              :: h5_aspaceid   ! for fieldtype,memorder  
  integer(hid_t)                              :: h5_attrid     ! for fieldtype,memorder
  integer(hsize_t), dimension(7)              :: adata_dims
  integer                                     :: routine_atype


  integer,          dimension(:),allocatable  :: dimrank_data

  INTEGER(HSIZE_T), dimension(:),allocatable  :: dims  ! Dataset dimensions
  INTEGER(HSIZE_T), dimension(:),allocatable  :: sizes ! Dataset dimensions
  INTEGER(HSIZE_T), dimension(:),allocatable  :: chunk_dims 
  INTEGER(HSIZE_T), dimension(:),allocatable  :: hdf5_maxdims
  INTEGER(HSIZE_T), dimension(:),allocatable  :: offset 
  INTEGER(HSIZE_T), dimension(:),allocatable  :: count  
  INTEGER(HSIZE_T), DIMENSION(7)              :: dimsfi
  integer                                     :: hdf5err
  integer                                     :: i,j
  integer(size_t)                             :: dsetsize

  ! FOR PARALLEL IO
  integer(hid_t)                              :: xfer_list
  logical                                     :: no_par

!-------- uncomment for debug ----------------
!
!  INTEGER :: myproc
!
!  CALL mpi_comm_rank( Comm, myproc, Status )
!
!-------- uncomment for debug ----------------

  ! get the handle 
  call GetDH(DataHandle,DH,Status)
  if(Status /= WRF_NO_ERR) then
     write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
     call wrf_debug ( WARN , msg) 
     return
  endif

  ! get the rank of the dimension
  call GetDim(MemoryOrder,NDim,Status)
  if(Status /= WRF_NO_ERR) then
     write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
     call wrf_debug ( WARN , msg) 
     return
  endif

  ! If patch is equal to domain, the parallel is not necessary, sequential is used.
  ! In this version, we haven't implemented this yet.
  ! We use no_par to check whether we can use compact data storage.
!
! CAPS begin:
!
!  no_par = .TRUE.
!  do i = 1,NDim
!     if((PatchStart(i)/=DomainStart(i)).or.(PatchEnd(i)/=DomainEnd(i))) then
!        no_par = .FALSE.
!        exit
!     endif
!  enddo
!
!-----------------------------------------------------------------------
!
!  This is not a correct criteria. anyway, we do not use H5D_COMPACT 
!  data storage for bounary data.
!
!-----------------------------------------------------------------------

  no_par = .FALSE.
!
! CAPS end
!

  ! change the different Memory Order to XYZ for patch and domain
  if(MemoryOrder.NE.'0') then
     call ExtOrder(MemoryOrder,PatchStart,Status)
     call ExtOrder(MemoryOrder,PatchEnd,Status)
     call ExtOrder(MemoryOrder,DomainStart,Status)
     call ExtOrder(MemoryOrder,DomainEnd,Status)
  endif

  ! allocating memory for dynamic arrays; 
  ! since the time step is always 1, we may ignore the fourth
  ! dimension time; now keep it to make it consistent with sequential version
  allocate(dims(NDim+1))
  allocate(count(NDim+1))
  allocate(offset(NDim+1))
  allocate(sizes(NDim+1))


  ! arrange offset, count for each hyperslab
  dims(1:NDim)   = DomainEnd(1:NDim) - DomainStart(1:NDim) + 1
  dims(NDim+1)   = 1

  count(NDim+1)  = 1
  count(1:NDim)  = Length(1:NDim)

  offset(NDim+1) = 0
  offset(1:NDim) = PatchStart(1:NDim) - 1

  ! allocate the dataspace to write hyperslab data

  dimsfi = 0
  do i = 1, NDim + 1
     dimsfi(i) = count(i)
  enddo

  ! create the memory space id
  call h5screate_simple_f(NDim+1,count,dspace_id,hdf5err,count)
  if(hdf5err.lt.0) then
     Status =  WRF_HDF5_ERR_DATASPACE
     write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
     call wrf_debug ( WARN , msg) 
     deallocate(dims)
     deallocate(count)
     deallocate(offset)
     deallocate(sizes)
     return
  endif


  ! create file space
  call h5screate_simple_f(NDim+1,dims,fspace_id,hdf5err,dims)
  if(hdf5err.lt.0) then        
     Status =  WRF_HDF5_ERR_DATASPACE
     write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
     call wrf_debug ( WARN , msg) 
     deallocate(dims)
     deallocate(count)
     deallocate(offset)
     deallocate(sizes)
     return
  endif

  ! compact storage when the patch is equal to the whole domain
  ! calculate the non-decomposed dataset size

  call h5tget_size_f(FieldType,dsetsize,hdf5err)
  if(hdf5err.lt.0) then
     Status = WRF_HDF5_ERR_DATATYPE
     write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
     call wrf_debug ( WARN , msg) 
     deallocate(dims)
     deallocate(count)
     deallocate(offset)
     deallocate(sizes)
     return
  endif

  do i =1,NDim
     dsetsize = dsetsize*dims(i)
  enddo
  if(no_par.and.(dsetsize.le.CompDsetSize)) then
     call h5pcreate_f(H5P_DATASET_CREATE_F,crp_list,hdf5err)
     if(hdf5err.lt.0) then
        Status =  WRF_HDF5_ERR_PROPERTY_LIST
        write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
        call wrf_debug ( WARN , msg) 
        deallocate(dims)
        deallocate(count)
        deallocate(offset)
        deallocate(sizes)
        return
     endif
     call h5pset_layout_f(crp_list,0,hdf5err)
     if(hdf5err.lt.0) then
        Status =  WRF_HDF5_ERR_PROPERTY_LIST
        write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
        call wrf_debug ( WARN , msg) 
        deallocate(dims)
        deallocate(count)
        deallocate(offset)
        deallocate(sizes)
        return
     endif
     call h5dcreate_f(DH%TgroupIDs(TimeIndex),DatasetName,FieldType,fspace_id,dset_id,&
          hdf5err,crp_list)
     call h5pclose_f(crp_list,hdf5err)
  else
     call h5dcreate_f(DH%TgroupIDs(TimeIndex),DatasetName,FieldType,fspace_id,dset_id,hdf5err)
  endif

  if(hdf5err.lt.0) then
     Status =  WRF_HDF5_ERR_DATASET_CREATE 
     write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
     call wrf_debug ( WARN , msg) 
     deallocate(dims)
     deallocate(count)
     deallocate(offset)
     deallocate(sizes)
     return
  endif

  ! select the correct hyperslab for file space id
  CALL h5sselect_hyperslab_f(fspace_id, H5S_SELECT_SET_F, offset, count &
       ,hdf5err) 
  if(hdf5err.lt.0) then
     Status =  WRF_HDF5_ERR_DATASET_GENERAL
     write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
     call wrf_debug ( WARN , msg) 
     deallocate(dims)
     deallocate(count)
     deallocate(offset)
     deallocate(sizes)
     return
  endif

  ! Create property list for collective dataset write
  CALL h5pcreate_f(H5P_DATASET_XFER_F, xfer_list, hdf5err)
  if(hdf5err.lt.0) then
     Status =  WRF_HDF5_ERR_PROPERTY_LIST
     write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
     call wrf_debug ( WARN , msg) 
     deallocate(dims)
     deallocate(count)
     deallocate(offset)
     deallocate(sizes)
     return
  endif

  CALL h5pset_dxpl_mpio_f(xfer_list, H5FD_MPIO_COLLECTIVE_F&
       ,hdf5err)
  if(hdf5err.lt.0) then
     Status =  WRF_HDF5_ERR_PROPERTY_LIST
     write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
     call wrf_debug ( WARN , msg) 
     deallocate(dims)
     deallocate(count)
     deallocate(offset)
     deallocate(sizes)
     return
  endif

  ! write the data in memory space to file space
!-----------------------------------------------------------------------
!
! CAPS Begin: 
!   Write dataset independently instead of colletively
!
!-----------------------------------------------------------------------

!  CALL h5dwrite_f(dset_id,FieldType,XField,dimsfi,hdf5err,&
!       mem_space_id =dspace_id,file_space_id =fspace_id, &
!       xfer_prp = xfer_list)

  IF (IOFlag) THEN

!write(0,*) ':: ',myproc,'  is writing ',datasetname

    CALL h5dwrite_f(dset_id,FieldType,XField,dimsfi,hdf5err,&
       mem_space_id =dspace_id,file_space_id =fspace_id)
    if(hdf5err.lt.0) then
       Status =  WRF_HDF5_ERR_DATASET_WRITE
       write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
       call wrf_debug ( WARN , msg) 
       deallocate(dims)
       deallocate(count)
       deallocate(offset)
       deallocate(sizes)
       return
    endif

  END IF
!-----------------------------------------------------------------------
!
! CAPS End: 
!
!-----------------------------------------------------------------------

  CALL h5pclose_f(xfer_list,hdf5err)
  if(hdf5err.lt.0) then
     Status =  WRF_HDF5_ERR_PROPERTY_LIST
     write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
     call wrf_debug ( WARN , msg) 
     deallocate(dims)
     deallocate(count)
     deallocate(offset)
     deallocate(sizes)
     return
  endif

  if(TimeIndex == 1) then
     do i =1, MaxVars
        if(DH%dsetids(i) == -1) then
           DH%dsetids(i) = dset_id
           DH%VarNames(i) = DataSetName
           exit
        endif
     enddo
     ! Only writing attributes when TimeIndex ==1
     call write_hdf5_attributes(DataHandle,MemoryOrder,WrfDType,DimRank,&
          NDim,dset_id,Status)
  endif

  call h5sclose_f(fspace_id,hdf5err)
  call h5sclose_f(dspace_id,hdf5err)
  if(TimeIndex /= 1) then
     call h5dclose_f(dset_id,hdf5err)  
  endif
  if(hdf5err.lt.0) then
     Status =  WRF_HDF5_ERR_DATASPACE  
     write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
     call wrf_debug ( WARN , msg) 
     deallocate(dims)
     deallocate(count)
     deallocate(offset)
     deallocate(sizes)
     return
  endif
  Status = WRF_NO_ERR
  return
end subroutine  HDF5IOWRITE_bdy

! The real routine to write HDF5 boundary file

subroutine ext_phdf5_write_bdy(DataHandle,DateStr,Var,Field,FieldType,& 1,15
     Comm,IOComm,DomainDesc,MemoryOrder,  &
     Stagger,DimNames,DomainStart,DomainEnd,&
     MemoryStart,MemoryEnd,PatchStart,PatchEnd,&
     IOFlag,Status)

  use wrf_phdf5_data
  use ext_phdf5_support_routines
  USE HDF5 ! This module contains all necessary modules 
  implicit none
  include 'wrf_status_codes.h'

  integer                       ,intent(in)      :: DataHandle
  character*(*)                 ,intent(in)      :: DateStr
  character*(*)                 ,intent(in)      :: Var
  integer                       ,intent(inout)   :: Field(*)
  integer                       ,intent(in)      :: FieldType
  integer                       ,intent(inout)   :: Comm
  integer                       ,intent(inout)   :: IOComm
  integer                       ,intent(in)      :: DomainDesc
  character*(*)                 ,intent(in)      :: MemoryOrder
  character*(*)                 ,intent(in)      :: Stagger   ! Dummy for now
  character*(*) , dimension (*) ,intent(in)      :: DimNames
  integer ,dimension(*)         ,intent(in)      :: DomainStart, DomainEnd
  integer ,dimension(*)         ,intent(in)      :: MemoryStart, MemoryEnd
  integer ,dimension(*)         ,intent(in)      :: PatchStart,  PatchEnd
  LOGICAL,                       INTENT(IN)      :: IOFlag
  integer                       ,intent(out)     :: Status

  type(wrf_phdf5_data_handle)    ,pointer        :: DH
  integer(hid_t)                                 :: GroupID
  integer                                        :: NDim
  character (VarNameLen)                         :: VarName
  character (3)                                  :: MemO
  character (3)                                  :: UCMemO
  integer(hid_t)                                 :: DsetID
  integer      ,dimension(NVarDims)              :: Length
  integer      ,dimension(NVarDims)              :: DomLength
  integer      ,dimension(NVarDims+1)            :: DimRank
  character(256),dimension(NVarDims)              :: RODimNames
  integer      ,dimension(NVarDims)              :: StoredStart
  integer      ,dimension(:,:,:,:),allocatable   :: XField
  integer      ,dimension(:,:,:,:),allocatable   :: BUFFER! for logical field
  integer                                        :: stat
  integer                                        :: NVar
  integer                                        :: i,j,k,m,dim_flag
  integer                                        :: i1,i2,j1,j2,k1,k2
  integer                                        :: x1,x2,y1,y2,z1,z2
  integer                                        :: l1,l2,m1,m2,n1,n2
  integer(hid_t)                                 :: XType
  integer                                        :: di
  character (256)                                 :: NullName
  integer                                        :: TimeIndex
  integer ,dimension(NVarDims+1)                 :: temprank
  logical                                        :: NotFound


  NullName = char(0)
  dim_flag = 0

  call GetDH(DataHandle,DH,Status)
  if(Status /= WRF_NO_ERR) then
     write(msg,*) 'Warning Status = ',Status,' in ',__FILE__,', line', __LINE__
     call wrf_debug ( WARN , msg)
     return
  endif

  ! Examine here, Nov. 7th, 2003
  if(DH%FileStatus == WRF_FILE_OPENED_AND_COMMITTED) then 

     ! obtain group id and initialize the rank of dimensional attributes
     GroupID = DH%GroupID
     DimRank = -1

     ! get the rank of the dimension based on MemoryOrder string(cleaver from NetCDF)
     call GetDim(MemoryOrder,NDim,Status)
     if(Status /= WRF_NO_ERR) then
        write(msg,*) 'Warning BAD MEMORY ORDER in ',__FILE__,', line', __LINE__
        call wrf_debug ( WARN , msg)
        return
     endif

     ! check whether the DateStr is the correct length
     call DateCheck(DateStr,Status)
     if(Status /= WRF_NO_ERR) then
        write(msg,*) 'Warning DATE STRING ERROR in ',__FILE__,', line', __LINE__ 
        call wrf_debug ( WARN , msg)
        return
     endif

     ! get the dataset name and dimensional information of the data
     VarName           = Var
     Length(1:NDim)    = PatchEnd(1:NDim) - PatchStart(1:NDim) + 1
     DomLength(1:NDim) = DomainEnd(1:NDim) - DomainStart(1:NDim) + 1

     ! Transposing the data order and dim. string order, store to RODimNames
     call ExtOrder(MemoryOrder,Length,Status)
     call ExtOrder(MemoryOrder,DomLength,Status)
     if(Status /= WRF_NO_ERR) then
        write(msg,*) 'Warning BAD MEMORY ORDER in ',__FILE__,', line', __LINE__ 
        call wrf_debug ( WARN , msg)
        return
     endif

     ! Map datatype from WRF to HDF5
     select case (FieldType)
     case (WRF_REAL)
        XType = H5T_NATIVE_REAL
     case (WRF_REAL8)
        Xtype = H5T_NATIVE_DOUBLE
     case (WRF_INTEGER)
        XType = H5T_NATIVE_INTEGER
     case (WRF_LOGICAL)
        XType = DH%EnumID
     case default
        Status = WRF_HDF5_ERR_DATA_TYPE_NOTFOUND
        return
     end select

     ! HANDLE  with dim. scale 
     ! handle dimensional scale data; search and store them in a table.
     ! The table is one dimensional array of compound data type. One member of
     ! the type is HDF5 string, representing the name of the dim(west_east_stag eg.)
     ! Another number is the length of the dimension(west_east_stag = 31)
     ! In this part, we will not store TIME but leave it at the end since the time
     ! index won't be known until the end of the run; since all fields(HDF5 datasets)
     ! have the same timestamp, writing it once should be fine.

     ! 1) create a loop for dimensions
     call GetDataTimeIndex('write',DataHandle,DateStr,TimeIndex,Status)
     if(Status /= WRF_NO_ERR) then
        return
     endif

     if(TimeIndex == 1) then

        ! 2) get the dim. name, the first dim. is reserved for time, 
        call ExtOrderStr(MemoryOrder,DimNames,RODimNames,Status)
        if(Status /= WRF_NO_ERR) then
           write(msg,*) 'Warning BAD MEMORY ORDER in ',__FILE__,', line', __LINE__ 
           call wrf_debug ( WARN , msg)
           return
        endif
        ! 3) get the dim. length
        ! 4) inside the loop, search the table for dimensional name( table module)
        !    IF FOUND, go to the next dimension, return the table dimensional rank
        !    (For example, find west_east_stag in the table, the rank of "west_east_stag"
        !     is 3; so return 3 for the array dimrank.)
        !    in the table; so through the table, we can find the information
        !    such as names, length of this dimension
        ! 4.1) save the rank into an array for attribute
        !      if not found,  go to 5)
        ! 4)' the first dimension is reserved for time, so table starts from j = 2 
        !
        ! 5) NOT FOUND, inside the loop add the new dimensional information to the 
        ! table(table module)

        ! The first dimension of the field is always "time" and "time"
        ! is also the first dimension of the "table".
        k = 2
        DimRank(1) = 1

        do i = 1,NDim
           do j = 2,MaxTabDims

              ! Search for the table and see if we are at the end of the table
              if (DH%DIMTABLE(j)%dim_name == NO_NAME) then

                 ! Sometimes the RODimNames is NULLName or ''. If that happens,
                 ! we will search the table from the beginning and see 
                 ! whether the name is FAKEDIM(the default name) and  the 
                 ! current length of the dim. is the same as that of FAKEDIM; 
                 ! if yes, use this FAKEDIM for the current field dim. 

                 if(RODimNames(i) ==''.or. RODimNames(i)==NullName) then
                    do m = 2,j
                       if(DomLength(i)==DH%DIMTABLE(m)%Length.and. &
                            DH%DIMTABLE(m)%dim_name(1:7)=='FAKEDIM')then
                          DimRank(k) = m
                          k = k + 1
                          dim_flag = 1
                          exit
                       endif
                    enddo
                    ! No FAKEDIM and the same length dim. is found,
                    ! Add another dimension "FAKEDIM + j", with the length
                    ! as DomLength(i)
                    if (dim_flag == 1) then 
                       dim_flag = 0
                    else   
                       RODimNames(i) = 'FAKEDIM'//achar(j+iachar('0'))
                       DH%DIMTABLE(j)%dim_name  = RODimNames(i)
                       DH%DIMTABLE(j)%length    = DomLength(i)
                       DimRank(k) = j
                       k          = k + 1
                    endif
                    ! no '' or NULLName is found, then assign this RODimNames
                    ! to the dim. table.
                 else
                    DH%DIMTABLE(j)%dim_name  = RODimNames(i)
                    DH%DIMTABLE(j)%length    = DomLength(i)
                    DimRank(k)               = j
                    k = k + 1
                 endif
                 exit
                 ! If we found the current dim. in the table already,save the rank
              else if(DH%DIMTABLE(j)%dim_name == RODimNames(i)) then
                 ! remember the rank of dimensional scale
                 DimRank(k) = j
                 k = k + 1
                 exit
              else
                 continue
              endif
           enddo
        enddo
     endif ! end of timeindex of 1

     ! 6) create an attribute array called DimRank to store the rank of the attribute.
     !    This will be done in the HDF5IOWRITE routine        

     ! 7) before the end of the run, 1) update time, 2) write the table to HDF5.

     ! get the index of l1,.......for writing HDF5 file.
     StoredStart = 1
     call GetIndices(NDim,MemoryStart,MemoryEnd,l1,l2,m1,m2,n1,n2)
     call GetIndices(NDim,StoredStart,Length   ,x1,x2,y1,y2,z1,z2)
     call GetIndices(NDim,PatchStart, PatchEnd ,i1,i2,j1,j2,k1,k2)
     di=1
     if(FieldType == WRF_REAL8) di = 2
     allocate(XField(di,x1:x2,y1:y2,z1:z2), STAT=stat)
     if(stat/= 0) then
        Status = WRF_ERR_FATAL_ALLOCATION_ERROR
        write(msg,*) 'Fatal ALLOCATION ERROR in ',__FILE__,', line',__LINE__
        call wrf_debug ( FATAL , msg)
        return
     endif

     ! Transpose the real data for tools people
     call Transpose('write',MemoryOrder,di, Field,l1,l2,m1,m2,n1,n2 &
          ,XField,x1,x2,y1,y2,z1,z2 &
          ,i1,i2,j1,j2,k1,k2 )

     ! handle with logical data separately,because of not able to 
     ! map Fortran Logical type to C type
     if(FieldType .eq. WRF_LOGICAL) then
        allocate(BUFFER(di,x1:x2,y1:y2,z1:z2), STAT=stat)
        do k =z1,z2
           do j = y1,y2
              do i = x1,x2
                 do m = 1,di
                    if(XField(m,i,j,k)/= 0) then
                       BUFFER(m,i,j,k) = 1
                    else
                       BUFFER(m,i,j,k) = 0
                    endif
                 enddo
              enddo
           enddo
        enddo
        call HDF5IOWRITE_bdy(DataHandle,Comm,DateStr,Length,DomainStart, DomainEnd &
             ,PatchStart,PatchEnd, MemoryOrder &
             ,FieldType,XType,groupID,TimeIndex,DimRank &
             ,Var,BUFFER,IOFlag,Status)
        deallocate(BUFFER,STAT=stat)
        if(stat/=0) then
           Status = WRF_ERR_FATAL_ALLOCATION_ERROR
           write(msg,*) 'Fatal ALLOCATION ERROR in ',__FILE__,', line',__LINE__
           call wrf_debug ( FATAL , msg)
           return
        endif
     else 
        call HDF5IOWRITE_bdy(DataHandle,Comm,DateStr,Length, DomainStart, DomainEnd &
             ,PatchStart, PatchEnd, MemoryOrder &
             ,FieldType,XType,groupID,TimeIndex,DimRank &
             ,Var,XField,IOFlag,Status)
     endif

     if (Status /= WRF_NO_ERR) then 
        return
     endif

     deallocate(XField,STAT=stat)
     if(stat/=0) then
        Status = WRF_ERR_FATAL_ALLOCATION_ERROR
        write(msg,*) 'Fatal ALLOCATION ERROR in ',__FILE__,', line',__LINE__
        call wrf_debug ( FATAL , msg)
        return
     endif
  endif

  return 

end subroutine ext_phdf5_write_bdy