!*********************************************************************** !* 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 . !*********************************************************************** ! nf95 -r8 -g -I ~/regression/ia64/23-Jun-2005/CM2.1U_Control-1990_E1.k32pe/include/ -D_TEST_CLOUD_INTERPOLATOR -D_F95 cloud_interpolator.F90 #define _FLATTEN(A) reshape((A), (/size((A))/) ) MODULE cloud_interpolator_mod #include implicit none private public :: cld_ntrp_linear_cell_interp, cld_ntrp_locate_cell, cld_ntrp_get_cell_values public :: cld_ntrp_expand_index, cld_ntrp_contract_indices ! Include variable "version" to be written to log file. #include real, parameter :: tol = 10.0*epsilon(1.) CONTAINS !............................................................................... pure subroutine cld_ntrp_expand_index(Ic, ie, ier) integer, intent(in) :: Ic ! contacted index integer, intent(out) :: ie(:) ! expanded list of indices integer, intent(out) :: ier ! error flag (0=ok) integer j, nd ier = 0 nd = size(ie) ! dimension if(Ic >= 2**nd) then ie = -1 ier = 1 ! error return endif do j = 1, nd ie(j) = mod(Ic/2**(j-1), 2) end do end subroutine cld_ntrp_expand_index !............................................................................... !............................................................................... pure subroutine cld_ntrp_contract_indices(ie, Ic, ier) integer, intent(in) :: ie(:) ! expanded list of indices integer, intent(out) :: Ic ! contacted index integer, intent(out) :: ier ! error flag (0=ok) integer j, nd ier = 0 nd = size(ie) ! dimension Ic = ie(nd) do j = nd-1, 1, -1 Ic = Ic * 2 Ic = Ic + ie(j) end do if(Ic >= 2**nd) ier = 1 end subroutine cld_ntrp_contract_indices !............................................................................... !............................................................................... pure subroutine cld_ntrp_linear_cell_interp(fvals, ts, f, ier) real, intent(in) :: fvals(0:) ! values at the cell nodes real, intent(in) :: ts(:) ! normalized [0,1]^nd cell coordinates real, intent(out):: f ! interpolated value integer, intent(out) :: ier ! error flag (0=ok) integer j, nd, Ic, iflag integer ie(size(fvals)) real basis ier = 0 f = 0. nd = size(ts) if(size(fvals) /= 2**nd) then ier = 1 return endif do Ic = 0, 2**nd - 1 basis = 1. call cld_ntrp_expand_index(Ic, ie, iflag) do j = 1, nd basis = basis * ( (1.0-real(ie(j)))*(1.0-ts(j)) + real(ie(j))*ts(j) ) end do f = f + fvals(Ic)*basis end do end subroutine cld_ntrp_linear_cell_interp !............................................................................... !............................................................................... pure subroutine cld_ntrp_locate_cell(axis, x, index, ier) real, intent(in) :: axis(:) ! axis real, intent(in) :: x ! abscissae integer, intent(out) :: index ! lower-left corner index integer, intent(out) :: ier ! error flag (0=ok) logical down integer n, index1, is real axis_1, axis_n, axis_min, axis_max ier = 0 index = -1 down = .FALSE. n = size(axis) if(n < 2) then ier = 3 return endif axis_1 = axis(1) axis_n = axis(n) axis_min = axis_1 axis_max = axis_n if(axis_1 > axis_n) then down = .TRUE. axis_min = axis_n axis_max = axis_1 endif if(x < axis_min-tol) then ier = 1 return endif if(x > axis_max+tol) then ier = 2 return endif index = floor(real(n-1)*(x - axis_1)/(axis_n-axis_1)) + 1 index = min(n-1, index) index1 = index+1 if(.NOT. down) then if(axis(index) <= x+tol) then if(x <= axis(index1)+tol) then ! axis is uniform, or nearly so. Done! return else ! increase index is = index+1 do index = is, n-1 index1 = index+1 if(axis(index1) >= x-tol) return enddo endif else ! decrease index is = index - 1 do index = is, 1, -1 if(axis(index) <= x+tol) return enddo endif else ! axis is pointing down if(axis(index) >= x-tol) then if(x >= axis(index1)-tol) then ! axis is uniform, or nearly so. Done! return else ! increase index is = index + 1 do index = is, n-1 index1 = index+1 if(axis(index1) <= x+tol) return enddo endif else ! decrease index is = index - 1 do index = is, 1, -1 if(axis(index) >= x-tol) return enddo endif endif end subroutine cld_ntrp_locate_cell !............................................................................... !............................................................................... pure subroutine cld_ntrp_get_flat_index(nsizes, indices, flat_index, ier) integer, intent(in) :: nsizes(:) ! size of array along each axis integer, intent(in) :: indices(:) ! cell indices integer, intent(out) :: flat_index ! index into flattened array integer, intent(out) :: ier ! error flag (0=ok) integer nd, id ier = 0 flat_index = -1 nd = size(nsizes) if(nd /= size(indices)) then ! size mismatch ier = 1 return endif flat_index = indices(nd)-1 do id = nd-1, 1, -1 flat_index = flat_index*nsizes(id) + indices(id)-1 enddo flat_index = flat_index + 1 end subroutine cld_ntrp_get_flat_index !............................................................................... !............................................................................... pure subroutine cld_ntrp_get_cell_values(nsizes, fnodes, indices, fvals, ier) integer, intent(in) :: nsizes(:) ! size of fnodes along each axis real, intent(in) :: fnodes(:) ! flattened array of node values integer, intent(in) :: indices(:) ! cell indices real, intent(out) :: fvals(0:) ! returned array values in the cell integer, intent(out) :: ier ! error flag (0=ok) integer id, nt, nd, flat_index, Ic, iflag integer, dimension(size(nsizes)) :: cell_indices, node_indices ier = 0 fvals = 0. nd = size(nsizes) if(nd /= size(indices)) then ! size mismatch ier = 1 return endif if(2**nd > size(fvals)) then ! not enough elements to hold result ier = 2 return endif nt = 1 do id = 1, nd nt = nt * nsizes(id) enddo if(nt /= size(fnodes)) then ! not enough node values ier = 3 return endif do Ic = 0, 2**nd-1 call cld_ntrp_expand_index(Ic, cell_indices, iflag) node_indices = indices + cell_indices call cld_ntrp_get_flat_index(nsizes, node_indices, flat_index, iflag) fvals(Ic) = fnodes(flat_index) enddo end subroutine cld_ntrp_get_cell_values end MODULE cloud_interpolator_mod !===============================================================================