!
SUBROUTINE splitncdf(filenames,nfile,stag, xdimname, ydimname, & 1
nproc_x,nproc_y,outdirname, debug,istatus)
!
!-----------------------------------------------------------------------
!
! PURPOSE:
!
! Split files in netCDF format into patches. The patched files will
! contain the same data as original file but in evenly divided
! subdomain specified by the user.
!
!-----------------------------------------------------------------------
!
! Author: Yunheng Wang (11/07/2006)
!
! MODIFICATIONS:
!
!-----------------------------------------------------------------------
!
IMPLICIT NONE
!-----------------------------------------------------------------------
!
! Variable declaration
!
!-----------------------------------------------------------------------
INTEGER, INTENT(IN) :: nfile
CHARACTER(LEN=*), INTENT(IN) :: filenames(nfile)
CHARACTER(LEN=*), INTENT(IN) :: outdirname
CHARACTER(LEN=*), INTENT(IN) :: xdimname, ydimname
LOGICAL, INTENT(IN) :: stag ! Whether the data contains
! both staggered and unstaggered dimensions. If it is true, then xdimname/ydimname is
! the name of staggered dimension. The unstaggered dimensions are assumed to be
! xdimname/ydimname by tripping the trail '_stag'. Such as xdimname = 'x_stag' then
! the unstaggered dimension name is 'x'.
INTEGER, INTENT(IN) :: nproc_x, nproc_y
INTEGER, INTENT(IN) :: debug
INTEGER, INTENT(OUT) :: istatus
!-----------------------------------------------------------------------
!
! Dimensions and work arrays
!
!-----------------------------------------------------------------------
INTEGER :: nxlg, nylg
INTEGER :: nx, ny
INTEGER, ALLOCATABLE :: variin(:), variout(:)
INTEGER, ALLOCATABLE :: varain(:), varaout(:)
INTEGER :: finid
CHARACTER(LEN=256), ALLOCATABLE :: outfilenames(:,:)
INTEGER, ALLOCATABLE :: foutids(:,:)
INTEGER, ALLOCATABLE :: dimouts0(:,:,:)
!
!-----------------------------------------------------------------------
!
! Misc. local variables
!
!-----------------------------------------------------------------------
INTEGER, PARAMETER :: MAX_RANK = 5 ! Assume the max rank is 5
INTEGER :: nf, dindx
INTEGER :: iout, iin
CHARACTER(LEN=256) :: xsdimname, ysdimname
INTEGER :: nxid, nyid, nxsid, nysid
INTEGER :: iloc, jloc
INTEGER :: ndims, unlimdimid, ngatts, nvars
INTEGER :: dimid, odimid, attnum, varid, ovarid
INTEGER :: dimlen
CHARACTER(LEN=256) :: dimname, attname, varname
INTEGER :: vartype, varndims, varnatts
INTEGER :: vardim, varainsize, varaoutsize, varaallsize, varballsize
INTEGER :: vardimids(MAX_RANK), startidx(MAX_RANK), countidx(MAX_RANK), outidx(MAX_RANK)
INTEGER :: sin1d, sin2d, sin3d, sin4d
INTEGER :: sout1d, sout2d, sout3d, sout4d
INTEGER :: nd1, nd2, nd3, nd4, nd5 ! Assume the max rank is 5
!
!-----------------------------------------------------------------------
!
! Including files
!
!-----------------------------------------------------------------------
INCLUDE 'netcdf.inc'
INTEGER :: dimina(NF_MAX_DIMS) ! Dimension size in original file
INTEGER :: dimouta(NF_MAX_DIMS) ! Dimension size in split files
CHARACTER(LEN=256) :: diminnames(NF_MAX_DIMS)
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Begin of executable code below
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
nxsid = 0
nysid = 0
xsdimname = ' '
ysdimname = ' '
IF (stag) THEN
xsdimname = xdimname(1:INDEX(xdimname,'_stag')-1)
ysdimname = ydimname(1:INDEX(ydimname,'_stag')-1)
END IF
!-----------------------------------------------------------------------
!
! Check dimensions first
!
!-----------------------------------------------------------------------
istatus = nf_open(filenames(1),NF_NOWRITE,finid)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
istatus = nf_inq_dimid(finid,xdimname,nxid)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
istatus = nf_inq_dimlen(finid,nxid,nxlg)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
istatus = nf_inq_dimid(finid,ydimname,nyid)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
istatus = nf_inq_dimlen(finid,nyid,nylg)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
WRITE(6,'(1x,2(a,I5))') 'Dimensions in file to be split are: nx = ',nxlg,', ny = ',nylg
IF (MOD((nxlg-3),nproc_x) /= 0 ) THEN
WRITE(6,'(1x,a)') 'ERROR: Wrong dimension size'
WRITE(6,'(1x,2(a,I5),a)') ' Dimension size in X direction (',nxlg,&
') is not divisible by nproc_x (',nproc_x,').'
istatus = -1
RETURN
END IF
IF (MOD((nylg-3),nproc_y) /= 0 ) THEN
WRITE(6,'(1x,a)') 'ERROR: Wrong dimension size'
WRITE(6,'(1x,2(a,I5),a)') ' Dimension size in Y direction (',nylg,&
') is not divisible by nproc_y (',nproc_y,').'
istatus = -2
RETURN
END IF
istatus = nf_close(finid)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
!-----------------------------------------------------------------------
!
! Loop over filenames
!
!-----------------------------------------------------------------------
startidx(:) = 1
ALLOCATE(outfilenames(nproc_x,nproc_y), STAT = istatus)
ALLOCATE(foutids(nproc_x,nproc_y), STAT = istatus)
ALLOCATE(dimouts0(0:NF_MAX_DIMS,nproc_x,nproc_y), STAT = istatus)
DO nf = 1,nfile
IF (debug > 0) WRITE(6,'(1x,2a)') 'Opening file - ',filenames(nf)
istatus = nf_open(filenames(nf),NF_NOWRITE,finid) ! Open file
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
dindx = INDEX(filenames(nf),'/',.TRUE.) + 1
DO jloc = 1,nproc_y ! Create patches
DO iloc = 1,nproc_x
WRITE(outfilenames(iloc,jloc),'(3a,2I2.2)') &
TRIM(outdirname),TRIM(filenames(nf)(dindx:)),'_',iloc,jloc
IF (debug > 0) WRITE(6,'(1x,2a)') 'Creating file - ',TRIM(outfilenames(iloc,jloc))
istatus = nf_create(outfilenames(iloc,jloc),NF_CLOBBER,foutids(iloc,jloc))
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
END DO
END DO
!
! Set dimensions
!
istatus = nf_inq_dimid(finid,xdimname,nxid)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
istatus = nf_inq_dimlen(finid,nxid,nxlg)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
nx = (nxlg-3)/nproc_x + 3
istatus = nf_inq_dimid(finid,ydimname,nyid)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
istatus = nf_inq_dimlen(finid,nyid,nylg)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
ny = (nylg-3)/nproc_y + 3
IF (stag) THEN
istatus = nf_inq_dimid(finid,xsdimname,nxsid)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
istatus = nf_inq_dimlen(finid,nxsid,dimlen)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
IF (dimlen /= nxlg -1) THEN
WRITE(6,'(1x,3a,I4,a,I4,a)') 'ERROR: Wrong size with dimension - ', &
TRIM(xsdimname),'(',dimlen,'), expected: ',nxlg-1,'.'
istatus = -5
RETURN
END IF
istatus = nf_inq_dimid(finid,ysdimname,nysid)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
istatus = nf_inq_dimlen(finid,nysid,dimlen)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
IF (dimlen /= nylg -1) THEN
WRITE(6,'(1x,3a,I4,a,I4,a)') 'ERROR: Wrong size with dimension - ', &
TRIM(ysdimname),'(',dimlen,'), expected: ',nylg-1,'.'
istatus = -5
RETURN
END IF
END IF
istatus = nf_inq_ndims(finid,ndims)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
istatus = nf_inq_unlimdim(finid,unlimdimid)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
IF (debug > 0) WRITE(6,'(5x,a,I2)') 'Copying dimensions - ',ndims
DO dimid = 1,ndims
istatus = nf_inq_dim(finid,dimid,dimname,dimlen)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
diminnames(dimid) = dimname
dimina(dimid) = dimlen ! Save dimension id and len
dimouta(dimid) = dimlen ! Output dimension id and len
IF (dimid == nxid) THEN
dimlen = nx
dimouta(dimid) = dimlen
ELSE IF (dimid == nxsid) THEN
dimlen = nx-1
dimouta(dimid) = dimlen
ELSE IF (dimid == nyid) THEN
dimlen = ny
dimouta(dimid) = dimlen
ELSE IF (dimid == nysid) THEN
dimlen = ny-1
dimouta(dimid) = dimlen
ELSE IF (dimid == unlimdimid) THEN
dimlen = NF_UNLIMITED
END IF
IF (debug > 0) WRITE(6,'(9x,2a)') 'Dimension name - ',TRIM(dimname)
DO jloc = 1,nproc_y ! Write patches Dimensions
DO iloc = 1,nproc_x
istatus = nf_def_dim(foutids(iloc,jloc),dimname,dimlen,odimid)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
END DO
END DO
END DO
dimouts0(:,:,:) = 0 ! The starting index of each dimensions for each subdomain
DO jloc = 1,nproc_y
DO iloc = 1,nproc_x
dimouts0(nxid,iloc,jloc) = (iloc-1)*(nx-3)
dimouts0(nyid,iloc,jloc) = (jloc-1)*(ny-3)
END DO
END DO
IF (stag) THEN
dimouts0(nxsid,:,:) = dimouts0(nxid,:,:)
dimouts0(nysid,:,:) = dimouts0(nyid,:,:)
END IF
!
! Set Global attributes
!
istatus = nf_inq_natts(finid,ngatts)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
IF (debug > 0) WRITE(6,'(5x,a,I2)') 'Copying global attributes - ',ngatts
DO attnum = 1,ngatts
istatus = nf_inq_attname(finid,NF_GLOBAL,attnum,attname)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
IF (debug > 0) WRITE(6,'(9x,2a)') 'Attribute name - ',TRIM(attname)
DO jloc = 1,nproc_y ! Write patches global attributes
DO iloc = 1,nproc_x
istatus = nf_copy_att(finid,NF_GLOBAL,attname,foutids(iloc,jloc),NF_GLOBAL)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
END DO
END DO
END DO
!
! Define variables
!
istatus = nf_inq_nvars(finid,nvars)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
IF (debug > 0) WRITE(6,'(5x,a,I2)') 'Defining variables - ',nvars
DO varid = 1,nvars
istatus = nf_inq_var(finid,varid,varname,vartype,varndims,vardimids,varnatts)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
IF (debug > 0) WRITE(6,'(9x,2a)') 'Variables - ',TRIM(varname)
DO jloc = 1,nproc_y ! Define patches variables
DO iloc = 1,nproc_x
! Dimensions should be in the same order
istatus = nf_def_var(foutids(iloc,jloc),varname,vartype,varndims,vardimids,ovarid)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
DO attnum = 1,varnatts ! Copy variable attributes
istatus = nf_inq_attname(finid,varid,attnum,attname)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
istatus = nf_copy_att(finid,varid,attname,foutids(iloc,jloc),ovarid)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
END DO
END DO
END DO
END DO
DO jloc = 1,nproc_y ! End patches DEF mode
DO iloc = 1,nproc_x
istatus = nf_enddef(foutids(iloc,jloc))
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
END DO
END DO
IF(debug > 0) WRITE(6,'(1x,a)') 'All patches have been defined.'
!
! Split and assign variables, LOOP over variables
!
DO varid = 1,nvars
vardimids(:) = 0
istatus = nf_inq_var(finid,varid,varname,vartype,varndims,vardimids,varnatts)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
IF (debug >0) WRITE(6,'(9x,2a)') 'Processing variables - ',TRIM(varname)
varainsize = 1
varaoutsize = 1
outidx(:) = 1 ! Initial all dimension size to be 1
countidx(:) = 1
DO vardim = 1, varndims
countidx(vardim) = dimina(vardimids(vardim))
outidx(vardim) = dimouta(vardimids(vardim))
varainsize = countidx(vardim)*varainsize
varaoutsize = outidx(vardim)*varaoutsize
IF (debug > 1) WRITE(6,'(13x,a15,2(a,I4),a)') &
TRIM(diminnames(vardimids(vardim))),': ',countidx(vardim),'(in) - ',&
outidx(vardim), '(out).'
END DO
sin1d = countidx(1) ! size of one column, INPUT
sin2d = sin1d*countidx(2) ! size of one slice (xy)
sin3d = sin2d*countidx(3) ! size of one cell (xyz)
sin4d = sin3d*countidx(4)
sout1d = outidx(1) ! size of one column, OUTPUT
sout2d = sout1d*outidx(2)
sout3d = sout2d*outidx(3)
sout4d = sout3d*outidx(4)
SELECT CASE (vartype)
CASE (NF_INT)
IF (varainsize > varaallsize) THEN ! Allocate input array only when necessary
IF (ALLOCATED(variin)) DEALLOCATE(variin, STAT = istatus)
ALLOCATE(variin(varainsize), STAT = istatus)
varaallsize = varainsize
END IF
IF (varaoutsize > varballsize) THEN ! Allocate output array only when necessary
IF (ALLOCATED(variout)) DEALLOCATE(variout, STAT = istatus)
ALLOCATE(variout(varaoutsize), STAT = istatus)
varballsize = varaoutsize
END IF
istatus = NF_GET_VARA_INT(finid,varid,startidx,countidx,variin)
DO jloc = 1,nproc_y ! Write patches variables
DO iloc = 1,nproc_x
IF (debug > 1) THEN
WRITE(6,FMT='(13x,a,2(I4,a))',ADVANCE='NO') &
'Writing to processor - (',iloc,',',jloc,') with: '
DO vardim = 1,varndims
WRITE(6,FMT='(I4,a)',ADVANCE='NO') dimouts0(vardimids(vardim),iloc,jloc),' '
END DO
WRITE(6,*)
END IF
DO nd5 = 1, outidx(5) ! Assume max rank is 5, IMPORTANT
DO nd4 = 1, outidx(4)
DO nd3 = 1, outidx(3)
DO nd2 = 1, outidx(2)
DO nd1 = 1, outidx(1)
iin = nd1+dimouts0(vardimids(1),iloc,jloc) &
+ (nd2+dimouts0(vardimids(2),iloc,jloc)-1)*sin1d &
+ (nd3+dimouts0(vardimids(3),iloc,jloc)-1)*sin2d &
+ (nd4+dimouts0(vardimids(4),iloc,jloc)-1)*sin3d &
+ (nd5+dimouts0(vardimids(5),iloc,jloc)-1)*sin4d
iout = nd1 + (nd2-1)*sout1d + (nd3-1)*sout2d &
+ (nd4-1)*sout3d + (nd5-1)*sout4d
! IF (debug > 2) WRITE(6,'(13x,a,2I2,3(a,I4),4I4)') &
! 'Processor - ',iloc,jloc,': Extracting from ',iin, &
! ' to ',iout,' at ',nd1,nd2,nd3,nd4,nd5
variout(iout) = variin(iin)
END DO
END DO
END DO
END DO
END DO
istatus = nf_put_vara_INT(foutids(iloc,jloc),varid,startidx,outidx,variout)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
END DO
END DO
CASE (NF_FLOAT)
IF (varainsize > varaallsize) THEN ! Allocate input array only when necessary
IF (ALLOCATED(varain)) DEALLOCATE(varain, STAT = istatus)
ALLOCATE(varain(varainsize), STAT = istatus)
varaallsize = varainsize
END IF
IF (varaoutsize > varballsize) THEN ! Allocate output array only when necessary
IF (ALLOCATED(varaout)) DEALLOCATE(varaout, STAT = istatus)
ALLOCATE(varaout(varaoutsize), STAT = istatus)
varballsize = varaoutsize
END IF
istatus = NF_GET_VARA_REAL(finid,varid,startidx,countidx,varain)
DO jloc = 1,nproc_y ! Write patches variables
DO iloc = 1,nproc_x
IF (debug > 1) THEN
WRITE(6,FMT='(13x,a,2(I4,a))',ADVANCE='NO') &
'Writing to processor - (',iloc,',',jloc,') with: '
DO vardim = 1,varndims
WRITE(6,FMT='(I4,a)',ADVANCE='NO') dimouts0(vardimids(vardim),iloc,jloc),' '
END DO
WRITE(6,*)
END IF
DO nd5 = 1, outidx(5) ! Assume max rank is 5, IMPORTANT
DO nd4 = 1, outidx(4)
DO nd3 = 1, outidx(3)
DO nd2 = 1, outidx(2)
DO nd1 = 1, outidx(1)
iin = nd1+dimouts0(vardimids(1),iloc,jloc) &
+ (nd2+dimouts0(vardimids(2),iloc,jloc)-1)*sin1d &
+ (nd3+dimouts0(vardimids(3),iloc,jloc)-1)*sin2d &
+ (nd4+dimouts0(vardimids(4),iloc,jloc)-1)*sin3d &
+ (nd5+dimouts0(vardimids(5),iloc,jloc)-1)*sin4d
iout = nd1 + (nd2-1)*sout1d + (nd3-1)*sout2d &
+ (nd4-1)*sout3d + (nd5-1)*sout4d
! IF (debug > 2) WRITE(6,'(13x,a,2I2,3(a,I4),4I4)') &
! 'Processor - ',iloc,jloc,': Extracting from ',iin, &
! ' to ',iout,' at ',nd1,nd2,nd3,nd4,nd5
!
varaout(iout) = varain(iin)
END DO
END DO
END DO
END DO
END DO
istatus = nf_put_vara_real(foutids(iloc,jloc),varid,startidx,outidx,varaout)
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
END DO
END DO
CASE DEFAULT
WRITE(6,'(1x,a,I2)') 'ERROR: unsupported variable type = ',vartype
istatus = -4
RETURN
END SELECT
END DO
!
! Close files
!
IF (debug > 0) WRITE(6,'(1x,a)') 'Closing all files ...'
DO jloc = 1,nproc_y ! Close patches
DO iloc = 1,nproc_x
istatus = nf_close(foutids(iloc,jloc))
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
END DO
END DO
istatus = nf_close(finid) ! Close file
IF (istatus /= NF_NOERR) CALL handle_err
(istatus)
END DO
DEALLOCATE(outfilenames, foutids, STAT = istatus)
IF (ALLOCATED(varain)) DEALLOCATE(varain, varaout, STAT = istatus)
IF (ALLOCATED(variin)) DEALLOCATE(variin, variout, STAT = istatus)
RETURN
END SUBROUTINE splitncdf
SUBROUTINE handle_err(istat) 151
IMPLICIT NONE
INTEGER, INTENT(IN) :: istat
INCLUDE 'netcdf.inc'
IF (istat /= NF_NOERR) THEN
PRINT *, TRIM(nf_strerror(istat))
STOP 'NetCDF error!'
END IF
RETURN
END SUBROUTINE handle_err