program regrid
!-----------------------------------------------------------------------
! GNU General Public License
!
! This program is free software; you can redistribute it and/or modify it and
! are expected to follow the terms of the GNU General Public License
! as published by the Free Software Foundation; either version 2 of
! the License, or (at your option) any later version.
!
! MOM is distributed in the hope that it will be useful, but WITHOUT
! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
! License for more details.
!
! For the full text of the GNU General Public License,
! write to: Free Software Foundation, Inc.,
! 675 Mass Ave, Cambridge, MA 02139, USA.
! or see: http://www.gnu.org/licenses/gpl.html
!-----------------------------------------------------------------------
!
! Zhi Liang
!
!
! This program remap data from logically rectangular grid to logically rectangular grid.
!
!
! This program expects to read data from a netcdf file, which is specfied
! by the namelist variable "src_data". The number of data to be remapped is
! specified by num_flds. The name of field to be remapped is specified
! by the namelist variable "fld_name". The source data should be on the source
! grid which is specified by namelist variable src_grid. The destination grid is
! specified by nml dst_grd. The output file is a netcdf file specified
! by the namelist variable "dst_data". Each field can be a scalar variable or
! a vector field, which is specified by vector_fld. The vector field should
! always be paired together. A laplacian extrapolation will be performed when
! there is any missing value in the source data to interpolate data onto missing points.
!
use mpp_mod, only : mpp_npes, mpp_pe, mpp_root_pe, mpp_error
use mpp_mod, only : FATAL, WARNING, stdout, mpp_chksum
use mpp_domains_mod, only : mpp_define_layout, mpp_define_domains, domain2d
use mpp_domains_mod, only : mpp_global_field, mpp_domains_set_stack_size, mpp_get_compute_domain
use mpp_domains_mod, only : mpp_update_domains, CYCLIC_GLOBAL_DOMAIN, FOLD_NORTH_EDGE
use fms_mod, only : fms_init, open_namelist_file, close_file, fms_end
use fms_mod, only : check_nml_error, write_version_number, lowercase, uppercase
use fms_io_mod, only : fms_io_exit
use constants_mod, only : constants_init, PI
use horiz_interp_mod, only : horiz_interp_init, horiz_interp, horiz_interp_type
use axis_utils_mod, only : interp_1d
implicit none
#include "netcdf.inc"
integer, parameter :: max_flds = 20
integer, parameter :: max_iter = 2000
integer, parameter :: max_atts = 20
real, parameter :: rel_coef = 0.6
real, parameter :: epsln = 1.0e-10
!--- namelist interface ----------------------------------------------
!
!
! Number of fields.
!
!
! Name of input file containing to-be-remapped data.
!
!
! Name of output file containing after-remapped data.
!
!
! Name of grid descriptor file containing target grid information.
!
!
! Name of grid descriptor file containing source grid information.
!
!
! Name of runoff field in input file.
!
!
! Name of grid where the field located. Valid choices are (T)racer, (C)orner, (E)ast and (N)orth.
!
!
! True if fields are vector components. All the vector field should be paired together.
! That is, if vector_field(n) is .true., then vector_field(n+1) should be true.
!
!
! The stopping criteria when extrapping data onto missing points.
!
!
! Number of nearest neighbors for regridding.
!
!
! Maximum region of influence around destination grid points.
!
!
! when use_source_vertical_grid is set to true, the destination data will
! have the same vertical level as the source data. When use_source_vertical_grid
! is false, the vertical grid of destination data will come from dest_grid.
! a linear vertical interpolation will be done when the source vertical is different
! from destination vertical grid.
!
!
! flag to indicate if the land/sea mask of source/destination grid will be applied
! on the output dest_file. When apply_mask is false, the destination data will be
! global data, i.e. no missing value in the destination data file. When apply_mask
! is true, mask will be applied to the destination data. The mask can be either
! source grid or destination grid determined by nml use_source_vertical_grid.
! When use_source_vertical_grid is true, source grid mask will be applied, otherwise
! destination grid mask will be applied.
!
!
! specifying the remapping method when remampping data onto current grid.
! Its value can be "spherical" or " bilinear". "spherical" interpolation is a
! inverse distance weighted interpolation algorithm. Default value is "bilinear".
! "bilinear" interpolation is recommanded, since bilinear interpolation will provide
! more smooth results than "spherical" interpolation (especially when interpolating
! from coarse grid to fine grid). Plus bilinear interpolation is much more efficiency
! than "spherical interpolation". Since bilinear interpolation suppose the source grid
! is a lat-lon grid, "spherical" need to be used if the source grid is not a lat-lon grid.
!
!
! For Debugging. Set true to print out chksum information for debugging reproducing ability
! accross processors. default is false.
!
!
integer :: num_flds = 0
character(len=128) :: src_data = ''
character(len=128) :: src_grid = ''
character(len=128) :: dst_data = ''
character(len=128) :: dst_grid = ''
character(len=16) :: fld_name(max_flds) = ''
character(len=1) :: fld_pos(max_flds) = '' ! with value 'T','C','E','N'
logical :: vector_fld(max_flds) = .false. ! True if fields are vector components.
real :: stop_crit(max_flds) = 0.001
integer :: num_nbrs = 5
real :: max_dist = 0.1
logical :: use_source_vertical_grid = .FALSE.
logical :: apply_mask = .TRUE.
character(len=32) :: interp_method = "bilinear"
logical :: debug = .false.
namelist /regrid_nml/ num_flds, src_data, src_grid, dst_data, dst_grid, fld_name, &
fld_pos, vector_fld, num_nbrs, max_dist, stop_crit, interp_method, &
apply_mask, use_source_vertical_grid, debug
!--- data type for easy data management ------------------------------
type cell_type
real, dimension(:,:), pointer :: geolon=>NULL(), geolat=>NULL() ! geographical grid
real, dimension(:,:,:), pointer :: mask =>NULL() ! mask at each vertical level
real, dimension(:,:), pointer :: sinrot=>NULL(), cosrot=>NULL() ! rotation
end type cell_type
type regrid_type
type(cell_type) :: T,C,E,N ! T,C,E,N-cell
integer :: ni, nj,nk ! grid size
integer :: isc, iec, jsc, jec ! compute domain decompsition src grid
integer :: isd, ied, jsd, jed ! data domain decompsition on dst grid
type(domain2d) :: domain ! domain of the grid ( only destination grid will use it).
logical :: is_cyclic ! indicate if the grid is cyclic
logical :: is_tripolar ! indicate if the grid is tripolar
real, pointer :: zt(:) =>NULL() ! vertical grid
real, pointer :: grid_xt(:)=>NULL() ! T-cell longitude grid
real, pointer :: grid_yt(:)=>NULL() ! T-cell latitude grid
real, pointer :: grid_xc(:)=>NULL() ! C-cell longitude grid
real, pointer :: grid_yc(:)=>NULL() ! C-cell latitude grid
end type regrid_type
!--- version information ---------------------------------------------
character(len=128) :: version = '$Id: regrid.F90,v 1.1 2005/05/12 21:41:05 gtn Exp $'
character(len=128) :: tagname = '$Name: mom4p0d $'
!--- other variables
integer :: ntime_src ! number of time levels of src data
logical :: do_vertical_interp ! indicate if vertical interpolation is needed.
logical :: is_root_pe ! if current pe is root pe.
type(regrid_type) :: Src ! regrid_type data of source
type(regrid_type) :: Dst ! regrid_type data of destination
type(horiz_interp_type), target :: Interp_T, Interp_C ! horiz_interp data at T,C-cell
type(horiz_interp_type), target :: Interp_E, Interp_N ! horiz_interp data at E,N-cell
real, dimension(:), allocatable :: missing_value ! missing value for source field.
real, dimension(:), allocatable :: time_value ! time axis value
real, dimension(:), allocatable :: t1_avg, t2_avg, dt_avg ! time average data
real, dimension(:,:), allocatable :: ht, hc, he, hn ! topography
logical, dimension(:), allocatable :: has_zaxis ! indicate if the field has z axis
logical :: has_taxis,tavg_exist ! indicate if all the field has time axis
integer :: ncid_dst ! ncid corresponding to
integer :: id_t1_dst, id_t2_dst, id_dt_dst
integer :: id_time_dst, id_dst_fld(max_flds)
!--- begin of the program -------------------------------------------
call regrid_init()
call read_grid()
call setup_meta()
call process_data ()
call regrid_end ()
contains
!#####################################################################
subroutine regrid_init
integer :: unit, io_status, ierr, n
character(len=1) :: direction
call fms_init()
call constants_init()
!--- reading namelist ------------------------------------------------
unit = open_namelist_file()
read (unit, regrid_nml,iostat=io_status)
write (stdout(),'(/)')
write (stdout(), regrid_nml)
ierr = check_nml_error(io_status,'regrid_nml')
call close_file (unit)
!--- write out version information ---------------------------------
call write_version_number( version, tagname )
if(num_flds == 0) call error_handler('regrid: nml num_fiels = 0 should be a positive number')
if(num_flds .gt. max_flds) call error_handler('regrid: nml num_fiels is greater than maximum'// &
' allowed fields max_flds. Modify num_flds or increase "max_flds" at top of the program' )
do n = 1, num_flds
if(fld_pos(n) .ne. 'T' .and. fld_pos(n) .ne. 'C' .and. fld_pos(n) .ne. 'E' .and. fld_pos(n) .ne. 'N' ) &
call error_handler('regrid: fld_pos should be "T", "C", "E" or "N" ')
enddo
!--- number of vector_fld is true should be even and should be paired adjacent.
!--- The first one of the pair should be u-component and the second one
!--- should be v-component.
n = 1
do while ( n .le. num_flds )
if(vector_fld(n)) then
n = n + 1
if( n .gt. num_flds .or. ( .NOT. vector_fld(n) ) ) then
call error_handler('regrid: vector field should be paired together')
endif
endif
n = n+1
enddo
!--- write out field information to be remapped.
Write(stdout(),*) '*****************************************************************'
write(stdout(),*) 'number of fields to be remapped are: ', num_flds
write(stdout(),*) 'The source data file is: ', trim(src_data)
write(stdout(),*) 'The source grid file is: ', trim(src_grid)
write(stdout(),*) 'The destination grid file is: ', trim(dst_grid)
if(use_source_vertical_grid) then
write(stdout(),*) 'use_source_vertical_grid is set to true. The destination data will have '// &
'same vertical level as the source data '
else
write(stdout(),*) 'use_source_vertical_grid is set to false. vertical interpolation will ', &
'be performed if the source and destination has different vertical grid. '
endif
direction = 'x'
do n = 1, num_flds
if(vector_fld(n)) then
write(stdout(),*) '** field ',n,': ',trim(fld_name(n)), ' at '// &
trim(fld_pos(n))//'-cell center is the '//direction//'-component of a vector field'
if(direction == 'x') then
direction = 'y'
else
direction = 'x'
endif
else
write(stdout(),*) '**field ',n,': ',trim(fld_name(n)), ' at '// &
trim(fld_pos(n))//'-cell center is a scalar variable'
endif
enddo
!--- memory allocation
allocate(has_zaxis(num_flds), missing_value(num_flds) )
has_zaxis = .false.
missing_value = -1e20
is_root_pe = mpp_pe() == mpp_root_pe()
end subroutine regrid_init
!#################################################################
!--- read the src grid and dst grid and land/sea mask of dst grid.
subroutine read_grid
integer :: isc, iec, jsc, jec
integer :: k, npes, layout(2)
real :: D2R
logical :: use_src_vgrid
D2R = PI/180.0
!--- read some general grid informaiton for source grid and destination grid
call get_grid_info(src_grid, Src, .TRUE.)
call get_grid_info(dst_grid, Dst, .FALSE.)
do_vertical_interp = .false.
if(use_source_vertical_grid) then !--- modify the destination vertical information for the future use.
!--- In this case the destination vertical grid should be the same as source.
Dst%nk = Src%nk
deallocate(Dst%zt)
allocate(Dst%zt(Dst%nk))
Dst%zt = Src%zt
else !--- when use_source_vertical_grid is false, vertical interpolation will be done if the source vertical
!--- grid didn't match destination vertical grid.
if(Src%nk .ne. Dst%nk) then
do_vertical_interp = .true.
else
do k = 1, Src%nk
if( abs(Src%zt(k) - Dst%zt(k)) .gt. epsln ) then
do_vertical_interp = .true.
exit
endif
enddo
endif
if(do_vertical_interp) then
write(stdout(),*)'NOTE: Since source vertical grid does not match ' //&
'destination vertical grid and nml use_source_vertical_grid is set ' //&
'to false, vertical interpolation will be performed. '
else
write(stdout(),*)'NOTE: Even though nml use_source_vertical_grid is set to false, ', &
'but since source vertical grid match destination vertical grid, ', &
'no vertical interpolation will be performed. '
endif
endif
isc= Dst%isc; iec= Dst%iec; jsc= Dst%jsc; jec= Dst%jec;
!--- when source is tripolar grid, 'spherical' interpolation will be used
!--- no matter your choice of "interp_method".
if(Src%is_tripolar .and. trim(interp_method) == "bilinear") then
write(stdout(),*) "WARNING: Since src grid is tripolar grid, even though you chose ", &
"bilinear option, spherical option will be used."
endif
!--- call horiz_interp_init to calculate the reampping weight in horizontal direction
if( any(fld_pos == 'T') ) then
if(Src%is_tripolar) then
call horiz_interp_init(Interp_T, Src%T%geolon*D2R, Src%T%geolat*D2R, &
Dst%T%geolon(isc:iec,jsc:jec)*D2R, Dst%T%geolat(isc:iec,jsc:jec)*D2R, &
interp_method='spherical', num_nbrs=num_nbrs, max_dist=max_dist, &
src_modulo = Src%is_cyclic)
else
call horiz_interp_init(Interp_T, Src%T%geolon(:,1)*D2R, Src%T%geolat(1,:)*D2R, &
Dst%T%geolon(isc:iec,jsc:jec)*D2R, Dst%T%geolat(isc:iec,jsc:jec)*D2R, &
interp_method=trim(interp_method), num_nbrs=num_nbrs, max_dist=max_dist, &
src_modulo = Src%is_cyclic, grid_at_center = .true.)
endif
endif
if( any(fld_pos == 'C') ) then
if(Src%is_tripolar) then
call horiz_interp_init(Interp_C, Src%C%geolon*D2R, Src%C%geolat*D2R, &
Dst%C%geolon(isc:iec,jsc:jec)*D2R, Dst%C%geolat(isc:iec,jsc:jec)*D2R, &
interp_method='spherical', num_nbrs=num_nbrs, max_dist=max_dist, &
src_modulo = Src%is_cyclic )
else
call horiz_interp_init(Interp_C, Src%C%geolon(:,1)*D2R, Src%C%geolat(1,:)*D2R, &
Dst%C%geolon(isc:iec,jsc:jec)*D2R, Dst%C%geolat(isc:iec,jsc:jec)*D2R, &
interp_method=trim(interp_method), num_nbrs=num_nbrs, max_dist=max_dist, &
src_modulo = Src%is_cyclic, grid_at_center = .true.)
endif
endif
if( any(fld_pos == 'E') ) then
if(Src%is_tripolar) then
call horiz_interp_init(Interp_E, Src%E%geolon*D2R, Src%E%geolat*D2R, &
Dst%E%geolon(isc:iec,jsc:jec)*D2R, Dst%E%geolat(isc:iec,jsc:jec)*D2R, &
interp_method='spherical', num_nbrs=num_nbrs, max_dist=max_dist, &
src_modulo = Src%is_cyclic)
else
call horiz_interp_init(Interp_E, Src%E%geolon(:,1)*D2R, Src%E%geolat(1,:)*D2R, &
Dst%E%geolon(isc:iec,jsc:jec)*D2R, Dst%E%geolat(isc:iec,jsc:jec)*D2R, &
interp_method=trim(interp_method), num_nbrs=num_nbrs, max_dist=max_dist, &
src_modulo = Src%is_cyclic, grid_at_center = .true.)
endif
endif
if( any(fld_pos == 'N') ) then
if(Src%is_tripolar) then
call horiz_interp_init(Interp_N, Src%N%geolon*D2R, Src%N%geolat*D2R, &
Dst%N%geolon(isc:iec,jsc:jec)*D2R, Dst%N%geolat(isc:iec,jsc:jec)*D2R, &
interp_method='spherical', num_nbrs=num_nbrs, max_dist=max_dist, &
src_modulo = Src%is_cyclic)
else
call horiz_interp_init(Interp_N, Src%N%geolon(:,1)*D2R, Src%N%geolat(1,:)*D2R, &
Dst%N%geolon(isc:iec,jsc:jec)*D2R, Dst%N%geolat(isc:iec,jsc:jec)*D2R, &
interp_method=trim(interp_method), num_nbrs=num_nbrs, max_dist=max_dist, &
src_modulo = Src%is_cyclic, grid_at_center = .true.)
endif
endif
end subroutine read_grid
!#####################################################################
subroutine get_grid_info(gridfile, Regrid, is_src_grid)
character(len=*), intent(in) :: gridfile
type(regrid_type), intent(inout) :: Regrid
logical, intent(in) :: is_src_grid
integer :: rcode, ncid, natt, id_zt, id_kmt, dims(2)
integer :: id_grid_xt, id_grid_yt, id_grid_xc, id_grid_yc
integer :: npes, i, j, k, layout(2)
integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
logical :: is_new_grid
character(len=128) :: name, catt
integer,allocatable,dimension(:,:) :: kmt, kmc, kme, kmn
real, allocatable,dimension(:,:) :: tmp
rcode = nf_open(trim(gridfile), NF_NOWRITE, ncid)
call error_handler('error in open file '//trim(src_data), rcode)
Regrid%ni = 0; Regrid%nj = 0; Regrid%nk = 0
!--- get vertical grid information
rcode = nf_inq_varid(ncid, 'zt', id_zt)
call error_handler('error in inquring id of field zt from file '//trim(gridfile), rcode)
rcode = nf_inq_vardimid(ncid, id_zt, dims)
call error_handler('error in inquring dims of field zt from file '//trim(gridfile), rcode)
rcode = nf_inq_dimlen(ncid, dims(1), Regrid%nk)
call error_handler('error in inquring dimlen of field zt from file '//trim(gridfile), rcode)
allocate(Regrid%zt(Regrid%nk) )
rcode = nf_get_var_double(ncid, id_zt, Regrid%zt)
call error_handler('error in getting data of zt from file '//trim(gridfile), rcode)
!--- get horizontal grid size
rcode = nf_inq_varid(ncid, 'num_levels', id_kmt)
if(rcode == 0) then
is_new_grid = .true.
else
is_new_grid = .false.
rcode = nf_inq_varid(ncid, 'kmt', id_kmt)
endif
call error_handler('Can not find kmt/num_levels in file '//trim(gridfile), rcode)
rcode = nf_inq_vardimid(ncid, id_kmt, dims)
call error_handler('error in inquring dims of field num_levels/kmt from file '//trim(gridfile), rcode)
rcode = nf_inq_dimlen(ncid, dims(1), Regrid%ni )
call error_handler('error in inquring dimlen ni of field num_levels/kmt from file '//trim(gridfile), rcode)
rcode = nf_inq_dimlen(ncid, dims(2), Regrid%nj )
call error_handler('error in inquring dimlen nj of field num_levels/kmt from file '//trim(gridfile), rcode)
!--- get global attributes ( cyclic or tripolar )
rcode = nf_inq_natts(ncid, natt)
call error_handler('error in inquring natts of file '//trim(gridfile), rcode )
do i = 1, natt
rcode = nf_inq_attname(ncid,NF_GLOBAL,i,name )
call error_handler('error in inquring att name of file '//trim(gridfile), rcode )
catt = ''
select case( trim(name) )
case('x_boundary_type')
rcode = nf_get_att_text(ncid,NF_GLOBAL,name,catt)
call error_handler('error in inquring x_boundary_type value of file '//trim(gridfile), rcode )
if(trim(catt) == 'cyclic') then
Regrid%is_cyclic = .true.
Write(stdout(),*)' NOTE: x_boundary_type of grid '//trim(gridfile)//' is cyclic'
else
Write(stdout(),*)' NOTE: x_boundary_type of '//trim(gridfile)//' is solid_walls'
endif
case ('y_boundary_type')
rcode = nf_get_att_text(ncid,NF_GLOBAL,name,catt)
call error_handler('error in inquring y_boundary_type value of file '//trim(gridfile), rcode )
if (trim(catt) == 'fold_north_edge') then
Regrid%is_tripolar = .true.
Write(stdout(),*)' NOTE: y_boundary_type of '//trim(gridfile)//' is tripolar'
else
Write(stdout(),*)' NOTE: y_boundary_type of '//trim(gridfile)//' is solid_walls'
endif
end select
end do
!--- define domain decompsition for destination grid ---------------
if(.not. is_src_grid) then
npes = mpp_npes()
layout = (/1,0/)
call mpp_define_layout((/1,Regrid%ni,1,Regrid%nj/),npes,layout)
if(Regrid%is_tripolar) then
call mpp_define_domains((/1,Regrid%ni,1,Regrid%nj/),layout, Regrid%domain, xflags = CYCLIC_GLOBAL_DOMAIN, &
yflags = FOLD_NORTH_EDGE, xhalo=1, yhalo=1)
else if (Regrid%is_cyclic) then
call mpp_define_domains((/1,Regrid%ni,1,Regrid%nj/),layout, Regrid%domain, xflags = cyclic_global_domain, &
xhalo=1, yhalo=1)
else
call mpp_define_domains((/1,Regrid%ni,1,Regrid%nj/),layout, Regrid%domain, xhalo=1, yhalo=1)
endif
call mpp_get_compute_domain(Regrid%domain,Regrid%isc,Regrid%iec,Regrid%jsc,Regrid%jec)
endif
!--- when the grid is source grid, need to get global grid information.
!--- when the grid is destination grid, only need to get local grid information.
if(is_src_grid) then
isc = 1; iec = Regrid%ni
jsc = 1; jec = Regrid%nj
else
isc = Regrid%isc ; iec = Regrid%iec
jsc = Regrid%jsc ; jec = Regrid%jec
endif
isd = isc-1 ; ied = iec+1
jsd = jsc-1 ; jed = jec+1
! get number vertical level
allocate(kmt(isd:ied,jsd:jed), kmc(isc:iec,jsc:jec), kme(isc:iec,jsc:jec), kmn(isc:iec,jsc:jec) )
allocate(tmp(Regrid%ni,Regrid%nj) )
rcode = nf_get_var_double(ncid, id_kmt, tmp)
call error_handler('error in getting value of kmt from file '//trim(gridfile), rcode)
kmt = 0
kmt(isc:iec,jsc:jec) = tmp(isc:iec,jsc:jec)
if(is_src_grid) then
kmt(isd,jsc:jec) = kmt(iec,jsc:jec)
kmt(ied,jsc:jec) = kmt(isc,jsc:jec)
else
call mpp_update_domains(kmt,Dst%domain)
endif
!--- calculate the mask at T,C,E,N-cell if needed
if( any(fld_pos == 'T') ) then
allocate(Regrid%T%mask(isc:iec,jsc:jec,Regrid%nk))
do k=1,Regrid%nk
do j=jsc,jec
do i=isc,iec
if (kmt(i,j) .ge. k) then
Regrid%T%mask(i,j,k) = 1.0
else
Regrid%T%mask(i,j,k) = 0.0
endif
enddo
enddo
enddo
endif
if( any(fld_pos == 'C') ) then
do j = jsc, jec
do i = isc, iec
kmc(i,j) = min(kmt(i,j), kmt(i+1,j), kmt(i,j+1), kmt(i+1,j+1))
enddo
enddo
allocate(Regrid%C%mask(isc:iec,jsc:jec,Regrid%nk))
do k=1,Regrid%nk
do j=jsc,jec
do i=isc,iec
if (kmc(i,j) .ge. k) then
Regrid%C%mask(i,j,k) = 1.0
else
Regrid%C%mask(i,j,k) = 0.0
endif
enddo
enddo
enddo
endif
if( any(fld_pos == 'E') ) then
do j = jsc, jec
do i = isc, iec
kme(i,j) = min(kmt(i,j), kmt(i+1,j))
enddo
enddo
allocate(Regrid%E%mask(isc:iec,jsc:jec,Regrid%nk))
do k=1,Regrid%nk
do j=jsc,jec
do i=isc,iec
if (kme(i,j) .ge. k) then
Regrid%E%mask(i,j,k) = 1.0
else
Regrid%E%mask(i,j,k) = 0.0
endif
enddo
enddo
enddo
endif
if( any(fld_pos == 'N') ) then
do j = jsc, jec
do i = isc, iec
kmn(i,j) = min(kmt(i,j), kmt(i,j+1))
enddo
enddo
allocate(Regrid%N%mask(isc:iec,jsc:jec,Regrid%nk))
do k=1,Regrid%nk
do j=jsc,jec
do i=isc,iec
if (kmn(i,j) .ge. k) then
Regrid%N%mask(i,j,k) = 1.0
else
Regrid%N%mask(i,j,k) = 0.0
endif
enddo
enddo
enddo
endif
!--- get the destination axis grid information ---------------------------------
if(.not. is_src_grid) then
allocate(Regrid%grid_xt(Regrid%ni),Regrid%grid_yt(Regrid%nj) )
allocate(Regrid%grid_xc(Regrid%ni),Regrid%grid_yc(Regrid%nj) )
if(is_new_grid) then
rcode = nf_inq_varid(ncid, 'grid_x_T', id_grid_xt)
call error_handler('error in inquring variable id of field grid_x_T', rcode )
rcode = nf_inq_varid(ncid, 'grid_y_T', id_grid_yt)
call error_handler('error in inquring variable id of field grid_y_T', rcode )
rcode = nf_inq_varid(ncid, 'grid_x_C', id_grid_xc)
call error_handler('error in inquring variable id of field grid_x_C', rcode )
rcode = nf_inq_varid(ncid, 'grid_y_C', id_grid_yc)
call error_handler('error in inquring variable id of field grid_y_C', rcode )
else
rcode = nf_inq_varid(ncid, 'gridlon_t', id_grid_xt)
call error_handler('error in inquring variable id of field gridlon_t', rcode )
rcode = nf_inq_varid(ncid, 'gridlat_t', id_grid_yt)
call error_handler('error in inquring variable id of field gridlat_t', rcode )
rcode = nf_inq_varid(ncid, 'gridlon_c', id_grid_xc)
call error_handler('error in inquring variable id of field gridlon_c', rcode )
rcode = nf_inq_varid(ncid, 'gridlat_c', id_grid_yc)
call error_handler('error in inquring variable id of field gridlat_c', rcode )
endif
rcode = nf_get_var_double(ncid, id_grid_xt, Regrid%grid_xt)
call error_handler('error in getting data of variable grid_x_T/gridlon_t', rcode )
rcode = nf_get_var_double(ncid, id_grid_yt, Regrid%grid_yt)
call error_handler('error in getting data of variable grid_y_T/gridlat_t', rcode )
rcode = nf_get_var_double(ncid, id_grid_xc, Regrid%grid_xc)
call error_handler('error in getting data of variable grid_x_C/gridlon_c', rcode )
rcode = nf_get_var_double(ncid, id_grid_yc, Regrid%grid_yc)
call error_handler('error in getting data of variable grid_y_C/gridlat_c', rcode )
endif
if(any(fld_pos == 'T') ) then
call get_cell_info(Regrid%T,'T',ncid,Regrid%ni,Regrid%nj,isc,iec,jsc,jec,is_new_grid)
endif
if(any(fld_pos == 'C') ) then
call get_cell_info(Regrid%C,'C',ncid,Regrid%ni,Regrid%nj,isc,iec,jsc,jec,is_new_grid)
endif
if(any(fld_pos == 'E') ) then
call get_cell_info(Regrid%E,'E',ncid,Regrid%ni,Regrid%nj,isc,iec,jsc,jec,is_new_grid)
endif
if(any(fld_pos == 'N') ) then
call get_cell_info(Regrid%N,'N',ncid,Regrid%ni,Regrid%nj,isc,iec,jsc,jec,is_new_grid)
endif
deallocate(kmt, kmc, kme, kmn,tmp)
rcode = nf_close(ncid)
end subroutine get_grid_info
!#####################################################################
subroutine get_cell_info(Cell, type, ncid, ni, nj, isc, iec,jsc,jec,is_new_grid )
type(cell_type), intent(inout) :: Cell
character(len=1), intent(in) :: type
integer, intent(in) :: ncid, ni, nj
integer, intent(in) :: isc, iec, jsc, jec
logical, intent(in) :: is_new_grid
character(len=1) :: lc_type, uc_type
integer :: rcode, id_x, id_y, id_angle, id_sinrot, id_cosrot
real, allocatable :: tmp(:,:)
allocate(Cell%geolon(isc:iec, jsc:jec), Cell%geolat(isc:iec, jsc:jec) )
allocate(Cell%sinrot(isc:iec, jsc:jec), Cell%cosrot(isc:iec, jsc:jec) )
allocate(tmp(ni,nj) )
lc_type = lowercase(type)
uc_type = uppercase(type)
if(is_new_grid) then
rcode = nf_inq_varid(ncid, 'x_'//uc_type, id_x)
call error_handler('error in inquring variable id of field x_'//uc_type, rcode )
rcode = nf_inq_varid(ncid, 'y_'//uc_type, id_y)
call error_handler('error in inquring variable id of field y_'//uc_type, rcode )
rcode = nf_inq_varid(ncid, 'angle_'//uc_type, id_angle)
call error_handler('error in inquring variable id of field angle_'//uc_type, rcode )
else
rcode = nf_inq_varid(ncid, 'geolon_'//lc_type, id_x)
call error_handler('error in inquring variable id of field geolon_'//lc_type, rcode )
rcode = nf_inq_varid(ncid, 'geolat_'//lc_type, id_y)
call error_handler('error in inquring variable id of field geolat_'//lc_type, rcode )
if(lc_type == 'c') then
rcode = nf_inq_varid(ncid, 'sin_rot', id_sinrot)
call error_handler('error in inquring variable id of field sin_rot', rcode )
rcode = nf_inq_varid(ncid, 'cos_rot', id_cosrot)
call error_handler('error in inquring variable id of field cos_rot', rcode )
else
write(stdout(),*)'==> NOTE: No rotation information avaible for '// &
uc_type//'-cell, will set sinrot = 0 and cosrot = 1'
endif
endif
rcode = nf_get_var_double(ncid, id_x, tmp)
call error_handler('error in getting data of variable x_'//uc_type//'/geolon_'//lc_type, rcode )
Cell%geolon(isc:iec, jsc:jec) = tmp(isc:iec,jsc:jec)
rcode = nf_get_var_double(ncid, id_y, tmp)
call error_handler('error in getting data of variable y_'//uc_type//'/geolat_'//lc_type, rcode )
Cell%geolat(isc:iec, jsc:jec) = tmp(isc:iec,jsc:jec)
if(is_new_grid) then
rcode = nf_get_var_double(ncid, id_angle, tmp)
call error_handler('error in getting data of variable angle_'//uc_type, rcode )
Cell%sinrot(isc:iec,jsc:jec) = sin(tmp(isc:iec,jsc:jec))
Cell%cosrot(isc:iec,jsc:jec) = cos(tmp(isc:iec,jsc:jec))
else
if(lc_type == 'c') then
rcode = nf_get_var_double(ncid, id_sinrot, tmp)
call error_handler('error in getting data of variable sin_rot', rcode )
Cell%sinrot(isc:iec,jsc:jec) = tmp(isc:iec,jsc:jec)
rcode = nf_get_var_double(ncid, id_cosrot, tmp)
call error_handler('error in getting data of variable cos_rot', rcode )
Cell%cosrot(isc:iec,jsc:jec) = tmp(isc:iec,jsc:jec)
else
Cell%sinrot = 0
Cell%cosrot = 1
endif
endif
deallocate(tmp)
end subroutine get_cell_info
!#####################################################################
!--- set up axis and field meta data for destination data file
subroutine setup_meta
integer :: ncid_src, rcode, id_fld, id_dim, id_time, dims(4)
integer :: type, len, ndims, natt_dim, natt, dimids(4), ndims_dst
integer :: n, m, i, j, num_has_taxis, start(4), nwrite(4)
integer :: id_t1_src, id_t2_src, id_dt_src, dim_time_dst
integer, parameter :: max_dim = 10
integer :: dims_dst(max_dim), id_axes(max_dim), fld_dims(4), dims_id(max_dim)
character(len=1) :: dims_pos(max_dim), dims_cart(max_dim)
character(len=128) :: name, att_name, cart, dims_name(max_dim)
character(len=512) :: catt
logical :: found_dim = .false.
logical :: has_missing(max_flds)
!--- open the dst_data file from root_pe.
if(is_root_pe) then
rcode = nf_create(trim(dst_data),NF_WRITE, ncid_dst)
call error_handler('error in creating file '//trim(dst_data), rcode)
endif
!--- get src_data information ( ntime, global attributes, axis and field meta information )
rcode = nf_open(trim(src_data), NF_NOWRITE, ncid_src)
call error_handler('error in opening file '//trim(src_data), rcode)
!--- get missing value, tavg_information, has_zaxis or has_taxis
num_has_taxis = 0
ndims_dst = 0
tavg_exist = .false.
ntime_src = 1
do n = 1, num_flds
rcode = nf_inq_varid(ncid_src,fld_name(n), id_fld)
call error_handler('error in inquring id of field '//trim(fld_name(n))// ' of file '//trim(src_data), rcode)
rcode = nf_inq_varndims( ncid_src, id_fld, ndims )
call error_handler('error in inquring ndims of field '//trim(fld_name(n))// ' of file '//trim(src_data), rcode)
rcode = nf_inq_vardimid( ncid_src, id_fld, dimids )
call error_handler('error in inquring dimids of field '//trim(fld_name(n))// ' of file '//trim(src_data), rcode)
rcode = nf_inq_varnatts(ncid_src, id_fld, natt )
call error_handler('error in inquring natt of field '//trim(fld_name(n))// ' of file '//trim(src_data), rcode)
!--- to check if each field has z or time axis
do m = 1, ndims
rcode = nf_inq_dimname ( ncid_src, dimids(m), name )
call error_handler('error in inquring dimension name of dimid', rcode)
rcode = nf_inq_varid(ncid_src, name, id_dim)
call error_handler('error in inquring variable id of '//trim(name), rcode)
rcode = nf_inq_varnatts(ncid_src, id_dim, natt_dim)
call error_handler('error in inquring number of attributes of variable '//trim(name), rcode)
if(lowercase(trim(name)) == 'time') then
cart = 'T'
if(num_has_taxis == 0) then
rcode = nf_inq_dimlen(ncid_src, dimids(m), ntime_src)
call error_handler('error in inquring time dimension from file '//trim(src_data), rcode)
allocate(time_value(ntime_src) )
rcode = nf_get_var_double(ncid_src, id_dim, time_value)
call error_handler('error in inquring time value from file '//trim(src_data), rcode)
endif
num_has_taxis = num_has_taxis + 1
else
do i = 1, natt_dim
rcode = nf_inq_attname(ncid_src, id_dim,i,att_name )
call error_handler('error in inquring attribute name ', rcode)
if(trim(att_name) == 'cartesian_axis' ) then
rcode = nf_get_att_text(ncid_src,id_dim,att_name,cart)
call error_handler('error in get attribute value of attribute '//trim(att_name), rcode)
select case(cart(1:1))
case('X','Y')
! do nothing
case('Z')
has_zaxis(n) = .true.
case default
call error_handler('The cartesian_axis of each axis should be X, Y or Z ' )
end select
exit
endif
enddo
endif
found_dim = .false.
do j = 1, ndims_dst
if(trim(dims_name(j)) == trim(name)) then
found_dim = .true.
exit
endif
enddo
if(.not. found_dim) then
ndims_dst = ndims_dst + 1
dims_name(ndims_dst) = trim(name)
dims_pos(ndims_dst) = fld_pos(n)
dims_cart(ndims_dst) = cart(1:1)
dims_id(ndims_dst) = id_dim
endif
enddo
has_missing(n) = .false.
do i = 1, natt
rcode = nf_inq_attname(ncid_src, id_fld,i,name )
call error_handler('error in inquring attribute name', rcode)
if(trim(name) == 'time_avg_info') then
tavg_exist = .true.
else if(trim(name) == 'missing_value') then
has_missing(n) = .true.
rcode = nf_get_att_double(ncid_src, id_fld, name, missing_value(n) )
endif
enddo
enddo
if(num_has_taxis == 0) then
has_taxis = .false.
else if(num_has_taxis == num_flds) then
has_taxis = .true.
else
call error_handler('Either all or none of the fields has time axis ' )
endif
!--- suppose the time_avg_info is specified by average_T1, average_T2, average_DT.
if(tavg_exist) then
allocate( t1_avg(ntime_src), t2_avg(ntime_src), dt_avg(ntime_src) )
rcode = nf_inq_varid(ncid_src, 'average_T1', id_t1_src)
call error_handler('error in inquring variable id of average_T1', rcode)
rcode = nf_get_var_double(ncid_src,id_t1_src, t1_avg )
call error_handler('error in getting average_T1 data', rcode)
rcode = nf_inq_varid(ncid_src, 'average_T2', id_t2_src)
call error_handler('error in inquring variable id of average_T2', rcode)
rcode = nf_get_var_double(ncid_src,id_t2_src, t2_avg )
call error_handler('error in getting average_T2 data', rcode)
rcode = nf_inq_varid(ncid_src, 'average_DT', id_dt_src)
call error_handler('error in inquring variable id of average_Dt', rcode)
rcode = nf_get_var_double(ncid_src,id_dt_src, dt_avg )
call error_handler('error in getting average_DT data', rcode)
endif
!--- read the global attributes from source data and write it to output file
rcode = nf_inq_natts(ncid_src, natt )
call error_handler('error in inquring natts of file '//trim(src_data), rcode)
do i = 1, natt
rcode = nf_inq_attname(ncid_src,NF_GLOBAL,i,name )
call error_handler('error in inquring attribute name of file '//trim(src_data), rcode)
rcode = nf_inq_att(ncid_src,NF_GLOBAL,name,type,len)
call error_handler('error in inquring attribute of file '//trim(src_data), rcode)
if(type == NF_CHAR ) then ! only keep character global attributes
if(len .le. 512) then
if(trim(name) == 'filename') then
catt = trim(dst_data)
else
rcode = nf_get_att_text(ncid_src,NF_GLOBAL,name,catt)
call error_handler('error in getting attribute text of file '//trim(src_data), rcode)
endif
if(is_root_pe) then
rcode = nf_put_att_text(ncid_dst, NF_GLOBAL, name, len, catt )
call error_handler('error in putting attribute to file '//trim(dst_data), rcode)
endif
else
write(stdout(),*)'GLOBAL ATT '//trim(name)//' too long - not reading this metadata'
endif
endif
enddo
!--- read dimension information from src_data and write them to dst_data file.
if( .not. is_root_pe) then
rcode = nf_close(ncid_src)
return
endif
rcode = nf_inq_ndims(ncid_src, ndims)
call error_handler('error in inquring ndims of file '//trim(src_data), rcode)
do j = 1, ndims_dst
if(lowercase(trim(dims_name(j)))=='time' ) then
rcode = nf_def_dim(ncid_dst, dims_name(j), NF_UNLIMITED, dims_dst(j))
call error_handler('error in defining time dimension of file '//trim(dst_data), rcode)
rcode = nf_def_var(ncid_dst, dims_name(j), NF_DOUBLE, 1, dims_dst(j), id_axes(j))
call error_handler('error in defining time variable of file '//trim(dst_data), rcode)
id_time_dst = id_axes(j)
dim_time_dst = dims_dst(j)
else
select case(dims_cart(j))
case('X')
len = Dst%ni
case('Y')
len = Dst%nj
case('Z')
len = Dst%nk
end select
rcode = nf_def_dim(ncid_dst, dims_name(j), len, dims_dst(j))
call error_handler('error in defining dimension '//trim(dims_name(j))//' of file '//trim(dst_data), rcode)
rcode = nf_def_var(ncid_dst, dims_name(j), NF_DOUBLE, 1, dims_dst(j), id_axes(j) )
call error_handler('error in defining axis var '//trim(dims_name(j))//' of file '//trim(dst_data), rcode)
endif
!--- write out axis attribute
rcode = nf_inq_varnatts(ncid_src, dims_id(j), natt_dim)
call error_handler('error in inquring number of attributes', rcode)
do i = 1, natt_dim
rcode = nf_inq_attname(ncid_src, dims_id(j), i, name)
rcode = nf_copy_att(ncid_src,dims_id(j), name, ncid_dst, id_axes(j))
call error_handler('error in copy attribute '//trim(name), rcode)
enddo
enddo
!--- read attribue of each field and write them to dst_data file
do n = 1, num_flds
rcode = nf_inq_varid(ncid_src,fld_name(n), id_fld)
call error_handler('error in inquring id of field '//trim(fld_name(n))// ' of file '//trim(src_data), rcode)
rcode = nf_inq_varndims( ncid_src, id_fld, ndims )
call error_handler('error in inquring ndims of field '//trim(fld_name(n))// ' of file '//trim(src_data), rcode)
rcode = nf_inq_vardimid( ncid_src, id_fld, dimids )
call error_handler('error in inquring dimids of field '//trim(fld_name(n))// ' of file '//trim(src_data), rcode)
do i = 1, ndims
rcode = nf_inq_dimname ( ncid_src, dimids(i), name )
call error_handler('error in inquring dimension name of dimid', rcode)
do j = 1, ndims_dst
if(trim(name) == trim(dims_name(j))) then
fld_dims(i) = dims_dst(j)
exit
endif
enddo
enddo
rcode = nf_def_var(ncid_dst, fld_name(n), NF_DOUBLE, ndims, fld_dims(1:ndims), id_dst_fld(n) )
!--- copy the source field attribute to destination field.
rcode = nf_inq_varnatts(ncid_src, id_fld, natt )
call error_handler('error in inquring natt of field '//trim(fld_name(n))// ' of file '//trim(src_data), rcode)
do i = 1, natt
rcode = nf_inq_attname(ncid_src, id_fld, i, name)
call error_handler('error in inquring attribute '//trim(name), rcode)
if(trim(name) .ne. '_FillValue') then
rcode = nf_copy_att(ncid_src,id_fld, trim(name), ncid_dst, id_dst_fld(n))
call error_handler('error in copy attribute '//trim(name)//' of variable '//trim(fld_name(n)), rcode)
endif
enddo
if(.not. has_missing(n)) then
rcode = nf_put_att_double(ncid_dst, id_dst_fld(n), 'missing_value', NF_DOUBLE, 1, missing_value(n:n) )
call error_handler('error in put missing_value attribute of var '//trim(fld_name(n))// &
' of file '//trim(dst_data), rcode)
endif
call error_handler('error in defining var '//trim(fld_name(n))//' of file '//trim(dst_data), rcode)
enddo
!--- define time avg info, suppose the time_avg_info is specified by average_T1, average_T2, average_DT.
if(tavg_exist) then
rcode = nf_def_var(ncid_dst, 'average_T1', NF_DOUBLE, 1, dim_time_dst, id_t1_dst)
rcode = nf_inq_varnatts(ncid_src, id_t1_src, natt )
call error_handler('error in inquring natt of average_T1 of file '//trim(src_data), rcode)
do i = 1, natt
rcode = nf_inq_attname(ncid_src, id_t1_src, i, name)
call error_handler('error in inquring average_T1 attribute '//trim(name), rcode)
rcode = nf_copy_att(ncid_src,id_t1_src, name, ncid_dst, id_t1_dst)
call error_handler('error in copy average_T1 attribute '//trim(name), rcode)
enddo
rcode = nf_def_var(ncid_dst, 'average_T2', NF_DOUBLE, 1, dim_time_dst, id_t2_dst)
rcode = nf_inq_varnatts(ncid_src, id_t2_src, natt )
call error_handler('error in inquring natt of average_T2 of file '//trim(src_data), rcode)
do i = 1, natt
rcode = nf_inq_attname(ncid_src, id_t2_src, i, name)
call error_handler('error in inquring average_T2 attribute '//trim(name), rcode)
rcode = nf_copy_att(ncid_src,id_t2_src, name, ncid_dst, id_t2_dst)
call error_handler('error in copy average_T2 attribute '//trim(name), rcode)
enddo
rcode = nf_def_var(ncid_dst, 'average_DT', NF_DOUBLE, 1, dim_time_dst, id_dt_dst)
rcode = nf_inq_varnatts(ncid_src, id_dt_src, natt )
call error_handler('error in inquring natt of average_DT of file '//trim(src_data), rcode)
do i = 1, natt
rcode = nf_inq_attname(ncid_src, id_dt_src, i, name)
call error_handler('error in inquring average_DT attribute '//trim(name), rcode)
rcode = nf_copy_att(ncid_src,id_dt_src, name, ncid_dst, id_dt_dst)
call error_handler('error in copy average_DT attribute '//trim(name), rcode)
enddo
endif
rcode = nf_enddef(ncid_dst)
rcode = nf_close(ncid_src)
!--- write axis data to dst_data
start = 1; nwrite = 1
do j = 1, ndims_dst
select case(dims_cart(j))
case('X')
nwrite(1) = Dst%ni
if(dims_pos(j) == 'T' .or. dims_pos(j) == 'N') then
rcode = nf_put_vara_double(ncid_dst,id_axes(j), start, nwrite, Dst%grid_xt )
else
rcode = nf_put_vara_double(ncid_dst,id_axes(j), start, nwrite, Dst%grid_xc )
endif
call error_handler('error in putting data of '//trim(dims_name(j))//' to file '//trim(dst_data), rcode)
case('Y')
nwrite(1) = Dst%nj
if(dims_pos(j) == 'T' .or. dims_pos(j) == 'E') then
rcode = nf_put_vara_double(ncid_dst,id_axes(j), start, nwrite, Dst%grid_yt )
else
rcode = nf_put_vara_double(ncid_dst,id_axes(j), start, nwrite, Dst%grid_yc )
endif
call error_handler('error in putting data of '//trim(dims_name(j))//' to file '//trim(dst_data), rcode)
case('Z')
nwrite(1) = Dst%nk
rcode = nf_put_vara_double(ncid_dst,id_axes(j), start, nwrite, Dst%zt )
call error_handler('error in putting data of '//trim(dims_name(j))//' to file '//trim(dst_data), rcode)
end select
enddo
end subroutine setup_meta
!#####################################################################
subroutine process_data
integer :: ncid_src, rcode, i, j, n, m, k, l, nf, nk_src, nk_dst
integer :: start(4), nread(4), nwrite(4), id_fld(num_flds)
integer :: isc, iec, jsc, jec
real :: temp1, temp2
real, dimension(:,:,:,:), allocatable :: data_src, data_dst
real, dimension(:,:,:), allocatable :: tmp1, tmp2, tmp_src
real, dimension(:,:,:), allocatable :: depth_src_3d, depth_dst_3d
real, dimension(:,:), allocatable :: mask_in
type(horiz_interp_type), pointer :: Interp => NULL()
real, dimension(:,:), pointer :: sinrot => NULL(), cosrot => NULL()
real, dimension(:,:,:), pointer :: mask => NULL()
logical :: is_first = .true.
isc = Dst%isc; iec = Dst%iec; jsc = Dst%jsc; jec = Dst%jec;
!-------------------------------------------------------------------
!--- read src data, remap onto current grid and write output -------
rcode = nf_open(trim(src_data), NF_NOWRITE, ncid_src)
do n = 1, num_flds
rcode = nf_inq_varid(ncid_src, fld_name(n), id_fld(n) )
call error_handler('error in inquring varid of '//trim(fld_name(n))//' of file '//trim(src_data), rcode)
enddo
write(stdout(),*)'***************************************'
write(stdout(),*)' ntime_src is ', ntime_src
if(do_vertical_interp) then
allocate(depth_src_3d(isc:iec,jsc:jec,Src%nk), depth_dst_3d(isc:iec,jsc:jec,Dst%nk))
do k=1, Src%nk
depth_src_3d(:,:,k) = Src%zt(k)
enddo
do k=1, Dst%nk
depth_dst_3d(:,:,k) = Dst%zt(k)
enddo
endif
allocate(mask_in(Src%ni, Src%nj) )
do m = 1, ntime_src
write(stdout(),*)'******************* at time level', m
n = 1
!--- write out time information
if(is_root_pe) then
if(has_taxis) then
rcode = nf_put_var1_double(ncid_dst, id_time_dst, m, time_value(m))
call error_handler('error in put time data to file '//trim(src_data), rcode )
if(tavg_exist) then
rcode = nf_put_var1_double(ncid_dst, id_t1_dst, m, t1_avg(m))
call error_handler('error in put average_T1 data to file '//trim(src_data), rcode )
rcode = nf_put_var1_double(ncid_dst, id_t2_dst, m, t2_avg(m))
call error_handler('error in put average_T2 data to file '//trim(src_data), rcode )
rcode = nf_put_var1_double(ncid_dst, id_dt_dst, m, dt_avg(m))
call error_handler('error in put average_DT data to file '//trim(src_data), rcode )
endif
endif
endif
do while ( n .le. num_flds )
nf = 1
if(vector_fld(n) .and. Src%is_tripolar) nf = 2
nk_src = 1
if(has_zaxis(n)) nk_src = Src%nk
nk_dst = 1
if(has_zaxis(n)) nk_dst = Dst%nk
write(stdout(),*)'************************************************************'
write(stdout(),*)'The following are for the # ',n,' field '//trim(fld_name(n))
write(stdout(),*)'has_zaxis is ', has_zaxis(n)
write(stdout(),*)'nk_dst is ', nk_dst
allocate(data_src(Src%ni, Src%nj, nk_src,nf), data_dst(Dst%ni, Dst%nj, nk_dst,nf) )
allocate(tmp_src(Src%ni, Src%nj, nk_src) )
allocate(tmp1(isc:iec,jsc:jec,nk_src), tmp2(isc:iec,jsc:jec,nk_dst) )
select case(fld_pos(n))
case('T')
Interp => Interp_T
case('C')
Interp => Interp_C
case('E')
Interp => Interp_E
case('N')
Interp => Interp_N
end select
start = 1; nread = 1
nread(1) = Src%ni; nread(2) = Src%nj;
if(has_zaxis(n)) then
nread(3) = nk_src; start(4) = m
else
start(3) = m
endif
rcode = nf_get_vara_double(ncid_src,id_fld(n), start, nread, data_src(:,:,:,1) )
call error_handler('error in getting '//trim(fld_name(n))//' from file '//trim(src_data), rcode )
!--- if the field is a vector field and src_grid is tripolar, read the next field and
!--- rotate data onto spherical grid.
if( vector_fld(n) .and. Src%is_tripolar ) then
select case(fld_pos(n))
case('T')
sinrot => Src%T%sinrot; cosrot => Src%T%cosrot
case('C')
sinrot => Src%C%sinrot; cosrot => Src%C%cosrot
case('E')
sinrot => Src%E%sinrot; cosrot => Src%E%cosrot
case('N')
sinrot => Src%N%sinrot; cosrot => Src%N%cosrot
end select
rcode = nf_get_vara_double(ncid_src,id_fld(n+1), start, nread, data_src(:,:,:,2) )
do k = 1, nk_src
do j = 1, Src%nj
do i = 1, Src%ni
if(data_src(i,j,k,1) /= missing_value(n)) then
temp1 = data_src(i,j,k,1)*cosrot(i,j)-data_src(i,j,k,2)*sinrot(i,j)
temp2 = data_src(i,j,k,1)*sinrot(i,j)+data_src(i,j,k,2)*cosrot(i,j)
data_src(i,j,k,1) = temp1
data_src(i,j,k,2) = temp2
endif
enddo
enddo
enddo
endif
!--- extrap data onto land grid
do l = 1, nf
if(use_source_vertical_grid) then !--- the source grid mask will decide the destination data mask.
if(apply_mask) then
do k = 1, size(data_src,3)
where(data_src(:,:,k,l) == missing_value(n) )
mask_in = 0.0
elsewhere
mask_in = 1.0
end where
call horiz_interp(Interp, data_src(:,:,k,l), tmp2(:,:,k), mask_in=mask_in, &
missing_value=missing_value(n) )
enddo
else
if(any(data_src(:,:,:,l) == missing_value(n))) then
if(Src%is_tripolar .and. is_first) then
is_first = .false.
write(stdout(),*)'WARNING: when the source is tripolar, ', &
'the laplacian extrapolation will not very accurate at the tripolar region. ', &
'Even the source grid is lat-lon grid, the extrapolation will not also not ', &
'very accurate if the lat-lon grid is not uniform. '
endif
call extrap(data_src(:,:,:,l), tmp_src, stop_crit(n), missing_value(n), fld_pos(n) )
!--- remap data onto destination horizontal grid
do k = 1, size(tmp_src,3)
call horiz_interp(Interp, tmp_src(:,:,k), tmp2(:,:,k))
enddo
else
!--- remap data onto destination horizontal grid
do k = 1, size(data_src,3)
call horiz_interp(Interp, data_src(:,:,k,l), tmp2(:,:,k))
enddo
endif
endif
else
if(any(data_src(:,:,:,l) == missing_value(n))) then
if(Src%is_tripolar .and. is_first) then
is_first = .false.
write(stdout(),*)'WARNING: when the source is tripolar, ', &
'the laplacian extrapolation will not very accurate at the tripolar region. ', &
'Even the source grid is lat-lon grid, the extrapolation will not also not ', &
'very accurate if the lat-lon grid is not uniform. '
endif
call extrap(data_src(:,:,:,l), tmp_src, stop_crit(n), missing_value(n), fld_pos(n) )
!--- remap data onto destination horizontal grid
do k = 1, size(tmp_src,3)
call horiz_interp(Interp, tmp_src(:,:,k), tmp1(:,:,k))
enddo
else
!--- remap data onto destination horizontal grid
do k = 1, size(data_src,3)
call horiz_interp(Interp, data_src(:,:,k,l), tmp1(:,:,k))
enddo
endif
if(has_zaxis(n) .and. do_vertical_interp ) then
call interp_1d(depth_src_3d,depth_dst_3d,tmp1,tmp2)
else
tmp2 = tmp1
endif
!--- apply mask if needed,
if(apply_mask) then
select case(fld_pos(n))
case('T')
mask => Dst%T%mask
case('C')
mask => Dst%C%mask
case('E')
mask => Dst%E%mask
case('N')
mask => Dst%N%mask
end select
do k = 1, nk_dst
do j = jsc, jec
do i = isc, iec
if(mask(i,j,k) < 0.5) tmp2(i,j,k) = missing_value(n)
enddo
enddo
enddo
endif
endif
!--- get global data ------------------------------
call mpp_domains_set_stack_size(2*Dst%ni*Dst%nj*nk_dst)
call mpp_global_field(Dst%domain,tmp2, data_dst(:,:,:,l) )
enddo
!--- rotate the data if the field is a vector field and dst_grid is tripolar.
if( vector_fld(n) .and. Dst%is_tripolar ) then
select case(fld_pos(n))
case('T')
sinrot => Dst%T%sinrot; cosrot => Dst%T%cosrot
case('C')
sinrot => Dst%C%sinrot; cosrot => Dst%C%cosrot
case('E')
sinrot => Dst%E%sinrot; cosrot => Dst%E%cosrot
case('N')
sinrot => Dst%C%sinrot; cosrot => Dst%C%cosrot
end select
do k = 1, nk_dst
do j = 1, Dst%nj
do i = 1, Dst%ni
if(data_dst(i,j,k,1) /= missing_value(n)) then
temp1 = data_dst(i,j,k,1)*cosrot(i,j)+data_dst(i,j,k,2)*sinrot(i,j)
temp2 = -data_dst(i,j,k,1)*sinrot(i,j)+data_dst(i,j,k,2)*cosrot(i,j)
data_dst(i,j,k,1) = temp1
data_dst(i,j,k,2) = temp2
endif
enddo
enddo
enddo
select case(fld_pos(n))
case('C')
do k = 1, nk_dst
do i=1,Dst%ni/2
if(data_dst(Dst%ni-i,Dst%nj,k,1) /= missing_value(n)) then
data_dst(i,Dst%nj,k,1) = -1.*data_dst(Dst%ni-i,Dst%nj,k,1)
data_dst(i,Dst%nj,k,2) = -1.*data_dst(Dst%ni-i,Dst%nj,k,2)
endif
enddo
enddo
case('N')
do k = 1, nk_dst
do i=1,Dst%ni/2
if(data_dst(Dst%ni-i+1,Dst%nj,k,1) /= missing_value(n)) then
data_dst(i,Dst%nj,k,1) = -1.*data_dst(Dst%ni-i+1,Dst%nj,k,1)
data_dst(i,Dst%nj,k,2) = -1.*data_dst(Dst%ni-i+1,Dst%nj,k,2)
endif
enddo
enddo
end select
endif
!--- write out data from root_pe
if(is_root_pe) then
if(debug) write(stdout(),*)'NOTE: after regrid data chksum :', mpp_chksum(data_dst, (/mpp_root_pe()/) )
do l = 1, nf
start = 1; nwrite = 1
nwrite(1) = Dst%ni; nwrite(2) = Dst%nj;
if(has_zaxis(n)) then
nwrite(3) = nk_dst
start(4) = m
rcode = nf_put_vara_double(ncid_dst, id_dst_fld(n+l-1), start, nwrite, data_dst(:,:,:,l) )
call error_handler('error in putting '//trim(fld_name(n+l-1))//' in file '//trim(dst_data), rcode )
else
start(3) = m
rcode = nf_put_vara_double(ncid_dst, id_dst_fld(n+l-1), start, nwrite, data_dst(:,:,1,l) )
call error_handler('error in putting '//trim(fld_name(n+l-1))//' in file '//trim(dst_data), rcode )
endif
! rcode = nf_put_vara_double(ncid_dst, id_dst_fld(n+l-1), start, nwrite, data_dst(:,:,:,l) )
! call error_handler('error in putting '//trim(fld_name(n+l-1))//' in file '//trim(dst_data), rcode )
enddo
endif
n = n+nf
deallocate(data_src, data_dst, tmp_src, tmp1, tmp2)
enddo
enddo
rcode = nf_close(ncid_src)
if(is_root_pe) rcode = nf_close(ncid_dst)
if(do_vertical_interp) deallocate(depth_src_3d, depth_dst_3d)
deallocate(mask_in)
end subroutine process_data
!#####################################################################
subroutine regrid_end
call fms_io_exit
call fms_end()
end subroutine regrid_end
!#####################################################################
subroutine extrap(data_in, data_out, crit, missing, pos)
real, dimension(:,:,:), intent(in) :: data_in
real, dimension(:,:,:), intent(out) :: data_out
real, intent(in) :: crit, missing
character(len=1), intent(in) :: pos
real :: resmax, initial_guess = 0.0
integer :: ni,nj,nk, i, j, k, n
real, dimension(0:size(data_in,1)+1, 0:size(data_in,2)+1) :: tmp
real, dimension(size(data_in,1), size(data_in,2) ) :: sor, res
ni = size(data_in,1)
nj = size(data_in,2)
nk = size(data_in,3)
tmp = 0.0
do j= 1, nj
do i= 1, ni
if(data_in(i,j,1) == missing) then
tmp(i,j) = initial_guess
endif
enddo
enddo
do k=1,nk
do j= 1, nj
do i= 1, ni
if(data_in(i,j,k) == missing) then
sor(i,j) = rel_coef
else
tmp(i,j)=data_in(i,j,k)
sor(i,j) = 0.0
endif
enddo
enddo
call fill_boundaries(tmp,pos)
! iterate
n=1
do
resmax=0.0
do j= 1, nj
do i= 1, ni
res(i,j) = 0.25*(tmp(i-1,j)+tmp(i+1,j)+tmp(i,j-1)+tmp(i,j+1)) -tmp(i,j)
enddo
enddo
do j= 1, nj
do i= 1, ni
res(i,j) = res(i,j)*sor(i,j)
tmp(i,j)=tmp(i,j)+res(i,j)
resmax = max(abs(res(i,j)),resmax)
enddo
enddo
if(resmax .le. crit .or. n > max_iter) then
data_out(:,:,k) = tmp(1:ni,1:nj)
exit
endif
!--- update boundaries
call fill_boundaries(tmp,pos)
n=n+1
enddo
write(stdout(),'(a,i4,a,i4)') 'At k-level= ',k
write(stdout(),'(a,i6,a)') 'Stopped after ',n,' iterations'
write(stdout(),'(a,f10.4)') 'maxres= ',resmax
enddo
end subroutine extrap
!##########################################################
subroutine fill_boundaries(data, pos)
real, dimension(0:,0:), intent(inout) :: data
character(len=1), intent(in) :: pos
integer :: i,j, ni, nj
ni = size(data,1) - 2
nj = size(data,2) - 2
if(Dst%is_cyclic) then
data(0,1:nj) = data(ni,1:nj)
data(ni+1,1:nj) = data(1,1:nj)
endif
if(Dst%is_tripolar) then
do i = 1, ni
select case(pos)
case('T')
data(i,nj+1) = data(ni-i+1,nj)
case('C')
data(i,nj+1) = data(ni-i,nj-1)
case('E')
data(i,nj+1) = data(ni-i+1,nj-1)
case('N')
data(i,nj+1) = data(ni-i,nj)
end select
enddo
endif
return
end subroutine fill_boundaries
!#####################################################################
! error handling routine.
subroutine error_handler(mesg, status)
character(len=*), intent(in) :: mesg
integer, optional, intent(in) :: status
character(len=256) :: msg
if(present(status)) then
if(status == 0) return
msg = nf_strerror(status)
msg = trim(mesg)//': '// trim(msg)
else
msg = trim(mesg)
endif
call mpp_error(FATAL,trim(msg) )
end subroutine error_handler
!#####################################################################
end program regrid