# 1 "../horiz_interp/horiz_interp_bicubic.F90"
!***********************************************************************
!* GNU Lesser General Public License
!*
!* This file is part of the GFDL Flexible Modeling System (FMS).
!*
!* FMS is free software: you can redistribute it and/or modify it under
!* the terms of the GNU Lesser General Public License as published by
!* the Free Software Foundation, either version 3 of the License, or (at
!* your option) any later version.
!*
!* FMS 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.
!*
!* You should have received a copy of the GNU Lesser General Public
!* License along with FMS. If not, see .
!***********************************************************************
module horiz_interp_bicubic_mod
use mpp_mod, only: mpp_error, FATAL, stdout, mpp_pe, mpp_root_pe
use fms_mod, only: write_version_number
use horiz_interp_type_mod, only: horiz_interp_type
use constants_mod, only: PI
implicit none
! This module delivers methods for bicubic interpolation from a
! coarse regular grid on a fine regular grid.
! Subroutines
!
! bcuint
! bcucof
!
! are methods taken from
!
! W. H. Press, S. A. Teukolski, W. T. Vetterling and B. P. Flannery,
! Numerical Recipies in FORTRAN, The Art of Scientific Computing.
! Cambridge University Press, 1992
!
! written by
! martin.schmidt@io-warnemuende.de (2004)
! revied by
! martin.schmidt@io-warnemuende.de (2004)
!
! Version 1.0.0.2005-07-06
! The module is thought to interact with MOM-4.
! Alle benotigten Felder werden extern von MOM verwaltet, da sie
! nicht fur alle interpolierten Daten die gleiche Dimension haben mussen.
private
public :: horiz_interp_bicubic, horiz_interp_bicubic_new, horiz_interp_bicubic_del, fill_xy
public :: horiz_interp_bicubic_init
interface horiz_interp_bicubic_new
module procedure horiz_interp_bicubic_new_1d
module procedure horiz_interp_bicubic_new_1d_s
end interface
! Include variable "version" to be written to log file.
# 1 "../include/file_version.h" 1
! -*-f90-*-
!***********************************************************************
!* GNU Lesser General Public License
!*
!* This file is part of the GFDL Flexible Modeling System (FMS).
!*
!* FMS is free software: you can redistribute it and/or modify it under
!* the terms of the GNU Lesser General Public License as published by
!* the Free Software Foundation, either version 3 of the License, or (at
!* your option) any later version.
!*
!* FMS 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.
!*
!* You should have received a copy of the GNU Lesser General Public
!* License along with FMS. If not, see .
!***********************************************************************
# 23
character(len=*), parameter :: version = 'unknown'
# 64 "../horiz_interp/horiz_interp_bicubic.F90" 2
logical :: module_is_initialized = .FALSE.
integer :: verbose_bicubic = 0
! Grid variables
! xc, yc : co-ordinates of the coarse grid
! xf, yf : co-ordinates of the fine grid
! fc : variable to be interpolated at the coarse grid
! dfc_x : x-derivative of fc at the coarse grid
! dfc_y : y-derivative of fc at the coarse grid
! dfc_xy : x-y-derivative of fc at the coarse grid
! ff : variable to be interpolated at the fine grid
! dff_x : x-derivative of fc at the fine grid
! dff_y : y-derivative of fc at the fine grid
! dff_xy : x-y-derivative of fc at the fine grid
logical :: initialized_bicubic = .false.
real, save :: missing = -1e33
real :: tpi
interface fill_xy
module procedure fill_xy
end interface
contains
!#######################################################################
!
!
! writes version number to logfile.out
!
!
! writes version number to logfile.out
!
subroutine horiz_interp_bicubic_init
if(module_is_initialized) return
call write_version_number("HORIZ_INTERP_BICUBIC_MOD", version)
module_is_initialized = .true.
tpi = 2.0*PI
end subroutine horiz_interp_bicubic_init
!
!#######################################################################
!
!
! Initialization routine.
!
!
! Allocates space and initializes a derived-type variable
! that contains pre-computed interpolation indices and weights.
!
!
! call horiz_interp_bicubic_new ( Interp, lon_in, lat_in, lon_out, lat_out, verbose_bicubic, src_modulo )
!
!
!
! Longitude (in radians) for source data grid.
!
!
! Latitude (in radians) for source data grid.
!
!
! Longitude (in radians) for source data grid.
!
!
! Latitude (in radians) for source data grid.
!
!
! logical variable to indicate if the boundary condition along zonal boundary
! is cyclic or not. When true, the zonal boundary condition is cyclic.
!
!
! flag for the amount of print output.
!
!
! A derived-type variable containing indices and weights used for subsequent
! interpolations. To reinitialize this variable for a different grid-to-grid
! interpolation you must first use the "horiz_interp_bicubic_del" interface.
!
subroutine horiz_interp_bicubic_new_1d_s ( Interp, lon_in, lat_in, lon_out, lat_out, &
verbose, src_modulo )
!-----------------------------------------------------------------------
type(horiz_interp_type), intent(inout) :: Interp
real, intent(in), dimension(:) :: lon_in , lat_in
real, intent(in), dimension(:,:) :: lon_out, lat_out
integer, intent(in), optional :: verbose
logical, intent(in), optional :: src_modulo
integer :: i, j, ip1, im1, jp1, jm1
logical :: src_is_modulo
integer :: nlon_in, nlat_in, nlon_out, nlat_out
integer :: jcl, jcu, icl, icu, jj
real :: xz, yz
integer :: unit
if(present(verbose)) verbose_bicubic = verbose
src_is_modulo = .false.
if (present(src_modulo)) src_is_modulo = src_modulo
if(size(lon_out,1) /= size(lat_out,1) .or. size(lon_out,2) /= size(lat_out,2) ) &
call mpp_error(FATAL,'horiz_interp_bilinear_mod: when using bilinear ' // &
'interplation, the output grids should be geographical grids')
!--- get the grid size
nlon_in = size(lon_in) ; nlat_in = size(lat_in)
nlon_out = size(lon_out,1); nlat_out = size(lat_out,2)
Interp%nlon_src = nlon_in; Interp%nlat_src = nlat_in
Interp%nlon_dst = nlon_out; Interp%nlat_dst = nlat_out
! use wti(:,:,1) for x-derivative, wti(:,:,2) for y-derivative, wti(:,:,3) for xy-derivative
allocate ( Interp%wti (nlon_in, nlat_in, 3) )
allocate ( Interp%lon_in (nlon_in) )
allocate ( Interp%lat_in (nlat_in) )
allocate ( Interp%rat_x (nlon_out, nlat_out) )
allocate ( Interp%rat_y (nlon_out, nlat_out) )
allocate ( Interp%i_lon (nlon_out, nlat_out, 2) )
allocate ( Interp%j_lat (nlon_out, nlat_out, 2) )
Interp%lon_in = lon_in
Interp%lat_in = lat_in
if ( verbose_bicubic > 0 ) then
unit = stdout()
write (unit,'(/,"Initialising bicubic interpolation, interface horiz_interp_bicubic_new_1d_s")')
write (unit,'(/," Longitude of coarse grid points (radian): xc(i) i=1, ",i4)') Interp%nlon_src
write (unit,'(1x,10f10.4)') (Interp%lon_in(jj),jj=1,Interp%nlon_src)
write (unit,'(/," Latitude of coarse grid points (radian): yc(j) j=1, ",i4)') Interp%nlat_src
write (unit,'(1x,10f10.4)') (Interp%lat_in(jj),jj=1,Interp%nlat_src)
do i=1, Interp%nlat_dst
write (unit,*)
write (unit,'(/," Longitude of fine grid points (radian): xf(i) i=1, ",i4)') Interp%nlat_dst
write (unit,'(1x,10f10.4)') (lon_out(jj,i),jj=1,Interp%nlon_dst)
enddo
do i=1, Interp%nlon_dst
write (unit,*)
write (unit,'(/," Latitude of fine grid points (radian): yf(j) j=1, ",i4)') Interp%nlon_dst
write (unit,'(1x,10f10.4)') (lat_out(i,jj),jj=1,Interp%nlat_dst)
enddo
endif
!---------------------------------------------------------------------------
! Find the x-derivative. Use central differences and forward or
! backward steps at the boundaries
do j=1,nlat_in
do i=1,nlon_in
ip1=min(i+1,nlon_in)
im1=max(i-1,1)
Interp%wti(i,j,1) = 1./(Interp%lon_in(ip1)-Interp%lon_in(im1))
enddo
enddo
!---------------------------------------------------------------------------
! Find the y-derivative. Use central differences and forward or
! backward steps at the boundaries
do j=1,nlat_in
jp1=min(j+1,nlat_in)
jm1=max(j-1,1)
do i=1,nlon_in
Interp%wti(i,j,2) = 1./(Interp%lat_in(jp1)-Interp%lat_in(jm1))
enddo
enddo
!---------------------------------------------------------------------------
! Find the xy-derivative. Use central differences and forward or
! backward steps at the boundaries
do j=1,nlat_in
jp1=min(j+1,nlat_in)
jm1=max(j-1,1)
do i=1,nlon_in
ip1=min(i+1,nlon_in)
im1=max(i-1,1)
Interp%wti(i,j,3) = 1./((Interp%lon_in(ip1)-Interp%lon_in(im1))*(Interp%lat_in(jp1)-Interp%lat_in(jm1)))
enddo
enddo
!---------------------------------------------------------------------------
! Now for each point at the dest-grid find the boundary points of
! the source grid
do j=1, nlat_out
do i=1,nlon_out
yz = lat_out(i,j)
xz = lon_out(i,j)
jcl = 0
jcu = 0
if( yz .le. Interp%lat_in(1) ) then
jcl = 1
jcu = 1
else if( yz .ge. Interp%lat_in(nlat_in) ) then
jcl = nlat_in
jcu = nlat_in
else
jcl = indl(Interp%lat_in, yz)
jcu = indu(Interp%lat_in, yz)
endif
icl = 0
icu = 0
!--- cyclic condition, do we need to use do while
if( xz .gt. Interp%lon_in(nlon_in) ) xz = xz - tpi
if( xz .le. Interp%lon_in(1) ) xz = xz + tpi
if( xz .ge. Interp%lon_in(nlon_in) ) then
icl = nlon_in
icu = 1
Interp%rat_x(i,j) = (xz - Interp%lon_in(icl))/(Interp%lon_in(icu) - Interp%lon_in(icl) + tpi)
else
icl = indl(Interp%lon_in, xz)
icu = indu(Interp%lon_in, xz)
Interp%rat_x(i,j) = (xz - Interp%lon_in(icl))/(Interp%lon_in(icu) - Interp%lon_in(icl))
endif
Interp%j_lat(i,j,1) = jcl
Interp%j_lat(i,j,2) = jcu
Interp%i_lon(i,j,1) = icl
Interp%i_lon(i,j,2) = icu
if(jcl == jcu) then
Interp%rat_y(i,j) = 0.0
else
Interp%rat_y(i,j) = (yz - Interp%lat_in(jcl))/(Interp%lat_in(jcu) - Interp%lat_in(jcl))
endif
! if(yz.gt.Interp%lat_in(jcu)) call mpp_error(FATAL, ' horiz_interp_bicubic_new_1d_s: yf < ycl, no valid boundary point')
! if(yz.lt.Interp%lat_in(jcl)) call mpp_error(FATAL, ' horiz_interp_bicubic_new_1d_s: yf > ycu, no valid boundary point')
! if(xz.gt.Interp%lon_in(icu)) call mpp_error(FATAL, ' horiz_interp_bicubic_new_1d_s: xf < xcl, no valid boundary point')
! if(xz.lt.Interp%lon_in(icl)) call mpp_error(FATAL, ' horiz_interp_bicubic_new_1d_s: xf > xcu, no valid boundary point')
enddo
enddo
end subroutine horiz_interp_bicubic_new_1d_s
!
subroutine horiz_interp_bicubic_new_1d ( Interp, lon_in, lat_in, lon_out, lat_out, &
verbose, src_modulo )
!-----------------------------------------------------------------------
type(horiz_interp_type), intent(inout) :: Interp
real, intent(in), dimension(:) :: lon_in , lat_in
real, intent(in), dimension(:) :: lon_out, lat_out
integer, intent(in), optional :: verbose
logical, intent(in), optional :: src_modulo
integer :: i, j, ip1, im1, jp1, jm1
logical :: src_is_modulo
integer :: nlon_in, nlat_in, nlon_out, nlat_out
integer :: jcl, jcu, icl, icu, jj
real :: xz, yz
integer :: unit
if(present(verbose)) verbose_bicubic = verbose
src_is_modulo = .false.
if (present(src_modulo)) src_is_modulo = src_modulo
!--- get the grid size
nlon_in = size(lon_in) ; nlat_in = size(lat_in)
nlon_out = size(lon_out); nlat_out = size(lat_out)
Interp%nlon_src = nlon_in; Interp%nlat_src = nlat_in
Interp%nlon_dst = nlon_out; Interp%nlat_dst = nlat_out
allocate ( Interp%wti (nlon_in, nlat_in, 3) )
allocate ( Interp%lon_in (nlon_in) )
allocate ( Interp%lat_in (nlat_in) )
allocate ( Interp%rat_x (nlon_out, nlat_out) )
allocate ( Interp%rat_y (nlon_out, nlat_out) )
allocate ( Interp%i_lon (nlon_out, nlat_out, 2) )
allocate ( Interp%j_lat (nlon_out, nlat_out, 2) )
Interp%lon_in = lon_in
Interp%lat_in = lat_in
if ( verbose_bicubic > 0 ) then
unit = stdout()
write (unit,'(/,"Initialising bicubic interpolation, interface horiz_interp_bicubic_new_1d")')
write (unit,'(/," Longitude of coarse grid points (radian): xc(i) i=1, ",i4)') Interp%nlon_src
write (unit,'(1x,10f10.4)') (Interp%lon_in(jj),jj=1,Interp%nlon_src)
write (unit,'(/," Latitude of coarse grid points (radian): yc(j) j=1, ",i4)') Interp%nlat_src
write (unit,'(1x,10f10.4)') (Interp%lat_in(jj),jj=1,Interp%nlat_src)
write (unit,*)
write (unit,'(/," Longitude of fine grid points (radian): xf(i) i=1, ",i4)') Interp%nlat_dst
write (unit,'(1x,10f10.4)') (lon_out(jj),jj=1,Interp%nlon_dst)
write (unit,'(/," Latitude of fine grid points (radian): yf(j) j=1, ",i4)') Interp%nlon_dst
write (unit,'(1x,10f10.4)') (lat_out(jj),jj=1,Interp%nlat_dst)
endif
!---------------------------------------------------------------------------
! Find the x-derivative. Use central differences and forward or
! backward steps at the boundaries
do j=1,nlat_in
do i=1,nlon_in
ip1=min(i+1,nlon_in)
im1=max(i-1,1)
Interp%wti(i,j,1) = 1./(lon_in(ip1)-lon_in(im1))
enddo
enddo
!---------------------------------------------------------------------------
! Find the y-derivative. Use central differences and forward or
! backward steps at the boundaries
do j=1,nlat_in
jp1=min(j+1,nlat_in)
jm1=max(j-1,1)
do i=1,nlon_in
Interp%wti(i,j,2) = 1./(lat_in(jp1)-lat_in(jm1))
enddo
enddo
!---------------------------------------------------------------------------
! Find the xy-derivative. Use central differences and forward or
! backward steps at the boundaries
do j=1,nlat_in
jp1=min(j+1,nlat_in)
jm1=max(j-1,1)
do i=1,nlon_in
ip1=min(i+1,nlon_in)
im1=max(i-1,1)
Interp%wti(i,j,3) = 1./((lon_in(ip1)-lon_in(im1))*(lat_in(jp1)-lat_in(jm1)))
enddo
enddo
!---------------------------------------------------------------------------
! Now for each point at the dest-grid find the boundary points of
! the source grid
do j=1, nlat_out
yz = lat_out(j)
jcl = 0
jcu = 0
if( yz .le. lat_in(1) ) then
jcl = 1
jcu = 1
else if( yz .ge. lat_in(nlat_in) ) then
jcl = nlat_in
jcu = nlat_in
else
jcl = indl(lat_in, yz)
jcu = indu(lat_in, yz)
endif
do i=1,nlon_out
xz = lon_out(i)
icl = 0
icu = 0
!--- cyclic condition, do we need to use do while
if( xz .gt. lon_in(nlon_in) ) xz = xz - tpi
if( xz .le. lon_in(1) ) xz = xz + tpi
if( xz .ge. lon_in(nlon_in) ) then
icl = nlon_in
icu = 1
Interp%rat_x(i,j) = (xz - Interp%lon_in(icl))/(Interp%lon_in(icu) - Interp%lon_in(icl) + tpi)
else
icl = indl(lon_in, xz)
icu = indu(lon_in, xz)
Interp%rat_x(i,j) = (xz - Interp%lon_in(icl))/(Interp%lon_in(icu) - Interp%lon_in(icl))
endif
icl = indl(lon_in, xz)
icu = indu(lon_in, xz)
Interp%j_lat(i,j,1) = jcl
Interp%j_lat(i,j,2) = jcu
Interp%i_lon(i,j,1) = icl
Interp%i_lon(i,j,2) = icu
if(jcl == jcu) then
Interp%rat_y(i,j) = 0.0
else
Interp%rat_y(i,j) = (yz - Interp%lat_in(jcl))/(Interp%lat_in(jcu) - Interp%lat_in(jcl))
endif
! if(yz.gt.lat_in(jcu)) call mpp_error(FATAL, ' horiz_interp_bicubic_new_1d: yf < ycl, no valid boundary point')
! if(yz.lt.lat_in(jcl)) call mpp_error(FATAL, ' horiz_interp_bicubic_new_1d: yf > ycu, no valid boundary point')
! if(xz.gt.lon_in(icu)) call mpp_error(FATAL, ' horiz_interp_bicubic_new_1d: xf < xcl, no valid boundary point')
! if(xz.lt.lon_in(icl)) call mpp_error(FATAL, ' horiz_interp_bicubic_new_1d: xf > xcu, no valid boundary point')
enddo
enddo
end subroutine horiz_interp_bicubic_new_1d
subroutine horiz_interp_bicubic( Interp, data_in, data_out, verbose, mask_in, mask_out, missing_value, missing_permit)
type (horiz_interp_type), intent(in) :: Interp
real, intent(in), dimension(:,:) :: data_in
real, intent(out), dimension(:,:) :: data_out
integer, intent(in), optional :: verbose
real, intent(in), dimension(:,:), optional :: mask_in
real, intent(out), dimension(:,:), optional :: mask_out
real, intent(in), optional :: missing_value
integer, intent(in), optional :: missing_permit
real :: yz, ycu, ycl
real :: xz, xcu, xcl
real :: val, val1, val2
real, dimension(4) :: y, y1, y2, y12
integer :: icl, icu, jcl, jcu
integer :: iclp1, icup1, jclp1, jcup1
integer :: iclm1, icum1, jclm1, jcum1
integer :: i,j
if ( present(verbose) ) verbose_bicubic = verbose
! fill_in = .false.
! if ( present(fill) ) fill_in = fill
! use dfc_x and dfc_y as workspace
! if ( fill_in ) call fill_xy(fc(ics:ice,jcs:jce), ics, ice, jcs, jce, maxpass=2)
! where ( data_in .le. missing ) data_in(:,:) = 0.
!!
do j=1, Interp%nlat_dst
do i=1, Interp%nlon_dst
yz = Interp%rat_y(i,j)
xz = Interp%rat_x(i,j)
jcl = Interp%j_lat(i,j,1)
jcu = Interp%j_lat(i,j,2)
icl = Interp%i_lon(i,j,1)
icu = Interp%i_lon(i,j,2)
if( icl > icu ) then
iclp1 = icu
icum1 = icl
xcl = Interp%lon_in(icl)
xcu = Interp%lon_in(icu)+tpi
else
iclp1 = min(icl+1,Interp%nlon_src)
icum1 = max(icu-1,1)
xcl = Interp%lon_in(icl)
xcu = Interp%lon_in(icu)
endif
iclm1 = max(icl-1,1)
icup1 = min(icu+1,Interp%nlon_src)
jclp1 = min(jcl+1,Interp%nlat_src)
jclm1 = max(jcl-1,1)
jcup1 = min(jcu+1,Interp%nlat_src)
jcum1 = max(jcu-1,1)
ycl = Interp%lat_in(jcl)
ycu = Interp%lat_in(jcu)
! xcl = Interp%lon_in(icl)
! xcu = Interp%lon_in(icu)
y(1) = data_in(icl,jcl)
y(2) = data_in(icu,jcl)
y(3) = data_in(icu,jcu)
y(4) = data_in(icl,jcu)
y1(1) = ( data_in(iclp1,jcl) - data_in(iclm1,jcl) ) * Interp%wti(icl,jcl,1)
y1(2) = ( data_in(icup1,jcl) - data_in(icum1,jcl) ) * Interp%wti(icu,jcl,1)
y1(3) = ( data_in(icup1,jcu) - data_in(icum1,jcu) ) * Interp%wti(icu,jcu,1)
y1(4) = ( data_in(iclp1,jcu) - data_in(iclm1,jcu) ) * Interp%wti(icl,jcu,1)
y2(1) = ( data_in(icl,jclp1) - data_in(icl,jclm1) ) * Interp%wti(icl,jcl,2)
y2(2) = ( data_in(icu,jclp1) - data_in(icu,jclm1) ) * Interp%wti(icu,jcl,2)
y2(3) = ( data_in(icu,jcup1) - data_in(icu,jcum1) ) * Interp%wti(icu,jcu,2)
y2(4) = ( data_in(icl,jcup1) - data_in(icl,jcum1) ) * Interp%wti(icl,jcu,2)
y12(1)= ( data_in(iclp1,jclp1) + data_in(iclm1,jclm1) - data_in(iclm1,jclp1) &
- data_in(iclp1,jclm1) ) * Interp%wti(icl,jcl,3)
y12(2)= ( data_in(icup1,jclp1) + data_in(icum1,jclm1) - data_in(icum1,jclp1) &
- data_in(icup1,jclm1) ) * Interp%wti(icu,jcl,3)
y12(3)= ( data_in(icup1,jcup1) + data_in(icum1,jcum1) - data_in(icum1,jcup1) &
- data_in(icup1,jcum1) ) * Interp%wti(icu,jcu,3)
y12(4)= ( data_in(iclp1,jcup1) + data_in(iclm1,jcum1) - data_in(iclm1,jcup1) &
- data_in(iclp1,jcum1) ) * Interp%wti(icl,jcu,3)
call bcuint(y,y1,y2,y12,xcl,xcu,ycl,ycu,xz,yz,val,val1,val2)
data_out (i,j) = val
if(present(mask_out)) mask_out(i,j) = 1.
!! dff_x(i,j) = val1
!! dff_y(i,j) = val2
enddo
enddo
return
end subroutine horiz_interp_bicubic
!---------------------------------------------------------------------------
subroutine bcuint(y,y1,y2,y12,x1l,x1u,x2l,x2u,t,u,ansy,ansy1,ansy2)
real ansy,ansy1,ansy2,x1l,x1u,x2l,x2u,y(4),y1(4),y12(4),y2(4)
! uses bcucof
integer i
real t,u,c(4,4)
call bcucof(y,y1,y2,y12,x1u-x1l,x2u-x2l,c)
ansy=0.
ansy2=0.
ansy1=0.
do i=4,1,-1
ansy=t*ansy+((c(i,4)*u+c(i,3))*u+c(i,2))*u+c(i,1)
! ansy2=t*ansy2+(3.*c(i,4)*u+2.*c(i,3))*u+c(i,2)
! ansy1=u*ansy1+(3.*c(4,i)*t+2.*c(3,i))*t+c(2,i)
enddo
! ansy1=ansy1/(x1u-x1l) ! could be used for accuracy checks
! ansy2=ansy2/(x2u-x2l) ! could be used for accuracy checks
return
! (c) copr. 1986-92 numerical recipes software -3#(-)f.
end subroutine bcuint
!---------------------------------------------------------------------------
subroutine bcucof(y,y1,y2,y12,d1,d2,c)
real d1,d2,c(4,4),y(4),y1(4),y12(4),y2(4)
integer i,j,k,l
real d1d2,xx,cl(16),wt(16,16),x(16)
save wt
data wt/1., 0., -3., 2., 4*0., -3., 0., 9., -6., 2., 0., -6., 4., 8*0., &
3., 0., -9., 6., -2., 0., 6., -4., 10*0., 9., -6., 2*0., -6., &
4., 2*0., 3., -2., 6*0., -9., 6., 2*0., 6., -4., 4*0., 1., 0., &
-3., 2., -2., 0., 6., -4., 1., 0., -3., 2., 8*0., -1., 0., 3., &
-2., 1., 0., -3., 2., 10*0., -3., 2., 2*0., 3., -2., 6*0., 3., &
-2., 2*0., -6., 4., 2*0., 3., -2., 0., 1., -2., 1., 5*0., -3., &
6., -3., 0., 2., -4., 2., 9*0., 3., -6., 3., 0., -2., 4., -2., &
10*0., -3., 3., 2*0., 2., -2., 2*0., -1., 1., 6*0., 3., -3., &
2*0., -2., 2., 5*0., 1., -2., 1., 0., -2., 4., -2., 0., 1., -2., &
1., 9*0., -1., 2., -1., 0., 1., -2., 1., 10*0., 1., -1., 2*0., &
-1., 1., 6*0., -1., 1., 2*0., 2., -2., 2*0., -1., 1./
d1d2=d1*d2
do i=1,4
x(i)=y(i)
x(i+4)=y1(i)*d1
x(i+8)=y2(i)*d2
x(i+12)=y12(i)*d1d2
enddo
do i=1,16
xx=0.
do k=1,16
xx=xx+wt(i,k)*x(k)
enddo
cl(i)=xx
enddo
l=0
do i=1,4
do j=1,4
l=l+1
c(i,j)=cl(l)
enddo
enddo
return
! (c) copr. 1986-92 numerical recipes software -3#(-)f.
end subroutine bcucof
!-----------------------------------------------------------------------
function indl(xc, xf)
! find the lower neighbour of xf in field xc, return is the index
real, intent(in) :: xc(1:)
real, intent(in) :: xf
integer :: indl
integer :: ii
indl = 1
do ii=1, size(xc)
if(xc(ii).gt.xf) return
indl = ii
enddo
call mpp_error(FATAL,'Error in indl')
return
end function indl
!-----------------------------------------------------------------------
function indu(xc, xf)
! find the upper neighbour of xf in field xc, return is the index
real, intent(in) :: xc(1:)
real, intent(in) :: xf
integer :: indu
integer :: ii
do ii=1, size(xc)
indu = ii
if(xc(ii).gt.xf) return
enddo
call mpp_error(FATAL,'Error in indu')
return
end function indu
!-----------------------------------------------------------------------
subroutine fill_xy(fi, ics, ice, jcs, jce, mask, maxpass)
integer, intent(in) :: ics,ice,jcs,jce
real, intent(inout) :: fi(ics:ice,jcs:jce)
real, intent(in), optional :: mask(ics:ice,jcs:jce)
integer, intent(in) :: maxpass
real :: work_old(ics:ice,jcs:jce)
real :: work_new(ics:ice,jcs:jce)
logical :: ready
real :: blank = -1.e30
real :: tavr
integer :: ipass = 0
integer :: inl, inr, jnl, jnu, i, j, is, js, iavr
ready = .false.
work_new(:,:) = fi(:,:)
work_old(:,:) = work_new(:,:)
ipass = 0
if ( present(mask) ) then
do while (.not.ready)
ipass = ipass+1
ready = .true.
do j=jcs, jce
do i=ics, ice
if (work_old(i,j).le.blank) then
tavr=0.
iavr=0
inl = max(i-1,ics)
inr = min(i+1,ice)
jnl = max(j-1,jcs)
jnu = min(j+1,jce)
do js=jnl,jnu
do is=inl,inr
if (work_old(is,js) .ne. blank .and. mask(is,js).ne.0.) then
tavr = tavr + work_old(is,js)
iavr = iavr+1
endif
enddo
enddo
if (iavr.gt.0) then
if (iavr.eq.1) then
! spreading is not allowed if the only valid neighbor is a corner point
! otherwise an ill posed cellular automaton is established leading to
! a spreading of constant values in diagonal direction
! if all corner points are blanked the valid neighbor must be a direct one
! and spreading is allowed
if (work_old(inl,jnu).eq.blank.and.&
work_old(inr,jnu).eq.blank.and.&
work_old(inr,jnl).eq.blank.and.&
work_old(inl,jnl).eq.blank) then
work_new(i,j)=tavr/iavr
ready = .false.
endif
else
work_new(i,j)=tavr/iavr
ready = .false.
endif
endif
endif
enddo ! j
enddo ! i
! save changes made during this pass to work_old
work_old(:,:)=work_new(:,:)
if(ipass.eq.maxpass) ready=.true.
enddo !while (.not.ready)
fi(:,:) = work_new(:,:)
else
do while (.not.ready)
ipass = ipass+1
ready = .true.
do j=jcs, jce
do i=ics, ice
if (work_old(i,j).le.blank) then
tavr=0.
iavr=0
inl = max(i-1,ics)
inr = min(i+1,ice)
jnl = max(j-1,jcs)
jnu = min(j+1,jce)
do is=inl,inr
do js=jnl,jnu
if (work_old(is,js).gt.blank) then
tavr = tavr + work_old(is,js)
iavr = iavr+1
endif
enddo
enddo
if (iavr.gt.0) then
if (iavr.eq.1) then
! spreading is not allowed if the only valid neighbor is a corner point
! otherwise an ill posed cellular automaton is established leading to
! a spreading of constant values in diagonal direction
! if all corner points are blanked the valid neighbor must be a direct one
! and spreading is allowed
if (work_old(inl,jnu).le.blank.and. &
work_old(inr,jnu).le.blank.and. &
work_old(inr,jnl).le.blank.and. &
work_old(inl,jnl).le.blank) then
work_new(i,j)=tavr/iavr
ready = .false.
endif
else
work_new(i,j)=tavr/iavr
ready = .false.
endif
endif
endif
enddo ! j
enddo ! i
! save changes made during this pass to work_old
work_old(:,:)=work_new(:,:)
if(ipass.eq.maxpass) ready=.true.
enddo !while (.not.ready)
fi(:,:) = work_new(:,:)
endif
return
end subroutine fill_xy
subroutine horiz_interp_bicubic_del( Interp )
type (horiz_interp_type), intent(inout) :: Interp
if(associated(Interp%rat_x)) deallocate ( Interp%rat_x )
if(associated(Interp%rat_y)) deallocate ( Interp%rat_y )
if(associated(Interp%lon_in)) deallocate ( Interp%lon_in )
if(associated(Interp%lat_in)) deallocate ( Interp%lat_in )
if(associated(Interp%i_lon)) deallocate ( Interp%i_lon )
if(associated(Interp%j_lat)) deallocate ( Interp%j_lat )
if(associated(Interp%wti)) deallocate ( Interp%wti )
end subroutine horiz_interp_bicubic_del
end module horiz_interp_bicubic_mod