FMS  2024.03
Flexible Modeling System
horiz_interp.F90
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 !***********************************************************************
19 !> @defgroup horiz_interp_mod horiz_interp_mod
20 !> @ingroup horiz_interp
21 !> @brief Performs spatial interpolation between grids.
22 !!
23 !> @author Zhi Liang, Bruce Wyman
24 !!
25 !! This module can interpolate data from any logically rectangular grid
26 !! to any logically rectangular grid. Four interpolation schems are used here:
27 !! conservative, bilinear, bicubic and inverse of square distance weighted.
28 !! The four interpolation schemes are implemented seperately in
29 !! horiz_interp_conserver_mod, horiz_interp_blinear_mod, horiz_interp_bicubic_mod
30 !! and horiz_interp_spherical_mod. bicubic interpolation requires the source grid
31 !! is regular lon/lat grid. User can choose the interpolation method in the
32 !! public interface horiz_interp_new through optional argument interp_method,
33 !! with acceptable value "conservative", "bilinear", "bicubic" and "spherical".
34 !! The default value is "conservative". There is an optional mask field for
35 !! missing input data. An optional output mask field may be used in conjunction with
36 !! the input mask to show where output data exists.
37 
38 module horiz_interp_mod
39 
40 !-----------------------------------------------------------------------
41 !
42 ! Performs spatial interpolation between grids.
43 !
44 !-----------------------------------------------------------------------
45 
46 use fms_mod, only: write_version_number, fms_error_handler
47 use fms_mod, only: check_nml_error
48 use mpp_mod, only: mpp_error, fatal, stdout, stdlog, mpp_min
49 use mpp_mod, only: input_nml_file, warning, mpp_pe, mpp_root_pe
50 use constants_mod, only: pi
51 use horiz_interp_type_mod, only: horiz_interp_type, assignment(=)
52 use horiz_interp_type_mod, only: conserve, bilinear, spherical, bicubic
53 use horiz_interp_conserve_mod, only: horiz_interp_conserve_init, horiz_interp_conserve
54 use horiz_interp_conserve_mod, only: horiz_interp_conserve_new, horiz_interp_conserve_del
55 use horiz_interp_bilinear_mod, only: horiz_interp_bilinear_init, horiz_interp_bilinear
56 use horiz_interp_bilinear_mod, only: horiz_interp_bilinear_new, horiz_interp_bilinear_del
57 use horiz_interp_bilinear_mod, only: horiz_interp_read_weights_bilinear
58 use horiz_interp_bicubic_mod, only: horiz_interp_bicubic_init, horiz_interp_bicubic
59 use horiz_interp_bicubic_mod, only: horiz_interp_bicubic_new, horiz_interp_bicubic_del
60 use horiz_interp_spherical_mod, only: horiz_interp_spherical_init, horiz_interp_spherical
61 use horiz_interp_spherical_mod, only: horiz_interp_spherical_new, horiz_interp_spherical_del
62 use platform_mod, only: r4_kind, r8_kind
63 
64  implicit none
65  private
66 
67 !---- interfaces ----
68 
71 
72 !> Allocates space and initializes a derived-type variable
73 !! that contains pre-computed interpolation indices and weights.
74 !!
75 !> Allocates space and initializes a derived-type variable
76 !! that contains pre-computed interpolation indices and weights
77 !! for improved performance of multiple interpolations between
78 !! the same grids. This routine does not need to be called if you
79 !! are doing a single grid-to-grid interpolation.
80 !!
81 !! @param lon_in
82 !! Longitude (in radians) for source data grid. You can pass 1-D lon_in to
83 !! represent the geographical longitude of regular lon/lat grid, or just
84 !! pass geographical longitude(lon_in is 2-D). The grid location may be
85 !! located at grid cell edge or center, decided by optional argument "grid_at_center".
86 !!
87 !! @param lat_in
88 !! Latitude (in radians) for source data grid. You can pass 1-D lat_in to
89 !! represent the geographical latitude of regular lon/lat grid, or just
90 !! pass geographical latitude(lat_in is 2-D). The grid location may be
91 !! located at grid cell edge or center, decided by optional argument "grid_at_center".
92 !!
93 !! @param lon_out
94 !! Longitude (in radians) for destination data grid. You can pass 1-D lon_out to
95 !! represent the geographical longitude of regular lon/lat grid, or just
96 !! pass geographical longitude(lon_out is 2-D). The grid location may be
97 !! located at grid cell edge or center, decided by optional argument "grid_at_center".
98 !!
99 !! @param lat_out
100 !! Latitude (in radians) for destination data grid. You can pass 1-D lat_out to
101 !! represent the geographical latitude of regular lon/lat grid, or just
102 !! pass geographical latitude(lat_out is 2-D). The grid location may be
103 !! located at grid cell edge or center, decided by optional argument "grid_at_center".
104 !!
105 !! @param verbose
106 !! Integer flag that controls the amount of printed output.
107 !! verbose = 0, no output; = 1, min,max,means; = 2, still more
108 !!
109 !! @param interp_method
110 !! interpolation method, = "conservative", using conservation scheme,
111 !! = "bilinear", using bilinear interpolation, = "spherical",using spherical regrid.
112 !! = "bicubic", using bicubic interpolation. The default value is "convervative".
113 !!
114 !! @param src_modulo
115 !! Indicate the source data grid is cyclic or not.
116 !!
117 !! @param grid_at_center
118 !! Indicate the data is on the center of grid box or the edge of grid box.
119 !! When true, the data is on the center of grid box. default vaule is false.
120 !! This option is only available when interp_method = "bilinear" or "bicubic".
121 !!
122 !! @param Interp
123 !! A derived-type variable containing indices and weights used for subsequent
124 !! interpolations. To reinitialize this variable for a different grid-to-grid
125 !! interpolation you must first use the "horiz_interp_del" interface.
127  ! Source grid is 1d, destination grid is 1d
128  module procedure horiz_interp_new_1d_r4
129  module procedure horiz_interp_new_1d_r8
130  ! Source grid is 1d, destination grid is 2d
131  module procedure horiz_interp_new_1d_src_r4
132  module procedure horiz_interp_new_1d_src_r8
133  ! Source grid is 2d, destination grid is 2d
134  module procedure horiz_interp_new_2d_r4
135  module procedure horiz_interp_new_2d_r8
136  ! Source grid is 2d, destination grid is 1d
137  module procedure horiz_interp_new_1d_dst_r4
138  module procedure horiz_interp_new_1d_dst_r8
139  end interface
140 
141  !> Subroutines for reading in weight files and using that to fill in the horiz_interp type instead
142  !! calculating it
144  module procedure horiz_interp_read_weights_r4
145  module procedure horiz_interp_read_weights_r8
146  end interface horiz_interp_read_weights
147 
148 !> Subroutine for performing the horizontal interpolation between two grids.
149 !!
150 !> Subroutine for performing the horizontal interpolation between
151 !! two grids. There are two forms of this interface.
152 !! Form A requires first calling horiz_interp_new, while Form B
153 !! requires no initialization.
154 !!
155 !! @param Interp
156 !! Derived-type variable containing interpolation indices and weights.
157 !! Returned by a previous call to horiz_interp_new.
158 !!
159 !! @param data_in
160 !! Input data on source grid.
161 !!
162 !! @param verbose
163 !! flag for the amount of print output.
164 !! verbose = 0, no output; = 1, min,max,means; = 2, still more
165 !!
166 !! @param 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 !!
172 !! @param missing_value
173 !! Use the missing_value to indicate missing data.
174 !!
175 !! @param missing_permit
176 !! numbers of points allowed to miss for the bilinear interpolation. The value
177 !! should be between 0 and 3.
178 !!
179 !! @param 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 !!
183 !! @param 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 !!
187 !! @param data_out
188 !! Output data on destination grid.
189 !!
190 !! @param mask_out
191 !! Output mask that specifies whether data was computed.
192 !!
193 !!
194 !! @throws FATAL, size of input array incorrect
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 !!
199 !! @throws FATAL, size of output array incorrect
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 !> @ingroup horiz_interp_mod
204  interface horiz_interp
205  module procedure horiz_interp_base_2d_r4
206  module procedure horiz_interp_base_2d_r8
207  module procedure horiz_interp_base_3d_r4
208  module procedure horiz_interp_base_3d_r8
209  module procedure horiz_interp_solo_1d_r4
210  module procedure horiz_interp_solo_1d_r8
211  module procedure horiz_interp_solo_1d_src_r4
212  module procedure horiz_interp_solo_1d_src_r8
213  module procedure horiz_interp_solo_2d_r4
214  module procedure horiz_interp_solo_2d_r8
215  module procedure horiz_interp_solo_1d_dst_r4
216  module procedure horiz_interp_solo_1d_dst_r8
217  module procedure horiz_interp_solo_old_r4
218  module procedure horiz_interp_solo_old_r8
219  end interface
220 
221 !> Private helper routines
222 interface is_lat_lon
223  module procedure is_lat_lon_r4
224  module procedure is_lat_lon_r8
225 end interface
226 
228  module procedure horiz_interp_solo_1d_r4
229  module procedure horiz_interp_solo_1d_r8
230 end interface
231 
232 
233 !> @addtogroup horiz_interp_mod
234 !> @{
235 
236  logical :: reproduce_siena = .false. !< Set reproduce_siena = .true. to reproduce siena results.
237  !! Set reproduce_siena = .false. to decrease truncation error
238  !! in routine poly_area in file mosaic_util.c. The truncation error of
239  !! second order conservative remapping might be big for high resolution
240  !! grid.
241 
242  namelist /horiz_interp_nml/ reproduce_siena
243 
244 !-----------------------------------------------------------------------
245 ! Include variable "version" to be written to log file.
246 #include<file_version.h>
247  logical :: module_is_initialized = .false.
248 !-----------------------------------------------------------------------
249 
250 contains
251 
252 !#######################################################################
253 
254  !> Initialize module and writes version number to logfile.out
255  subroutine horiz_interp_init
256  integer :: iunit, ierr, io
257 
258  if(module_is_initialized) return
259  call write_version_number("HORIZ_INTERP_MOD", version)
260 
261  read (input_nml_file, horiz_interp_nml, iostat=io)
262  ierr = check_nml_error(io,'horiz_interp_nml')
263  if (mpp_pe() == mpp_root_pe() ) then
264  iunit = stdlog()
265  write (iunit, nml=horiz_interp_nml)
266  endif
267 
268  if (reproduce_siena) then
269  call mpp_error(fatal, "horiz_interp_mod: You have overridden the default value of " // &
270  "reproduce_siena and set it to .true. in horiz_interp_nml. This was a temporary workaround to " // &
271  "allow for consistency in continuing experiments and is no longer supported. " // &
272  "Please remove this namelist.")
273  endif
274 
275  call horiz_interp_conserve_init
276  call horiz_interp_bilinear_init
277  call horiz_interp_bicubic_init
278  call horiz_interp_spherical_init
279 
280  module_is_initialized = .true.
281 
282  end subroutine horiz_interp_init
283 
284 !> Deallocates memory used by "horiz_interp_type" variables.
285 !! Must be called before reinitializing with horiz_interp_new.
286  subroutine horiz_interp_del ( Interp )
287 
288  type (horiz_interp_type), intent(inout) :: interp !< A derived-type variable returned by previous
289  !! call to horiz_interp_new. The input variable must have
290  !! allocated arrays. The returned variable will contain
291  !! deallocated arrays
292 
293 !-----------------------------------------------------------------------
294 ! releases space used by horiz_interp_type variables
295 ! must be called before re-initializing the same variable
296 !-----------------------------------------------------------------------
297  select case(interp % interp_method)
298  case (conserve)
299  call horiz_interp_conserve_del(interp )
300  case (bilinear)
301  call horiz_interp_bilinear_del(interp )
302  case (bicubic)
303  call horiz_interp_bicubic_del(interp )
304  case (spherical)
305  call horiz_interp_spherical_del(interp )
306  end select
307 
308  interp%I_am_initialized = .false.
309 !-----------------------------------------------------------------------
310 
311  end subroutine horiz_interp_del
312 
313  !#####################################################################
314 
315  !> Dummy routine
316  subroutine horiz_interp_end
317  return
318  end subroutine horiz_interp_end
319 
320 #include "horiz_interp_r4.fh"
321 #include "horiz_interp_r8.fh"
322 
323 end module horiz_interp_mod
324 !> @}
325 ! close documentation grouping
integer function, public check_nml_error(IOSTAT, NML_NAME)
Checks the iostat argument that is returned after reading a namelist and determines if the error code...
Definition: fms.F90:580
subroutine, public write_version_number(version, tag, unit)
Prints to the log file (or a specified unit) the version id string and tag name.
Definition: fms.F90:758
logical function, public fms_error_handler(routine, message, err_msg)
Facilitates the control of fatal error conditions.
Definition: fms.F90:525
subroutine, public horiz_interp_bicubic_del(Interp)
Free memory from a horiz_interp_type used for bicubic interpolation (allocated via horiz_bicubic_new)
subroutine, public horiz_interp_bicubic_init
Initializes module and writes version number to logfile.out.
Creates a new horiz_interp_type for bicubic interpolation. Allocates space and initializes a derived-...
subroutine, public horiz_interp_bilinear_del(Interp)
Deallocates memory used by "horiz_interp_type" variables.
subroutine, public horiz_interp_bilinear_init
Initialize this module and writes version number to logfile.
Creates a horiz_interp_type for bilinear interpolation.
Subroutines for reading in weight files and using that to fill in the horiz_interp type instead calcu...
subroutine, public horiz_interp_conserve_init
Writes version number to logfile.
subroutine, public horiz_interp_conserve_del(Interp)
Deallocates memory used by "HI_KIND_TYPE" variables. Must be called before reinitializing with horiz_...
Allocates space and initializes a derived-type variable that contains pre-computed interpolation indi...
subroutine, public horiz_interp_del(Interp)
Deallocates memory used by "horiz_interp_type" variables. Must be called before reinitializing with h...
logical reproduce_siena
Set reproduce_siena = .true. to reproduce siena results. Set reproduce_siena = .false....
subroutine, public horiz_interp_init
Initialize module and writes version number to logfile.out.
subroutine, public horiz_interp_end
Dummy routine.
Subroutine for performing the horizontal interpolation between two grids.
subroutine, public horiz_interp_spherical_init
Initializes module and writes version number to logfile.out.
subroutine, public horiz_interp_spherical_del(Interp)
Deallocates memory used by "HI_KIND_TYPE" variables. Must be called before reinitializing with horiz_...
Holds data pointers and metadata for horizontal interpolations, passed between the horiz_interp modul...
integer function stdout()
This function returns the current standard fortran unit numbers for output.
Definition: mpp_util.inc:43
integer function stdlog()
This function returns the current standard fortran unit numbers for log messages. Log messages,...
Definition: mpp_util.inc:59
integer function mpp_pe()
Returns processor ID.
Definition: mpp_util.inc:407
Error handler.
Definition: mpp.F90:382
Reduction operations. Find the min of scalar a from the PEs in pelist result is also automatically br...
Definition: mpp.F90:560
Perform bicubic horizontal interpolation.
Allocates space and initializes a derived-type variable that contains pre-computed interpolation indi...
Subroutines for reading in weight files and using that to fill in the horiz_interp type instead calcu...
Private helper routines.