FV3 Bundle
horiz_interp.F90
Go to the documentation of this file.
1 !***********************************************************************
2 !* GNU Lesser General Public License
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
10 !*
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 !* for more details.
15 !*
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
20 
21 ! <CONTACT EMAIL="Zhi.Liang@noaa.gov"> Zhi Liang </CONTACT>
22 ! <CONTACT EMAIL="Bruce.Wyman@noaa.gov"> Bruce Wyman </CONTACT>
23 
24 ! <HISTORY SRC="http://www.gfdl.noaa.gov/fms-cgi-bin/cvsweb.cgi/FMS/"/>
25 
26 ! <OVERVIEW>
27 ! Performs spatial interpolation between grids.
28 ! </OVERVIEW>
29 
30 ! <DESCRIPTION>
31 ! This module can interpolate data from any logically rectangular grid
32 ! to any logically rectangular grid. Four interpolation schems are used here:
33 ! conservative, bilinear, bicubic and inverse of square distance weighted.
34 ! The four interpolation schemes are implemented seperately in
35 ! horiz_interp_conserver_mod, horiz_interp_blinear_mod, horiz_interp_bicubic_mod
36 ! and horiz_interp_spherical_mod. bicubic interpolation requires the source grid
37 ! is regular lon/lat grid. User can choose the interpolation method in the
38 ! public interface horiz_interp_new through optional argument interp_method,
39 ! with acceptable value "conservative", "bilinear", "bicubic" and "spherical".
40 ! The default value is "conservative". There is an optional mask field for
41 ! missing input data. An optional output mask field may be used in conjunction with
42 ! the input mask to show where output data exists.
43 ! </DESCRIPTION>
44 
45 !-----------------------------------------------------------------------
46 !
47 ! Performs spatial interpolation between grids.
48 !
49 !-----------------------------------------------------------------------
50 
51 use fms_mod, only: write_version_number, fms_error_handler
52 use fms_mod, only: file_exist, close_file
53 use fms_mod, only: check_nml_error, open_namelist_file
54 use mpp_mod, only: mpp_error, fatal, stdout, stdlog, mpp_min
55 use mpp_mod, only: input_nml_file, warning, mpp_pe, mpp_root_pe
56 use constants_mod, only: pi
57 use horiz_interp_type_mod, only: horiz_interp_type, assignment(=)
67 
68  implicit none
69  private
70 
71 !---- interfaces ----
72 
74  horiz_interp_init, horiz_interp_end, assignment(=)
75 
76 ! <INTERFACE NAME="horiz_interp_new">
77 ! <OVERVIEW>
78 ! Allocates space and initializes a derived-type variable
79 ! that contains pre-computed interpolation indices and weights.
80 ! </OVERVIEW>
81 ! <DESCRIPTION>
82 ! Allocates space and initializes a derived-type variable
83 ! that contains pre-computed interpolation indices and weights
84 ! for improved performance of multiple interpolations between
85 ! the same grids. This routine does not need to be called if you
86 ! are doing a single grid-to-grid interpolation.
87 ! </DESCRIPTION>
88 ! <IN NAME="lon_in" TYPE="real" DIM="dimension(:), dimension(:,:)" UNITS="radians">
89 ! Longitude (in radians) for source data grid. You can pass 1-D lon_in to
90 ! represent the geographical longitude of regular lon/lat grid, or just
91 ! pass geographical longitude(lon_in is 2-D). The grid location may be
92 ! located at grid cell edge or center, decided by optional argument "grid_at_center".
93 ! </IN>
94 ! <IN NAME="lat_in" TYPE="real" DIM="dimension(:), dimension(:,:)" UNITS="radians">
95 ! Latitude (in radians) for source data grid. You can pass 1-D lat_in to
96 ! represent the geographical latitude of regular lon/lat grid, or just
97 ! pass geographical latitude(lat_in is 2-D). The grid location may be
98 ! located at grid cell edge or center, decided by optional argument "grid_at_center".
99 ! </IN>
100 ! <IN NAME="lon_out" TYPE="real" DIM="dimension(:), dimension(:,:)" UNITS="radians" >
101 ! Longitude (in radians) for destination data grid. You can pass 1-D lon_out to
102 ! represent the geographical longitude of regular lon/lat grid, or just
103 ! pass geographical longitude(lon_out is 2-D). The grid location may be
104 ! located at grid cell edge or center, decided by optional argument "grid_at_center".
105 ! </IN>
106 ! <IN NAME="lat_out" TYPE="real" DIM="dimension(:), dimension(:,:)" UNITS="radians" >
107 ! Latitude (in radians) for destination data grid. You can pass 1-D lat_out to
108 ! represent the geographical latitude of regular lon/lat grid, or just
109 ! pass geographical latitude(lat_out is 2-D). The grid location may be
110 ! located at grid cell edge or center, decided by optional argument "grid_at_center".
111 ! </IN>
112 ! <IN NAME="verbose" TYPE="integer">
113 ! Integer flag that controls the amount of printed output.
114 ! verbose = 0, no output; = 1, min,max,means; = 2, still more
115 ! </IN>
116 ! <IN NAME="interp_method" TYPE="character(len=*)" >
117 ! interpolation method, = "conservative", using conservation scheme,
118 ! = "bilinear", using bilinear interpolation, = "spherical",using spherical regrid.
119 ! = "bicubic", using bicubic interpolation. The default value is "convervative".
120 ! </IN>
121 ! <IN NAME = "src_modulo" >
122 ! Indicate the source data grid is cyclic or not.
123 ! </IN>
124 ! <IN NAME = "grid_at_center" >
125 ! Indicate the data is on the center of grid box or the edge of grid box.
126 ! When true, the data is on the center of grid box. default vaule is false.
127 ! This option is only available when interp_method = "bilinear" or "bicubic".
128 ! </IN>
129 ! <OUT NAME="Interp" >
130 ! A derived-type variable containing indices and weights used for subsequent
131 ! interpolations. To reinitialize this variable for a different grid-to-grid
132 ! interpolation you must first use the "horiz_interp_del" interface.
133 ! </OUT>
134 
136  module procedure horiz_interp_new_1d ! Source grid is 1d, destination grid is 1d
137  module procedure horiz_interp_new_1d_src ! Source grid is 1d, destination grid is 2d
138  module procedure horiz_interp_new_2d ! Source grid is 2d, destination grid is 2d
139  module procedure horiz_interp_new_1d_dst ! Source grid is 2d, destination grid is 1d
140  end interface
141 ! </INTERFACE>
142 
143 ! <INTERFACE NAME="horiz_interp">
144 !
145 ! <OVERVIEW>
146 ! Subroutine for performing the horizontal interpolation between two grids.
147 ! </OVERVIEW>
148 ! <DESCRIPTION>
149 ! Subroutine for performing the horizontal interpolation between
150 ! two grids. There are two forms of this interface.
151 ! Form A requires first calling horiz_interp_new, while Form B
152 ! requires no initialization.
153 ! </DESCRIPTION>
154 
155 ! <IN NAME="Interp" >
156 ! Derived-type variable containing interpolation indices and weights.
157 ! Returned by a previous call to horiz_interp_new.
158 ! </IN>
159 ! <IN NAME="data_in">
160 ! Input data on source grid.
161 ! </IN>
162 ! <IN NAME="verbose">
163 ! flag for the amount of print output.
164 ! verbose = 0, no output; = 1, min,max,means; = 2, still more
165 ! </IN>
166 ! <IN NAME="mask_in">
167 ! Input mask, must be the same size as the input data. The real value of
168 ! mask_in must be in the range (0.,1.). Set mask_in=0.0 for data points
169 ! that should not be used or have missing data. It is Not needed for
170 ! spherical regrid.
171 ! </IN>
172 ! <IN NAME="missing_value" >
173 ! Use the missing_value to indicate missing data.
174 ! </IN>
175 ! <IN NAME="missing_permit">
176 ! numbers of points allowed to miss for the bilinear interpolation. The value
177 ! should be between 0 and 3.
178 ! </IN>
179 ! <IN NAME="lon_in, lat_in" >
180 ! longitude and latitude (in radians) of source grid. More explanation can
181 ! be found in the documentation of horiz_interp_new.
182 ! </IN>
183 ! <IN NAME="lon_out, lat_out" >
184 ! longitude and latitude (in radians) of destination grid. More explanation can
185 ! be found in the documentation of horiz_interp_new.
186 ! </IN>
187 ! <OUT NAME="data_out">
188 ! Output data on destination grid.
189 ! </OUT>
190 ! <OUT NAME="mask_out">
191 ! Output mask that specifies whether data was computed.
192 ! </OUT>
193 
194 ! <ERROR MSG="size of input array incorrect" STATUS="FATAL">
195 ! The input data array does not match the size of the input grid edges
196 ! specified. If you are using the initialization interface make sure you
197 ! have the correct grid size.
198 ! </ERROR>
199 ! <ERROR MSG="size of output array incorrect" STATUS="FATAL">
200 ! The output data array does not match the size of the input grid
201 ! edges specified. If you are using the initialization interface make
202 ! sure you have the correct grid size.
203 ! </ERROR>
204 
205  interface horiz_interp
206  module procedure horiz_interp_base_2d
207  module procedure horiz_interp_base_3d
208  module procedure horiz_interp_solo_1d
209  module procedure horiz_interp_solo_1d_src
210  module procedure horiz_interp_solo_2d
211  module procedure horiz_interp_solo_1d_dst
212  module procedure horiz_interp_solo_old
213  end interface
214 ! </INTERFACE>
215 
216 
217  !--- namelist interface
218  !<NAMELIST NAME="horiz_interp_nml">
219  ! <DATA NAME="reproduce_siena" TYPE="logical" DEFAULT=".FALSE." >
220  ! Set reproduce_siena = .true. to reproduce siena results.
221  ! Set reproduce_siena = .false. to decrease truncation error
222  ! in routine poly_area in file mosaic_util.c. The truncation error of
223  ! second order conservative remapping might be big for high resolution
224  ! grid.
225  ! </DATA>
226  !</NAMELIST>
227 
228  logical :: reproduce_siena = .false.
229 
230  namelist /horiz_interp_nml/ reproduce_siena
231 
232 !-----------------------------------------------------------------------
233 ! Include variable "version" to be written to log file.
234 #include<file_version.h>
235  logical :: module_is_initialized = .false.
236 !-----------------------------------------------------------------------
237 
238 contains
239 
240 !#######################################################################
241 ! <SUBROUTINE NAME="horiz_interp_init">
242 ! <OVERVIEW>
243 ! writes version number to logfile.out
244 ! </OVERVIEW>
245 ! <DESCRIPTION>
246 ! writes version number to logfile.out
247 ! </DESCRIPTION>
248 
249  subroutine horiz_interp_init
250  integer :: unit, ierr, io
251 
252  if(module_is_initialized) return
253  call write_version_number("HORIZ_INTERP_MOD", version)
254 
255 #ifdef INTERNAL_FILE_NML
256  read (input_nml_file, horiz_interp_nml, iostat=io)
257  ierr = check_nml_error(io,'horiz_interp_nml')
258 #else
259  if (file_exist('input.nml')) then
260  unit = open_namelist_file( )
261  ierr=1
262  do while (ierr /= 0)
263  read (unit, nml=horiz_interp_nml, iostat=io, end=10)
264  ierr = check_nml_error(io,'horiz_interp_nml') ! also initializes nml error codes
265  enddo
266 10 call close_file (unit)
267  endif
268 #endif
269  if (mpp_pe() == mpp_root_pe() ) then
270  unit = stdlog()
271  write (unit, nml=horiz_interp_nml)
272  endif
273 
274  if( reproduce_siena ) then
275  call mpp_error(fatal, "horiz_interp_mod: You have overridden the default value of reproduce_siena " // &
276  "and set it to .true. in horiz_interp_nml. This is a temporary workaround to " // &
277  "allow for consistency in continuing experiments. Please remove this namelist " )
278  endif
279 
280  call horiz_interp_conserve_init
281  call horiz_interp_bilinear_init
282  call horiz_interp_bicubic_init
283  call horiz_interp_spherical_init
284 
285  module_is_initialized = .true.
286 
287  end subroutine horiz_interp_init
288 
289 ! </SUBROUTINE>
290 
291 !#######################################################################
292 ! <SUBROUTINE NAME="horiz_interp_new_1d" INTERFACE="horiz_interp_new">
293 ! <IN NAME="lon_in" TYPE="real" DIM="(:),(:,:)" UNITS="radians"></IN>
294 ! <IN NAME="lat_in" TYPE="real" DIM="(:),(:,:)"></IN>
295 ! <IN NAME="lon_out" TYPE="real" DIM="(:),(:,:)"></IN>
296 ! <IN NAME="lat_out" TYPE="real" DIM="(:),(:,:)"></IN>
297 ! <IN NAME="verbose" TYPE="integer, optional"></IN>
298 ! <IN NAME="interp_method" TYPE="character(len=*),optional"></IN>
299 ! <IN NAME="src_modulo" TYPE="logical, optional" > </IN>
300 ! <OUT NAME="Interp" TYPE="type(horiz_interp_type)"></OUT>
301 
302 !<PUBLICROUTINE INTERFACE="horiz_interp_new">
303  subroutine horiz_interp_new_1d (Interp, lon_in, lat_in, lon_out, lat_out, verbose, &
304  interp_method, num_nbrs, max_dist, src_modulo, &
305  grid_at_center, mask_in, mask_out)
306 !</PUBLICROUTINE>
307 
308  !-----------------------------------------------------------------------
309  type(horiz_interp_type), intent(inout) :: Interp
310  real, intent(in), dimension(:) :: lon_in , lat_in
311  real, intent(in), dimension(:) :: lon_out, lat_out
312  integer, intent(in), optional :: verbose
313  character(len=*), intent(in), optional :: interp_method
314  integer, intent(in), optional :: num_nbrs
315  real, intent(in), optional :: max_dist
316  logical, intent(in), optional :: src_modulo
317  logical, intent(in), optional :: grid_at_center
318  real, intent(in), dimension(:,:), optional :: mask_in ! dummy
319  real, intent(inout),dimension(:,:), optional :: mask_out ! dummy
320  !-----------------------------------------------------------------------
321  real, dimension(:,:), allocatable :: lon_src, lat_src, lon_dst, lat_dst
322  real, dimension(:), allocatable :: lon_src_1d, lat_src_1d, lon_dst_1d, lat_dst_1d
323  integer :: i, j, nlon_in, nlat_in, nlon_out, nlat_out
324  logical :: center
325  character(len=40) :: method
326  !-----------------------------------------------------------------------
327  call horiz_interp_init
328 
329  method = 'conservative'
330  if(present(interp_method)) method = interp_method
331 
332  select case (trim(method))
333  case ("conservative")
334  interp%interp_method = conserve
335  call horiz_interp_conserve_new ( interp, lon_in, lat_in, lon_out, lat_out, verbose)
336  case ("bilinear")
337  interp%interp_method = bilinear
338  center = .false.
339  if(present(grid_at_center) ) center = grid_at_center
340  if(center) then
341  nlon_out = size(lon_out(:)); nlat_out = size(lat_out(:))
342  allocate(lon_dst(nlon_out,nlat_out), lat_dst(nlon_out,nlat_out))
343  do i = 1, nlon_out
344  lon_dst(i,:) = lon_out(i)
345  enddo
346  do j = 1, nlat_out
347  lat_dst(:,j) = lat_out(j)
348  enddo
349 
350  call horiz_interp_bilinear_new ( interp, lon_in, lat_in, lon_dst, lat_dst, &
351  verbose, src_modulo)
352  deallocate(lon_dst, lat_dst)
353  else
354  nlon_in = size(lon_in(:))-1; nlat_in = size(lat_in(:))-1
355  nlon_out = size(lon_out(:))-1; nlat_out = size(lat_out(:))-1
356  allocate(lon_src_1d(nlon_in), lat_src_1d(nlat_in))
357  allocate(lon_dst(nlon_out,nlat_out), lat_dst(nlon_out,nlat_out))
358  do i = 1, nlon_in
359  lon_src_1d(i) = (lon_in(i) + lon_in(i+1)) * 0.5
360  enddo
361  do j = 1, nlat_in
362  lat_src_1d(j) = (lat_in(j) + lat_in(j+1)) * 0.5
363  enddo
364  do i = 1, nlon_out
365  lon_dst(i,:) = (lon_out(i) + lon_out(i+1)) * 0.5
366  enddo
367  do j = 1, nlat_out
368  lat_dst(:,j) = (lat_out(j) + lat_out(j+1)) * 0.5
369  enddo
370  call horiz_interp_bilinear_new ( interp, lon_src_1d, lat_src_1d, lon_dst, lat_dst, &
371  verbose, src_modulo)
372  deallocate(lon_src_1d, lat_src_1d, lon_dst, lat_dst)
373  endif
374  case ("bicubic")
375  interp%interp_method = bicubic
376  center = .false.
377  if(present(grid_at_center) ) center = grid_at_center
378  !No need to expand to 2d, horiz_interp_bicubic_new does 1d-1d
379  if(center) then
380  call horiz_interp_bicubic_new ( interp, lon_in, lat_in, lon_out, lat_out, &
381  verbose, src_modulo)
382  else
383  nlon_in = size(lon_in(:))-1; nlat_in = size(lat_in(:))-1
384  nlon_out = size(lon_out(:))-1; nlat_out = size(lat_out(:))-1
385  allocate(lon_src_1d(nlon_in), lat_src_1d(nlat_in))
386  allocate(lon_dst_1d(nlon_out), lat_dst_1d(nlat_out))
387  do i = 1, nlon_in
388  lon_src_1d(i) = (lon_in(i) + lon_in(i+1)) * 0.5
389  enddo
390  do j = 1, nlat_in
391  lat_src_1d(j) = (lat_in(j) + lat_in(j+1)) * 0.5
392  enddo
393  do i = 1, nlon_out
394  lon_dst_1d(i) = (lon_out(i) + lon_out(i+1)) * 0.5
395  enddo
396  do j = 1, nlat_out
397  lat_dst_1d(j) = (lat_out(j) + lat_out(j+1)) * 0.5
398  enddo
399  call horiz_interp_bicubic_new ( interp, lon_src_1d, lat_src_1d, lon_dst_1d, lat_dst_1d, &
400  verbose, src_modulo)
401  deallocate(lon_src_1d, lat_src_1d, lon_dst_1d, lat_dst_1d)
402  endif
403  case ("spherical")
404  interp%interp_method = spherica
405  nlon_in = size(lon_in(:)); nlat_in = size(lat_in(:))
406  nlon_out = size(lon_out(:)); nlat_out = size(lat_out(:))
407  allocate(lon_src(nlon_in,nlat_in), lat_src(nlon_in,nlat_in))
408  allocate(lon_dst(nlon_out,nlat_out), lat_dst(nlon_out,nlat_out))
409  do i = 1, nlon_in
410  lon_src(i,:) = lon_in(i)
411  enddo
412  do j = 1, nlat_in
413  lat_src(:,j) = lat_in(j)
414  enddo
415  do i = 1, nlon_out
416  lon_dst(i,:) = lon_out(i)
417  enddo
418  do j = 1, nlat_out
419  lat_dst(:,j) = lat_out(j)
420  enddo
421  call horiz_interp_spherical_new ( interp, lon_src, lat_src, lon_dst, lat_dst, &
422  num_nbrs, max_dist, src_modulo)
423  deallocate(lon_src, lat_src, lon_dst, lat_dst)
424  case default
425  call mpp_error(fatal,'horiz_interp_mod: interp_method should be conservative, bilinear, bicubic, spherical')
426  end select
427 
428  !-----------------------------------------------------------------------
429  interp%I_am_initialized = .true.
430 
431  end subroutine horiz_interp_new_1d
432 ! </SUBROUTINE>
433 
434 !#######################################################################
435 
436  subroutine horiz_interp_new_1d_src (Interp, lon_in, lat_in, lon_out, lat_out, &
437  verbose, interp_method, num_nbrs, max_dist, &
438  src_modulo, grid_at_center, mask_in, mask_out, is_latlon_out )
440  type(horiz_interp_type), intent(inout) :: Interp
441  real, intent(in), dimension(:) :: lon_in , lat_in
442  real, intent(in), dimension(:,:) :: lon_out, lat_out
443  integer, intent(in), optional :: verbose
444  character(len=*), intent(in), optional :: interp_method
445  integer, intent(in), optional :: num_nbrs ! minimum number of neighbors
446  real, intent(in), optional :: max_dist
447  logical, intent(in), optional :: src_modulo
448  logical, intent(in), optional :: grid_at_center
449  real, intent(in), dimension(:,:), optional :: mask_in
450  real, intent(out),dimension(:,:), optional :: mask_out
451  logical, intent(in), optional :: is_latlon_out
452 
453  real, dimension(:,:), allocatable :: lon_src, lat_src
454  real, dimension(:), allocatable :: lon_src_1d, lat_src_1d
455  integer :: i, j, nlon_in, nlat_in
456  character(len=40) :: method
457  logical :: center
458  logical :: dst_is_latlon
459  !-----------------------------------------------------------------------
460  call horiz_interp_init
461 
462  method = 'conservative'
463  if(present(interp_method)) method = interp_method
464 
465  select case (trim(method))
466  case ("conservative")
467  interp%interp_method = conserve
468  !--- check to see if the source grid is regular lat-lon grid or not.
469  if(PRESENT(is_latlon_out)) then
470  dst_is_latlon = is_latlon_out
471  else
472  dst_is_latlon = is_lat_lon(lon_out, lat_out)
473  end if
474  if(dst_is_latlon ) then
475  if(present(mask_in)) then
476  if ( any(mask_in < -.0001) .or. any(mask_in > 1.0001) ) call mpp_error(fatal, &
477  'horiz_interp_conserve_new_1d_src(horiz_interp_conserve_mod): input mask not between 0,1')
478  allocate(interp%mask_in(size(mask_in,1), size(mask_in,2)) )
479  interp%mask_in = mask_in
480  end if
481  call horiz_interp_conserve_new ( interp, lon_in, lat_in, lon_out(:,1), lat_out(1,:), &
482  verbose=verbose )
483  else
484  call horiz_interp_conserve_new ( interp, lon_in, lat_in, lon_out, lat_out, &
485  verbose=verbose, mask_in=mask_in, mask_out=mask_out )
486  end if
487  case ("bilinear")
488  interp%interp_method = bilinear
489  center = .false.
490  if(present(grid_at_center) ) center = grid_at_center
491  if(center) then
492  call horiz_interp_bilinear_new ( interp, lon_in, lat_in, lon_out, lat_out, &
493  verbose, src_modulo )
494  else
495  nlon_in = size(lon_in(:))-1; nlat_in = size(lat_in(:))-1
496  allocate(lon_src_1d(nlon_in), lat_src_1d(nlat_in))
497  do i = 1, nlon_in
498  lon_src_1d(i) = (lon_in(i) + lon_in(i+1)) * 0.5
499  enddo
500  do j = 1, nlat_in
501  lat_src_1d(j) = (lat_in(j) + lat_in(j+1)) * 0.5
502  enddo
503  call horiz_interp_bilinear_new ( interp, lon_src_1d, lat_src_1d, lon_out, lat_out, &
504  verbose, src_modulo )
505  deallocate(lon_src_1d,lat_src_1d)
506  endif
507  case ("bicubic")
508  interp%interp_method = bicubic
509  center = .false.
510  if(present(grid_at_center) ) center = grid_at_center
511  if(center) then
512  call horiz_interp_bicubic_new ( interp, lon_in, lat_in, lon_out, lat_out, &
513  verbose, src_modulo )
514  else
515  nlon_in = size(lon_in(:))-1; nlat_in = size(lat_in(:))-1
516  allocate(lon_src_1d(nlon_in), lat_src_1d(nlat_in))
517  do i = 1, nlon_in
518  lon_src_1d(i) = (lon_in(i) + lon_in(i+1)) * 0.5
519  enddo
520  do j = 1, nlat_in
521  lat_src_1d(j) = (lat_in(j) + lat_in(j+1)) * 0.5
522  enddo
523  call horiz_interp_bicubic_new ( interp, lon_src_1d, lat_src_1d, lon_out, lat_out, &
524  verbose, src_modulo )
525  deallocate(lon_src_1d,lat_src_1d)
526  endif
527  case ("spherical")
528  interp%interp_method = spherica
529  nlon_in = size(lon_in(:)); nlat_in = size(lat_in(:))
530  allocate(lon_src(nlon_in,nlat_in), lat_src(nlon_in,nlat_in))
531  do i = 1, nlon_in
532  lon_src(i,:) = lon_in(i)
533  enddo
534  do j = 1, nlat_in
535  lat_src(:,j) = lat_in(j)
536  enddo
537  call horiz_interp_spherical_new ( interp, lon_src, lat_src, lon_out, lat_out, &
538  num_nbrs, max_dist, src_modulo)
539  deallocate(lon_src, lat_src)
540  case default
541  call mpp_error(fatal,'interp_method should be conservative, bilinear, bicubic, spherical')
542  end select
543 
544  !-----------------------------------------------------------------------
545  interp%I_am_initialized = .true.
546 
547  end subroutine horiz_interp_new_1d_src
548 
549 !#######################################################################
550 
551  subroutine horiz_interp_new_2d (Interp, lon_in, lat_in, lon_out, lat_out, &
552  verbose, interp_method, num_nbrs, max_dist, &
553  src_modulo, mask_in, mask_out, is_latlon_in, is_latlon_out )
554  type(horiz_interp_type), intent(inout) :: Interp
555  real, intent(in), dimension(:,:) :: lon_in , lat_in
556  real, intent(in), dimension(:,:) :: lon_out, lat_out
557  integer, intent(in), optional :: verbose
558  character(len=*), intent(in), optional :: interp_method
559  integer, intent(in), optional :: num_nbrs
560  real, intent(in), optional :: max_dist
561  logical, intent(in), optional :: src_modulo
562  real, intent(in), dimension(:,:), optional :: mask_in
563  real, intent(out),dimension(:,:), optional :: mask_out
564  logical, intent(in), optional :: is_latlon_in, is_latlon_out
565  logical :: src_is_latlon, dst_is_latlon
566  character(len=40) :: method
567 !-----------------------------------------------------------------------
568  call horiz_interp_init
569 
570  method = 'bilinear'
571  if(present(interp_method)) method = interp_method
572 
573  select case (trim(method))
574  case ("conservative")
575  interp%interp_method = conserve
576  if(PRESENT(is_latlon_in)) then
577  src_is_latlon = is_latlon_in
578  else
579  src_is_latlon = is_lat_lon(lon_in, lat_in)
580  end if
581  if(PRESENT(is_latlon_out)) then
582  dst_is_latlon = is_latlon_out
583  else
584  dst_is_latlon = is_lat_lon(lon_out, lat_out)
585  end if
586  if(src_is_latlon .AND. dst_is_latlon) then
587  if(present(mask_in)) then
588  if ( any(mask_in < -.0001) .or. any(mask_in > 1.0001) ) call mpp_error(fatal, &
589  'horiz_interp_conserve_new_2d(horiz_interp_conserve_mod): input mask not between 0,1')
590  allocate(interp%mask_in(size(mask_in,1), size(mask_in,2)) )
591  interp%mask_in = mask_in
592  end if
593  call horiz_interp_conserve_new ( interp, lon_in(:,1), lat_in(1,:), lon_out(:,1), lat_out(1,:), &
594  verbose=verbose )
595  else if(src_is_latlon) then
596  call horiz_interp_conserve_new ( interp, lon_in(:,1), lat_in(1,:), lon_out, lat_out, &
597  verbose=verbose, mask_in=mask_in, mask_out=mask_out )
598  else if(dst_is_latlon) then
599  call horiz_interp_conserve_new ( interp, lon_in, lat_in, lon_out(:,1), lat_out(1,:), &
600  verbose=verbose, mask_in=mask_in, mask_out=mask_out )
601  else
602  call horiz_interp_conserve_new ( interp, lon_in, lat_in, lon_out, lat_out, &
603  verbose=verbose, mask_in=mask_in, mask_out=mask_out )
604  end if
605 
606  case ("spherical")
607  interp%interp_method = spherica
608  call horiz_interp_spherical_new ( interp, lon_in, lat_in, lon_out, lat_out, &
609  num_nbrs, max_dist, src_modulo )
610  case ("bilinear")
611  interp%interp_method = bilinear
612  call horiz_interp_bilinear_new ( interp, lon_in, lat_in, lon_out, lat_out, &
613  verbose, src_modulo )
614  case default
615  call mpp_error(fatal,'when source grid are 2d, interp_method should be spherical or bilinear')
616  end select
617 
618 !-----------------------------------------------------------------------
619  interp%I_am_initialized = .true.
620 
621  end subroutine horiz_interp_new_2d
622 
623 !#######################################################################
624  subroutine horiz_interp_new_1d_dst (Interp, lon_in, lat_in, lon_out, lat_out, &
625  verbose, interp_method, num_nbrs, max_dist, src_modulo, mask_in, mask_out, is_latlon_in )
626  type(horiz_interp_type), intent(inout) :: Interp
627  real, intent(in), dimension(:,:) :: lon_in , lat_in
628  real, intent(in), dimension(:) :: lon_out, lat_out
629  integer, intent(in), optional :: verbose
630  character(len=*), intent(in), optional :: interp_method
631  integer, intent(in), optional :: num_nbrs
632  real, intent(in), optional :: max_dist
633  logical, intent(in), optional :: src_modulo
634  real, intent(in), dimension(:,:), optional :: mask_in
635  real, intent(out),dimension(:,:), optional :: mask_out
636  logical, intent(in), optional :: is_latlon_in
637 
638  character(len=40) :: method
639  !-------------some local variables-----------------------------------------------
640  integer :: i, j, nlon_out, nlat_out
641  real, dimension(:,:), allocatable :: lon_dst, lat_dst
642  logical :: src_is_latlon
643  !-----------------------------------------------------------------------
644  call horiz_interp_init
645 
646  method = 'bilinear'
647  if(present(interp_method)) method = interp_method
648 
649  nlon_out = size(lon_out(:)); nlat_out = size(lat_out(:))
650  allocate(lon_dst(nlon_out,nlat_out), lat_dst(nlon_out,nlat_out))
651  do i = 1, nlon_out
652  lon_dst(i,:) = lon_out(i)
653  enddo
654  do j = 1, nlat_out
655  lat_dst(:,j) = lat_out(j)
656  enddo
657 
658  select case (trim(method))
659  case ("conservative")
660  interp%interp_method = conserve
661  if(PRESENT(is_latlon_in)) then
662  src_is_latlon = is_latlon_in
663  else
664  src_is_latlon = is_lat_lon(lon_in, lat_in)
665  end if
666 
667  if(src_is_latlon) then
668  if(present(mask_in)) then
669  if ( any(mask_in < -.0001) .or. any(mask_in > 1.0001) ) call mpp_error(fatal, &
670  'horiz_interp_conserve_new_1d_dst(horiz_interp_conserve_mod): input mask not between 0,1')
671  allocate(interp%mask_in(size(mask_in,1), size(mask_in,2)) )
672  interp%mask_in = mask_in
673  end if
674  call horiz_interp_conserve_new ( interp, lon_in(:,1), lat_in(1,:), lon_out, lat_out, &
675  verbose=verbose)
676  else
677  call horiz_interp_conserve_new ( interp, lon_in, lat_in, lon_out, lat_out, &
678  verbose=verbose, mask_in=mask_in, mask_out=mask_out )
679  end if
680  case ("bilinear")
681  interp%interp_method = bilinear
682  call horiz_interp_bilinear_new ( interp, lon_in, lat_in, lon_dst, lat_dst, &
683  verbose, src_modulo )
684  case ("spherical")
685  interp%interp_method = spherica
686  call horiz_interp_spherical_new ( interp, lon_in, lat_in, lon_dst, lat_dst, &
687  num_nbrs, max_dist, src_modulo)
688  case default
689  call mpp_error(fatal,'when source grid are 2d, interp_method should be spherical or bilinear')
690  end select
691 
692  deallocate(lon_dst,lat_dst)
693 
694  !-----------------------------------------------------------------------
695  interp%I_am_initialized = .true.
696 
697  end subroutine horiz_interp_new_1d_dst
698 
699 !#######################################################################
700 ! <SUBROUTINE NAME="horiz_interp_base_2d" INTERFACE="horiz_interp">
701 ! <IN NAME="Interp" TYPE="type(horiz_interp_type)"> </IN>
702 ! <IN NAME="data_in" TYPE="real" DIM="(:,:),(:,:,:)"> </IN>
703 ! <IN NAME="lon_in, lat_in" TYPE="real" DIM="(:),(:,:)"> </IN>
704 ! <IN NAME="lon_out, lat_out" TYPE="real" DIM="(:),(:,:)"> </IN>
705 ! <IN NAME="missing_value" TYPE="integer, optional" > </IN>
706 ! <IN NAME="missing_permit" TYPE="integer,optional" > </IN>
707 ! <IN NAME="verbose" TYPE="integer,optional"> </IN>
708 ! <IN NAME="mask_in" TYPE="real,optional" DIM="(:,:),(:,:,:)"> </IN>
709 ! <OUT NAME="data_out" TYPE="real" DIM="(:,:),(:,:,:)"> </OUT>
710 ! <OUT NAME="mask_out" TYPE="real,optional" DIM="(:,:),(:,:,:)"> </OUT>
711 
712 !<PUBLICROUTINE INTERFACE="horiz_interp">
713  subroutine horiz_interp_base_2d ( Interp, data_in, data_out, verbose, &
714  mask_in, mask_out, missing_value, missing_permit, &
715  err_msg, new_missing_handle )
716 !</PUBLICROUTINE>
717 !-----------------------------------------------------------------------
718  type(horiz_interp_type), intent(in) :: interp
719  real, intent(in), dimension(:,:) :: data_in
720  real, intent(out), dimension(:,:) :: data_out
721  integer, intent(in), optional :: verbose
722  real, intent(in), dimension(:,:), optional :: mask_in
723  real, intent(out), dimension(:,:), optional :: mask_out
724  real, intent(in), optional :: missing_value
725  integer, intent(in), optional :: missing_permit
726  character(len=*), intent(out), optional :: err_msg
727  logical, intent(in), optional :: new_missing_handle
728 !-----------------------------------------------------------------------
729  if(present(err_msg)) err_msg = ''
730  if(.not.interp%I_am_initialized) then
731  if(fms_error_handler('horiz_interp','The horiz_interp_type variable is not initialized',err_msg)) return
732  endif
733 
734  select case(interp%interp_method)
735  case(conserve)
736  call horiz_interp_conserve(interp,data_in, data_out, verbose, mask_in, mask_out)
737  case(bilinear)
738  call horiz_interp_bilinear(interp,data_in, data_out, verbose, mask_in, mask_out, &
739  missing_value, missing_permit, new_missing_handle )
740  case(bicubic)
741  call horiz_interp_bicubic(interp,data_in, data_out, verbose, mask_in, mask_out, &
742  missing_value, missing_permit )
743  case(spherica)
744  call horiz_interp_spherical(interp,data_in, data_out, verbose, mask_in, mask_out, &
745  missing_value )
746  case default
747  call mpp_error(fatal,'interp_method should be conservative, bilinear, bicubic, spherical')
748  end select
749 
750  return
751 
752  end subroutine horiz_interp_base_2d
753 ! </SUBROUTINE>
754 
755 !#######################################################################
756 
757  subroutine horiz_interp_base_3d ( Interp, data_in, data_out, verbose, mask_in, mask_out, &
758  missing_value, missing_permit, err_msg )
759  !-----------------------------------------------------------------------
760  ! overload of interface horiz_interp_base_2d
761  ! uses 3d arrays for data and mask
762  ! this allows for multiple interpolations with one call
763  !-----------------------------------------------------------------------
764  type(horiz_interp_type), intent(in) :: interp
765  real, intent(in), dimension(:,:,:) :: data_in
766  real, intent(out), dimension(:,:,:) :: data_out
767  integer, intent(in), optional :: verbose
768  real, intent(in), dimension(:,:,:), optional :: mask_in
769  real, intent(out), dimension(:,:,:), optional :: mask_out
770  real, intent(in), optional :: missing_value
771  integer, intent(in), optional :: missing_permit
772  character(len=*), intent(out), optional :: err_msg
773  !-----------------------------------------------------------------------
774  integer :: n
775 
776  if(present(err_msg)) err_msg = ''
777  if(.not.interp%I_am_initialized) then
778  if(fms_error_handler('horiz_interp','The horiz_interp_type variable is not initialized',err_msg)) return
779  endif
780 
781  do n = 1, size(data_in,3)
782  if (present(mask_in))then
783  if(present(mask_out)) then
784  call horiz_interp_base_2d ( interp, data_in(:,:,n), data_out(:,:,n), &
785  verbose, mask_in(:,:,n), mask_out(:,:,n), &
786  missing_value, missing_permit )
787  else
788  call horiz_interp_base_2d ( interp, data_in(:,:,n), data_out(:,:,n), &
789  verbose, mask_in(:,:,n), missing_value = missing_value, &
790  missing_permit = missing_permit )
791  endif
792  else
793  if(present(mask_out)) then
794  call horiz_interp_base_2d ( interp, data_in(:,:,n), data_out(:,:,n), &
795  verbose, mask_out=mask_out(:,:,n), missing_value = missing_value, &
796  missing_permit = missing_permit )
797  else
798  call horiz_interp_base_2d ( interp, data_in(:,:,n), data_out(:,:,n), &
799  verbose, missing_value = missing_value, &
800  missing_permit = missing_permit )
801  endif
802  endif
803  enddo
804 
805  return
806 !-----------------------------------------------------------------------
807  end subroutine horiz_interp_base_3d
808 
809 !#######################################################################
810 !<PUBLICROUTINE INTERFACE="horiz_interp">
811  subroutine horiz_interp_solo_1d ( data_in, lon_in, lat_in, lon_out, lat_out, &
812  data_out, verbose, mask_in, mask_out, &
813  interp_method, missing_value, missing_permit, &
814  num_nbrs, max_dist,src_modulo, grid_at_center )
815 !</PUBLICROUTINE>
816 !-----------------------------------------------------------------------
817 ! interpolates from a rectangular grid to rectangular grid.
818 ! interp_method can be the value conservative, bilinear or spherical.
819 ! horiz_interp_new don't need to be called before calling this routine.
820 
821 !-----------------------------------------------------------------------
822  real, intent(in), dimension(:,:) :: data_in
823  real, intent(in), dimension(:) :: lon_in , lat_in
824  real, intent(in), dimension(:) :: lon_out, lat_out
825  real, intent(out), dimension(:,:) :: data_out
826  integer, intent(in), optional :: verbose
827  real, intent(in), dimension(:,:), optional :: mask_in
828  real, intent(out), dimension(:,:), optional :: mask_out
829  character(len=*), intent(in), optional :: interp_method
830  real, intent(in), optional :: missing_value
831  integer, intent(in), optional :: missing_permit
832  integer, intent(in), optional :: num_nbrs
833  real, intent(in), optional :: max_dist
834  logical, intent(in), optional :: src_modulo
835  logical, intent(in), optional :: grid_at_center
836 !-----------------------------------------------------------------------
837  type(horiz_interp_type) :: interp
838 !-----------------------------------------------------------------------
839  call horiz_interp_init
840 
841  call horiz_interp_new ( interp, lon_in, lat_in, lon_out, lat_out, verbose, &
842  interp_method, num_nbrs, max_dist, src_modulo, grid_at_center )
843 
844  call horiz_interp ( interp, data_in, data_out, verbose, &
845  mask_in, mask_out, missing_value, missing_permit )
846 
847  call horiz_interp_del ( interp )
848 !-----------------------------------------------------------------------
849 
850  end subroutine horiz_interp_solo_1d
851 
852 !#######################################################################
853 
854  subroutine horiz_interp_solo_1d_src ( data_in, lon_in, lat_in, lon_out, lat_out, &
855  data_out, verbose, mask_in, mask_out, &
856  interp_method, missing_value, missing_permit, &
857  num_nbrs, max_dist, src_modulo, grid_at_center )
858 !-----------------------------------------------------------------------
859 !
860 ! interpolates from a uniformly spaced grid to any output grid.
861 ! interp_method can be the value "onservative","bilinear" or "spherical".
862 ! horiz_interp_new don't need to be called before calling this routine.
863 !
864 !-----------------------------------------------------------------------
865  real, intent(in), dimension(:,:) :: data_in
866  real, intent(in), dimension(:) :: lon_in , lat_in
867  real, intent(in), dimension(:,:) :: lon_out, lat_out
868  real, intent(out), dimension(:,:) :: data_out
869  integer, intent(in), optional :: verbose
870  real, intent(in), dimension(:,:), optional :: mask_in
871  real, intent(out), dimension(:,:), optional :: mask_out
872  character(len=*), intent(in), optional :: interp_method
873  real, intent(in), optional :: missing_value
874  integer, intent(in), optional :: missing_permit
875  integer, intent(in), optional :: num_nbrs
876  real, intent(in), optional :: max_dist
877  logical, intent(in), optional :: src_modulo
878  logical, intent(in), optional :: grid_at_center
879 
880 !-----------------------------------------------------------------------
881  type(horiz_interp_type) :: interp
882  logical :: dst_is_latlon
883  character(len=128) :: method
884 !-----------------------------------------------------------------------
885  call horiz_interp_init
886  method = 'conservative'
887  if(present(interp_method)) method = interp_method
888  dst_is_latlon = .true.
889  if(trim(method) == 'conservative') dst_is_latlon = is_lat_lon(lon_out, lat_out)
890 
891  if(dst_is_latlon) then
892  call horiz_interp_new ( interp, lon_in, lat_in, lon_out, lat_out, verbose, &
893  interp_method, num_nbrs, max_dist, src_modulo, &
894  grid_at_center, is_latlon_out = dst_is_latlon )
895  call horiz_interp ( interp, data_in, data_out, verbose, &
896  mask_in, mask_out, missing_value, missing_permit )
897  else
898  call horiz_interp_new ( interp, lon_in, lat_in, lon_out, lat_out, verbose, &
899  interp_method, num_nbrs, max_dist, src_modulo, &
900  grid_at_center, mask_in, mask_out, is_latlon_out = dst_is_latlon)
901 
902  call horiz_interp ( interp, data_in, data_out, verbose, &
903  missing_value=missing_value, missing_permit=missing_permit )
904  end if
905 
906  call horiz_interp_del ( interp )
907 
908 !-----------------------------------------------------------------------
909 
910  end subroutine horiz_interp_solo_1d_src
911 
912 
913 !#######################################################################
914 
915  subroutine horiz_interp_solo_2d ( data_in, lon_in, lat_in, lon_out, lat_out, data_out, &
916  verbose, mask_in, mask_out, interp_method, missing_value,&
917  missing_permit, num_nbrs, max_dist, src_modulo )
918 !-----------------------------------------------------------------------
919 !
920 ! interpolates from any grid to any grid. interp_method should be "spherical"
921 ! horiz_interp_new don't need to be called before calling this routine.
922 !
923 !-----------------------------------------------------------------------
924  real, intent(in), dimension(:,:) :: data_in
925  real, intent(in), dimension(:,:) :: lon_in , lat_in
926  real, intent(in), dimension(:,:) :: lon_out, lat_out
927  real, intent(out), dimension(:,:) :: data_out
928  integer, intent(in), optional :: verbose
929  real, intent(in), dimension(:,:), optional :: mask_in
930  real, intent(out), dimension(:,:), optional :: mask_out
931  character(len=*), intent(in), optional :: interp_method
932  real, intent(in), optional :: missing_value
933  integer, intent(in), optional :: missing_permit
934  integer, intent(in), optional :: num_nbrs
935  real, intent(in), optional :: max_dist
936  logical, intent(in), optional :: src_modulo
937 !-----------------------------------------------------------------------
938  type(horiz_interp_type) :: interp
939  logical :: dst_is_latlon, src_is_latlon
940  character(len=128) :: method
941 !-----------------------------------------------------------------------
942  call horiz_interp_init
943 
944  method = 'conservative'
945  if(present(interp_method)) method = interp_method
946  dst_is_latlon = .true.
947  src_is_latlon = .true.
948  if(trim(method) == 'conservative') then
949  dst_is_latlon = is_lat_lon(lon_out, lat_out)
950  src_is_latlon = is_lat_lon(lon_in, lat_in)
951  end if
952 
953  if(dst_is_latlon .and. src_is_latlon) then
954  call horiz_interp_new ( interp, lon_in, lat_in, lon_out, lat_out, verbose, &
955  interp_method, num_nbrs, max_dist, src_modulo, &
956  is_latlon_in=dst_is_latlon, is_latlon_out = dst_is_latlon )
957  call horiz_interp ( interp, data_in, data_out, verbose, &
958  mask_in, mask_out, missing_value, missing_permit )
959  else
960  call horiz_interp_new ( interp, lon_in, lat_in, lon_out, lat_out, verbose, &
961  interp_method, num_nbrs, max_dist, src_modulo, &
962  mask_in, mask_out, &
963  is_latlon_in=dst_is_latlon, is_latlon_out = dst_is_latlon)
964  call horiz_interp ( interp, data_in, data_out, verbose, &
965  missing_value=missing_value, missing_permit=missing_permit )
966  end if
967 
968  call horiz_interp_del ( interp )
969 
970 !-----------------------------------------------------------------------
971 
972  end subroutine horiz_interp_solo_2d
973 
974 !#######################################################################
975 
976  subroutine horiz_interp_solo_1d_dst ( data_in, lon_in, lat_in, lon_out, lat_out, data_out, &
977  verbose, mask_in, mask_out,interp_method,missing_value, &
978  missing_permit, num_nbrs, max_dist, src_modulo)
979 !-----------------------------------------------------------------------
980 !
981 ! interpolates from any grid to rectangular longitude/latitude grid.
982 ! interp_method should be "spherical".
983 ! horiz_interp_new don't need to be called before calling this routine.
984 !
985 !-----------------------------------------------------------------------
986  real, intent(in), dimension(:,:) :: data_in
987  real, intent(in), dimension(:,:) :: lon_in , lat_in
988  real, intent(in), dimension(:) :: lon_out, lat_out
989  real, intent(out), dimension(:,:) :: data_out
990  integer, intent(in), optional :: verbose
991  real, intent(in), dimension(:,:), optional :: mask_in
992  real, intent(out), dimension(:,:), optional :: mask_out
993  character(len=*), intent(in), optional :: interp_method
994  real, intent(in), optional :: missing_value
995  integer, intent(in), optional :: missing_permit
996  integer, intent(in), optional :: num_nbrs
997  real, intent(in), optional :: max_dist
998  logical, intent(in), optional :: src_modulo
999 !-----------------------------------------------------------------------
1000  type(horiz_interp_type) :: interp
1001  logical :: src_is_latlon
1002  character(len=128) :: method
1003 !-----------------------------------------------------------------------
1004  call horiz_interp_init
1005 
1006  method = 'conservative'
1007  if(present(interp_method)) method = interp_method
1008  src_is_latlon = .true.
1009  if(trim(method) == 'conservative') src_is_latlon = is_lat_lon(lon_in, lat_in)
1010 
1011  if(src_is_latlon) then
1012  call horiz_interp_new ( interp, lon_in, lat_in, lon_out, lat_out, verbose, &
1013  interp_method, num_nbrs, max_dist, src_modulo, &
1014  is_latlon_in = src_is_latlon )
1015  call horiz_interp ( interp, data_in, data_out, verbose, &
1016  mask_in, mask_out, missing_value, missing_permit )
1017  else
1018  call horiz_interp_new ( interp, lon_in, lat_in, lon_out, lat_out, verbose, &
1019  interp_method, num_nbrs, max_dist, src_modulo, &
1020  mask_in, mask_out, is_latlon_in = src_is_latlon)
1021 
1022  call horiz_interp ( interp, data_in, data_out, verbose, &
1023  missing_value=missing_value, missing_permit=missing_permit )
1024  end if
1025 
1026  call horiz_interp_del ( interp )
1027 
1028 !-----------------------------------------------------------------------
1029 
1030  end subroutine horiz_interp_solo_1d_dst
1031 
1032 !#######################################################################
1033 
1034  subroutine horiz_interp_solo_old (data_in, wb, sb, dx, dy, &
1035  lon_out, lat_out, data_out, &
1036  verbose, mask_in, mask_out)
1038 !-----------------------------------------------------------------------
1039 ! Overloaded version of interface horiz_interp_solo_2
1040 !
1041 ! input
1042 !
1043 ! data_in Global input data stored from west to east (first dimension),
1044 ! south to north (second dimension). [real, dimension(:,:)]
1045 !
1046 ! wb Longitude (in radians) that corresponds to western-most
1047 ! boundary of grid box i=1 in array data_in. [real]
1048 !
1049 ! sb Latitude (in radians) that corresponds to southern-most
1050 ! boundary of grid box j=1 in array data_in. [real]
1051 !
1052 ! dx Grid spacing (in radians) for the longitude axis (first
1053 ! dimension) for the input data. [real]
1054 !
1055 ! dy Grid spacing (in radians) for the latitude axis (second
1056 ! dimension) for the input data. [real]
1057 !
1058 ! lon_out The longitude edges (in radians) for output data grid boxes.
1059 ! The values are for adjacent grid boxes and must increase in
1060 ! value. If there are MLON grid boxes there must be MLON+1
1061 ! edge values. [real, dimension(:)]
1062 !
1063 ! lat_out The latitude edges (in radians) for output data grid boxes.
1064 ! The values are for adjacent grid boxes and may increase or
1065 ! decrease in value. If there are NLAT grid boxes there must
1066 ! be NLAT+1 edge values. [real, dimension(:)]
1067 !
1068 ! OUTPUT
1069 ! data_out Output data on the output grid defined by grid box
1070 ! edges: blon_out and blat_out. [real, dimension(:,:)]
1071 !
1072 !-----------------------------------------------------------------------
1073  real, intent(in), dimension(:,:) :: data_in
1074  real, intent(in) :: wb, sb, dx, dy
1075  real, intent(in), dimension(:) :: lon_out, lat_out
1076  real, intent(out), dimension(:,:) :: data_out
1077  integer, intent(in), optional :: verbose
1078  real, intent(in), dimension(:,:), optional :: mask_in
1079  real, intent(out), dimension(:,:), optional :: mask_out
1080 !-----------------------------------------------------------------------
1081  real, dimension(size(data_in,1)+1) :: blon_in
1082  real, dimension(size(data_in,2)+1) :: blat_in
1083  integer :: i, j, nlon_in, nlat_in
1084  real :: tpi
1085 !-----------------------------------------------------------------------
1086  call horiz_interp_init
1087 
1088  tpi = 2.*pi
1089  nlon_in = size(data_in,1)
1090  nlat_in = size(data_in,2)
1091 
1092  do i = 1, nlon_in+1
1093  blon_in(i) = wb + float(i-1)*dx
1094  enddo
1095  if (abs(blon_in(nlon_in+1)-blon_in(1)-tpi) < epsilon(blon_in)) &
1096  blon_in(nlon_in+1)=blon_in(1)+tpi
1097 
1098  do j = 2, nlat_in
1099  blat_in(j) = sb + float(j-1)*dy
1100  enddo
1101  blat_in(1) = -0.5*pi
1102  blat_in(nlat_in+1) = 0.5*pi
1103 
1104 
1105  call horiz_interp_solo_1d (data_in, blon_in, blat_in, &
1106  lon_out, lat_out, data_out, &
1107  verbose, mask_in, mask_out )
1108 
1109 !-----------------------------------------------------------------------
1110 
1111  end subroutine horiz_interp_solo_old
1112 
1113 !#######################################################################
1114 ! <SUBROUTINE NAME="horiz_interp_del">
1115 
1116 ! <OVERVIEW>
1117 ! Deallocates memory used by "horiz_interp_type" variables.
1118 ! Must be called before reinitializing with horiz_interp_new.
1119 ! </OVERVIEW>
1120 ! <DESCRIPTION>
1121 ! Deallocates memory used by "horiz_interp_type" variables.
1122 ! Must be called before reinitializing with horiz_interp_new.
1123 ! </DESCRIPTION>
1124 ! <TEMPLATE>
1125 ! call horiz_interp_del ( Interp )
1126 ! </TEMPLATE>
1127 
1128 ! <INOUT NAME="Interp" TYPE="horiz_interp_type">
1129 ! A derived-type variable returned by previous call
1130 ! to horiz_interp_new. The input variable must have
1131 ! allocated arrays. The returned variable will contain
1132 ! deallocated arrays.
1133 ! </INOUT>
1134 
1135 ! </SUBROUTINE>
1136 
1137  subroutine horiz_interp_del ( Interp )
1139  type(horiz_interp_type), intent(inout) :: interp
1140 
1141 !-----------------------------------------------------------------------
1142 ! releases space used by horiz_interp_type variables
1143 ! must be called before re-initializing the same variable
1144 !-----------------------------------------------------------------------
1145  select case(interp % interp_method)
1146  case (conserve)
1147  call horiz_interp_conserve_del(interp )
1148  case (bilinear)
1149  call horiz_interp_bilinear_del(interp )
1150  case (bicubic)
1151  call horiz_interp_bicubic_del(interp )
1152  case (spherica)
1153  call horiz_interp_spherical_del(interp )
1154  end select
1155 
1156  interp%I_am_initialized = .false.
1157 !-----------------------------------------------------------------------
1158 
1159  end subroutine horiz_interp_del
1160 
1161  !#####################################################################
1162 
1163 ! <SUBROUTINE NAME="horiz_interp_end">
1164 
1165 ! <OVERVIEW>
1166 ! Dummy routine.
1167 ! </OVERVIEW>
1168 ! <DESCRIPTION>
1169 ! Dummy routine.
1170 ! </DESCRIPTION>
1171 ! <TEMPLATE>
1172 ! call horiz_interp_end
1173 ! </TEMPLATE>
1174 
1175 ! </SUBROUTINE>
1176 
1177  subroutine horiz_interp_end
1178  return
1179  end subroutine horiz_interp_end
1180 
1181  !####################################################################
1182  function is_lat_lon(lon, lat)
1183  real, dimension(:,:), intent(in) :: lon, lat
1184  logical :: is_lat_lon
1185  integer :: i, j, nlon, nlat, num
1186 
1187  is_lat_lon = .true.
1188  nlon = size(lon,1)
1189  nlat = size(lon,2)
1190  loop_lat: do j = 1, nlat
1191  do i = 2, nlon
1192  if(lat(i,j) .NE. lat(1,j)) then
1193  is_lat_lon = .false.
1194  exit loop_lat
1195  end if
1196  end do
1197  end do loop_lat
1198 
1199  if(is_lat_lon) then
1200  loop_lon: do i = 1, nlon
1201  do j = 2, nlat
1202  if(lon(i,j) .NE. lon(i,1)) then
1203  is_lat_lon = .false.
1204  exit loop_lon
1205  end if
1206  end do
1207  end do loop_lon
1208  end if
1209 
1210  num = 0
1211  if(is_lat_lon) num = 1
1212  call mpp_min(num)
1213  if(num == 1) then
1214  is_lat_lon = .true.
1215  else
1216  is_lat_lon = .false.
1217  end if
1218 
1219  return
1220  end function is_lat_lon
1221 
1222 !#####################################################################
1223 
1224 end module horiz_interp_mod
1225 
1226 ! <INFO>
1227 ! <NOTE>
1228 ! Has not been checked with grids that do not cover the sphere.
1229 !
1230 ! Has not been checked with the optional mask arguments.
1231 !
1232 ! If a latitude or longitude index cannot be found the tolerance
1233 ! used for making this determination may need to be increased.
1234 ! This can be done by increasing the value of module variable
1235 ! num_iters (default 4).
1236 ! </NOTE>
1237 ! <TESTPROGRAM>
1238 ! <PRE>
1239 ! program test
1240 ! use horiz_interp_mod
1241 ! implicit none
1242 ! integer, parameter :: nxi=177, nyi=91, nxo=133, nyo=77 ! resolution
1243 ! real :: zi(nxi,nyi), zo(nxo,nyo) ! data
1244 ! real :: xi(nxi+1), yi(nyi+1), xo(nxo+1), yo(nyo+1) ! grid edges
1245 ! real :: pi, tpi, hpi, dx, dy
1246 !
1247 ! ! constants
1248 ! hpi = acos(0.0)
1249 ! pi = hpi*2.0
1250 ! tpi = hpi*4.0
1251 !
1252 ! ! grid setup: west to east, south to north
1253 ! dx = tpi/real(nxi); call setaxis (0.,dx,xi); xi(nxi+1) = xi(1)+tpi
1254 ! dx = tpi/real(nxo); call setaxis (0.,dx,xo); xo(nxo+1) = xo(1)+tpi
1255 ! dy = pi/real(nyi); call setaxis (-hpi,dy,yi); yi(nyi+1) = hpi
1256 ! dy = pi/real(nyo); call setaxis (-hpi,dy,yo); yo(nyo+1) = hpi
1257 !
1258 ! ! random data on the input grid
1259 ! call random_number (zi)
1260 !
1261 ! ! interpolate (flipping y-axis)
1262 ! call horiz_interp (zi(:,1:nyi:+1), xi, yi(1:nyi+1:+1), xo, yo(1:nyo+1:+1), zo, verbose=2)
1263 ! call horiz_interp (zi(:,nyi:1:-1), xi, yi(nyi+1:1:-1), xo, yo(1:nyo+1:+1), zo, verbose=2)
1264 ! call horiz_interp (zi(:,nyi:1:-1), xi, yi(nyi+1:1:-1), xo, yo(nyo+1:1:-1), zo, verbose=2)
1265 ! call horiz_interp (zi(:,1:nyi:+1), xi, yi(1:nyi+1:+1), xo, yo(nyo+1:1:-1), zo, verbose=2)
1266 !
1267 ! contains
1268 ! ! set up a sequence of numbers
1269 ! subroutine setaxis (xo,dx,x)
1270 ! real, intent(in) :: xo, dx
1271 ! real, intent(out) :: x(:)
1272 ! integer :: i
1273 ! x(1) = xo
1274 ! do i=2,size(x(:))
1275 ! x(i) = x(i-1)+dx
1276 ! enddo
1277 ! end subroutine setaxis
1278 !
1279 ! end program test
1280 ! </PRE>
1281 ! </TESTPROGRAM>
1282 ! </INFO>
1283 
1284 #ifdef test_horiz_interp
1285 ! T More tests will be added in the future.
1286 program horiz_interp_test
1287 
1288 use mpp_mod, only : mpp_init, mpp_exit, mpp_error, fatal, stdout, mpp_npes
1289 use mpp_mod, only : mpp_clock_id, mpp_clock_begin, mpp_clock_end
1290 use mpp_mod, only : mpp_pe, mpp_root_pe, note, mpp_clock_sync, mpp_clock_detailed
1291 use mpp_mod, only : input_nml_file
1292 use mpp_io_mod, only : mpp_io_init, mpp_io_exit
1294 use mpp_domains_mod, only : mpp_domains_init, domain2d
1295 use fms_mod, only : file_exist, open_namelist_file, close_file, check_nml_error
1297 use horiz_interp_mod, only : horiz_interp, horiz_interp_type
1298 use constants_mod, only : constants_init, pi
1299 
1300 implicit none
1301 
1302  integer :: ni_src = 360, nj_src = 180
1303  integer :: ni_dst = 144, nj_dst = 72
1304 
1305  namelist /test_horiz_interp_nml/ ni_src, nj_src, ni_dst, nj_dst
1306 
1307  real :: lon_src_beg = 0, lon_src_end = 360
1308  real :: lat_src_beg = -90, lat_src_end = 90
1309  real :: lon_dst_beg = -280, lon_dst_end = 80
1310  real :: lat_dst_beg = -90, lat_dst_end = 90
1311  real :: d2r = pi/180.
1312  real, parameter :: small = 1.0e-10
1313 
1314  type(domain2d) :: domain
1315  type(horiz_interp_type) :: interp
1316  integer :: id1, id2, id3, id4
1317  integer :: isc, iec, jsc, jec, i, j
1318  integer :: nml_unit, io, ierr, layout(2)
1319  real :: dlon_src, dlat_src, dlon_dst, dlat_dst
1320  real, allocatable, dimension(:) :: lon1d_src, lat1d_src, lon1d_dst, lat1d_dst
1321  real, allocatable, dimension(:,:) :: lon2d_src, lat2d_src, lon2d_dst, lat2d_dst
1322  real, allocatable, dimension(:,:) :: data_src, data1_dst, data2_dst, data3_dst, data4_dst
1323 
1324  call constants_init
1325  call mpp_init
1326  call mpp_domains_init
1327  call mpp_io_init
1328  call horiz_interp_init
1329 
1330  !--- read namelist
1331 #ifdef INTERNAL_FILE_NML
1332  read (input_nml_file, test_horiz_interp_nml, iostat=io)
1333  ierr = check_nml_error(io, 'test_horiz_interp_nml')
1334 #else
1335  if (file_exist('input.nml')) then
1336  ierr=1
1337  nml_unit = open_namelist_file()
1338  do while (ierr /= 0)
1339  read(nml_unit, nml=test_horiz_interp_nml, iostat=io, end=10)
1340  ierr = check_nml_error(io, 'test_horiz_interp_nml')
1341  enddo
1342 10 call close_file(nml_unit)
1343  endif
1344 #endif
1345 
1346  !--- define domains
1347  call mpp_define_layout( (/1, ni_dst, 1, nj_dst/), mpp_npes(), layout)
1348  call mpp_define_domains((/1, ni_dst, 1, nj_dst/), layout, domain)
1349  call mpp_get_compute_domain(domain,isc,iec,jsc,jec)
1350 
1351  !--- test conservative horiz_interp with a simple test. the source grid is the region
1352  ! (0:360,-90:90) with grid size ni_src, nj_src ( default 360X180). and the destination
1353  ! is the region (-280:80, -90:90) with grid size ni_dstXnj_dst( default 144X72).
1354  ! integer checksum and global sum will be printed out for both the 1D and 2D version.
1355 
1356  allocate(lon2d_src(ni_src+1, nj_src+1), lat2d_src(ni_src+1, nj_src+1) )
1357  allocate(lon1d_src(ni_src+1), lat1d_src(nj_src+1), data_src(ni_src, nj_src) )
1358 
1359  allocate(lon2d_dst(isc:iec+1, jsc:jec+1), lat2d_dst(isc:iec+1, jsc:jec+1) )
1360  allocate(lon1d_dst(isc:iec+1), lat1d_dst(jsc:jec+1) )
1361  allocate(data1_dst(isc:iec, jsc:jec), data2_dst(isc:iec, jsc:jec) )
1362  allocate(data3_dst(isc:iec, jsc:jec), data4_dst(isc:iec, jsc:jec) )
1363 
1364  ! set up longitude and latitude of source/destination grid.
1365  dlon_src = (lon_src_end-lon_src_beg)/ni_src
1366  dlat_src = (lat_src_end-lat_src_beg)/nj_src
1367  dlon_dst = (lon_dst_end-lon_dst_beg)/ni_dst
1368  dlat_dst = (lat_dst_end-lat_dst_beg)/nj_dst
1369 
1370  do i = 1, ni_src+1
1371  lon1d_src(i) = lon_src_beg + (i-1)*dlon_src
1372  end do
1373 
1374  do j = 1, nj_src+1
1375  lat1d_src(j) = lat_src_beg + (j-1)*dlat_src
1376  end do
1377 
1378  do i = isc, iec+1
1379  lon1d_dst(i) = lon_dst_beg + (i-1)*dlon_dst
1380  end do
1381 
1382  do j = jsc, jec+1
1383  lat1d_dst(j) = lat_dst_beg + (j-1)*dlat_dst
1384  end do
1385 
1386  ! scale grid to radians.
1387  lon1d_src = lon1d_src * d2r
1388  lat1d_src = lat1d_src * d2r
1389  lon1d_dst = lon1d_dst * d2r
1390  lat1d_dst = lat1d_dst * d2r
1391 
1392  do i = 1, ni_src+1
1393  lon2d_src(i,:) = lon1d_src(i)
1394  end do
1395 
1396  do j = 1, nj_src+1
1397  lat2d_src(:,j) = lat1d_src(j)
1398  end do
1399 
1400  do i = isc, iec+1
1401  lon2d_dst(i,:) = lon1d_dst(i)
1402  end do
1403 
1404  do j = jsc, jec+1
1405  lat2d_dst(:,j) = lat1d_dst(j)
1406  end do
1407 
1408  !--- set up the source data
1409  do j = 1, nj_src
1410  do i = 1, ni_src
1411  data_src(i,j) = i + j*0.001
1412  end do
1413  end do
1414 
1415  id1 = mpp_clock_id( 'horiz_interp_1dx1d', flags=mpp_clock_sync+mpp_clock_detailed )
1416  id2 = mpp_clock_id( 'horiz_interp_1dx2d', flags=mpp_clock_sync+mpp_clock_detailed )
1417  id3 = mpp_clock_id( 'horiz_interp_2dx1d', flags=mpp_clock_sync+mpp_clock_detailed )
1418  id4 = mpp_clock_id( 'horiz_interp_2dx2d', flags=mpp_clock_sync+mpp_clock_detailed )
1419 
1420  ! --- 1dx1d version conservative interpolation
1421  call mpp_clock_begin(id1)
1422  call horiz_interp_new(interp, lon1d_src, lat1d_src, lon1d_dst, lat1d_dst, interp_method = "conservative")
1423  call horiz_interp(interp, data_src, data1_dst)
1424  call horiz_interp_del(interp)
1425  call mpp_clock_end(id1)
1426 
1427  ! --- 1dx2d version conservative interpolation
1428  call mpp_clock_begin(id2)
1429  call horiz_interp_new(interp, lon1d_src, lat1d_src, lon2d_dst, lat2d_dst, interp_method = "conservative")
1430  call horiz_interp(interp, data_src, data2_dst)
1431  call horiz_interp_del(interp)
1432  call mpp_clock_end(id2)
1433 
1434  ! --- 2dx1d version conservative interpolation
1435  call mpp_clock_begin(id3)
1436  call horiz_interp_new(interp, lon2d_src, lat2d_src, lon1d_dst, lat1d_dst, interp_method = "conservative")
1437  call horiz_interp(interp, data_src, data3_dst)
1438  call horiz_interp_del(interp)
1439  call mpp_clock_end(id3)
1440 
1441  ! --- 2dx2d version conservative interpolation
1442  call mpp_clock_begin(id4)
1443  call horiz_interp_new(interp, lon2d_src, lat2d_src, lon2d_dst, lat2d_dst, interp_method = "conservative")
1444  call horiz_interp(interp, data_src, data4_dst)
1445  call horiz_interp_del(interp)
1446  call mpp_clock_end(id4)
1447 
1448  !--- compare the data after interpolation between 1-D and 2-D version interpolation
1449  do j = jsc, jsc
1450  do i = isc, iec
1451 
1452  if( abs(data1_dst(i,j)-data2_dst(i,j)) > small ) then
1453  print*, "After interpolation At point (i,j) = (", i, ",", j, "), data1 = ", data1_dst(i,j), &
1454  ", data2 = ", data2_dst(i,j), ", data1-data2 = ", data1_dst(i,j) - data2_dst(i,j)
1455  call mpp_error(fatal,"horiz_interp_test: data1_dst does not approxiamate data2_dst")
1456  end if
1457  end do
1458  end do
1459 
1460  if(mpp_pe() == mpp_root_pe()) call mpp_error(note, &
1461  "The test that verify 1dx2d version horiz_interp can reproduce 1dx1d version of horiz_interp is succesful")
1462 
1463  do j = jsc, jsc
1464  do i = isc, iec
1465 
1466  if( abs(data1_dst(i,j)-data3_dst(i,j)) > small ) then
1467  print*, "After interpolation At point (i,j) = (", i, ",", j, "), data1 = ", data1_dst(i,j), &
1468  ", data2 = ", data3_dst(i,j), ", data1-data2 = ", data1_dst(i,j) - data3_dst(i,j)
1469  call mpp_error(fatal,"horiz_interp_test: data1_dst does not approxiamate data3_dst")
1470  end if
1471  end do
1472  end do
1473 
1474  if(mpp_pe() == mpp_root_pe()) call mpp_error(note, &
1475  "The test that verify 2dx1d version horiz_interp can reproduce 1dx1d version of horiz_interp is succesful")
1476 
1477  do j = jsc, jsc
1478  do i = isc, iec
1479 
1480  if( abs(data1_dst(i,j)-data4_dst(i,j)) > small ) then
1481  print*, "After interpolation At point (i,j) = (", i, ",", j, "), data1 = ", data1_dst(i,j), &
1482  ", data2 = ", data4_dst(i,j), ", data1-data2 = ", data1_dst(i,j) - data4_dst(i,j)
1483  call mpp_error(fatal,"horiz_interp_test: data1_dst does not approxiamate data4_dst")
1484  end if
1485  end do
1486  end do
1487 
1488  if(mpp_pe() == mpp_root_pe()) call mpp_error(note, &
1489  "The test that verify 2dx2d version horiz_interp can reproduce 1dx1d version of horiz_interp is succesful")
1490 
1491  call mpp_io_exit
1492  call mpp_exit
1493 
1494 end program horiz_interp_test
1495 #endif
Definition: fms.F90:20
integer, parameter, public spherica
subroutine, public horiz_interp_end
subroutine horiz_interp_new_2d(Interp, lon_in, lat_in, lon_out, lat_out, verbose, interp_method, num_nbrs, max_dist, src_modulo, mask_in, mask_out, is_latlon_in, is_latlon_out)
integer, parameter, public bilinear
subroutine, public horiz_interp_spherical(Interp, data_in, data_out, verbose, mask_in, mask_out, missing_value)
subroutine, public horiz_interp_del(Interp)
subroutine, public horiz_interp_conserve(Interp, data_in, data_out, verbose, mask_in, mask_out)
subroutine horiz_interp_solo_1d_dst(data_in, lon_in, lat_in, lon_out, lat_out, data_out, verbose, mask_in, mask_out, interp_method, missing_value, missing_permit, num_nbrs, max_dist, src_modulo)
integer, parameter, public bicubic
subroutine, public horiz_interp_bilinear(Interp, data_in, data_out, verbose, mask_in, mask_out, missing_value, missing_permit, new_handle_missing)
logical function, public fms_error_handler(routine, message, err_msg)
Definition: fms.F90:573
subroutine, public horiz_interp_bilinear_del(Interp)
Definition: mpp.F90:39
logical function is_lat_lon(lon, lat)
integer function, public check_nml_error(IOSTAT, NML_NAME)
Definition: fms.F90:658
subroutine, public horiz_interp_bicubic(Interp, data_in, data_out, verbose, mask_in, mask_out, missing_value, missing_permit)
subroutine horiz_interp_new_1d(Interp, lon_in, lat_in, lon_out, lat_out, verbose, interp_method, num_nbrs, max_dist, src_modulo, grid_at_center, mask_in, mask_out)
subroutine horiz_interp_solo_1d_src(data_in, lon_in, lat_in, lon_out, lat_out, data_out, verbose, mask_in, mask_out, interp_method, missing_value, missing_permit, num_nbrs, max_dist, src_modulo, grid_at_center)
character(len=input_str_length), dimension(:), allocatable, target, public input_nml_file
Definition: mpp.F90:1378
subroutine, public horiz_interp_conserve_del(Interp)
subroutine, public horiz_interp_spherical_init
integer, parameter, public conserve
subroutine, public horiz_interp_bicubic_del(Interp)
subroutine, public horiz_interp_bilinear_init
subroutine, public horiz_interp_conserve_init
subroutine, public horiz_interp_bicubic_init
subroutine horiz_interp_base_3d(Interp, data_in, data_out, verbose, mask_in, mask_out, missing_value, missing_permit, err_msg)
subroutine horiz_interp_new_1d_src(Interp, lon_in, lat_in, lon_out, lat_out, verbose, interp_method, num_nbrs, max_dist, src_modulo, grid_at_center, mask_in, mask_out, is_latlon_out)
subroutine, public horiz_interp_spherical_new(Interp, lon_in, lat_in, lon_out, lat_out, num_nbrs, max_dist, src_modulo)
subroutine, public horiz_interp_init
subroutine, public horiz_interp_spherical_del(Interp)
subroutine horiz_interp_new_1d_dst(Interp, lon_in, lat_in, lon_out, lat_out, verbose, interp_method, num_nbrs, max_dist, src_modulo, mask_in, mask_out, is_latlon_in)
subroutine horiz_interp_solo_2d(data_in, lon_in, lat_in, lon_out, lat_out, data_out, verbose, mask_in, mask_out, interp_method, missing_value, missing_permit, num_nbrs, max_dist, src_modulo)
subroutine horiz_interp_base_2d(Interp, data_in, data_out, verbose, mask_in, mask_out, missing_value, missing_permit, err_msg, new_missing_handle)
logical module_is_initialized
subroutine, public constants_init
dummy routine.
Definition: constants.F90:141
subroutine horiz_interp_solo_1d(data_in, lon_in, lat_in, lon_out, lat_out, data_out, verbose, mask_in, mask_out, interp_method, missing_value, missing_permit, num_nbrs, max_dist, src_modulo, grid_at_center)
real(fp), parameter, public pi
subroutine horiz_interp_solo_old(data_in, wb, sb, dx, dy, lon_out, lat_out, data_out, verbose, mask_in, mask_out)