WAVEWATCH III  beta 0.0.1
w3gsrumd.F90
Go to the documentation of this file.
1 !/ =================================================================== /
2 !/ Define the ENABLE_WW3 macro when compiling within Wavewatch III.
3 !/
4 !/ When compiling outside of Wavewatch III the ENABLE_WW3 must be
5 !/ undefined and the ENABLE_MPI macro must be defined if compiling
6 !/ with MPI.
7 !/ =================================================================== /
8 #define ENABLE_WW3
9 
10 
11 
12 
13 #ifdef ENABLE_WW3
14 #include "w3macros.h"
15 #endif
16 !/ =================================================================== /
17 MODULE w3gsrumd
18  !/
19  !/ +-----------------------------------+
20  !/ | WAVEWATCH III NOAA/NCEP |
21  !/ | T. J. Campbell, NRL |
22  !/ | FORTRAN 90 |
23  !/ | Last update : 25-Jan-2017 |
24  !/ +-----------------------------------+
25  !/
26  !/ 30-Oct-2009 : Origination. ( version 3.14 )
27  !/ 14-Jun-2010 : Fix for ACOS argument > 1 in W3DIST ( version 3.14 )
28  !/ 12-Nov-2010 : Change T_NNS, W3NN*, W3SORT, W3ISRT to public.
29  !/ Add W3GFIJ (public). Implement r4 & r8 interfaces.
30  !/ Add subcell check for grid cell that includes a pole.
31  !/ Change to number of search buckets based on
32  !/ dimensions of input grid. ( version 3.14 )
33  !/ 01-Dec-2010 : Assign cells to buckets based on overlap. The
34  !/ nearest-neighbor bucket search is removed (no longer
35  !/ needed). Add support for tripole grids (JCLO).
36  !/ Add W3GFCD (public). Some cleanup. Add ouput of
37  !/ approximate memory usage. ( version 3.14 )
38  !/ 01-Dec-2010 : Add check for target point coincident with a cell
39  !/ vertex in W3RMBL. Change to error exit when unable
40  !/ to determine local (i,j). ( version 3.14 )
41  !/ 06-Dec-2010 : Remove restriction on longitude range. Change ICLO
42  !/ to integer and remove JCLO. Implement support for
43  !/ r4 and r8 source grids. ( version 3.14 )
44  !/ 15-Jun-2012 : Fixed various format statements that gave compile
45  !/ warnings with Intel compiler on NCEP R&D machine
46  !/ zeus (H. L. Tolman) ( version 4.07 )
47  !/ 20-Jan-2017 : Moved all record of changes from subroutines to
48  !/ the top of the module and consolidate source code
49  !/ for procedure interfaces ( version 6.02 )
50  !/ 20-Jan-2017 : Generalize index bounds for source ( version 6.02 )
51  !/ 20-Jan-2017 : Fix tripole grid index mapping and implement
52  !/ additional index closure types. ( version 6.02 )
53  !/ 20-Jan-2017 : Add small non-zero tolerance to bounding box checks,
54  !/ point coincidence checks and checks for points that
55  !/ lie exactly on a cell side ( version 6.02 )
56  !/ 20-Jan-2017 : Add option to W3GFCL, W3GRMP, W3GFPT, and W3GFIJ to
57  !/ allow target outside of source grid ( version 6.02 )
58  !/ 20-Jan-2017 : Implement more accurate sin(d/2) equation in W3DIST
59  !/ for computing angular distance ( version 6.02 )
60  !/ 20-Jan-2017 : Implement stereographic projection for remapping
61  !/ from cells near a pole ( version 6.02 )
62  !/ 20-Jan-2017 : Add routine for computing metric and derivatives
63  !/ for a curvilinear grid and routines for computing
64  !/ gradient and divergence of fields defined on a
65  !/ curvilinear grid ( version 6.02 )
66  !/ 20-Jan-2017 : Add routine for computing computing bounding box
67  !/ for a curvilinear grid ( version 6.02 )
68  !/ 20-Jan-2017 : Add W3GRMC as generic routine for computing
69  !/ remapping coefficients ( version 6.02 )
70  !/ 25-Jan-2017 : Fix index offsets for MASK in W3GRMP and W3GRMC.
71  !/ Change redist to nearpt in W3GRMC. ( version 6.03 )
72  !/ 31-Oct-2017 : Add optional MASK input for W3CGDM. ( version 6.03 )
73  !/ 18-Jul-2018 : Add fall back to NFD = 2 in W3CGDM for metric
74  !/ calculations where GSQRL < 0. ( version 6.05 )
75  !/
76  ! 1. Purpose :
77  !
78  ! Search, regrid, and miscellaneous utilities (data structures and
79  ! associated methods) for logically rectangular grids.
80  !
81  ! The grid-search-utility (GSU) object can be used for rapid searching
82  ! of the associated grid to identify a grid cell that encloses a target
83  ! point and to compute interpolation weights. The GSU object maintains
84  ! internal pointers to the associated grid coordinate arrays. Rapid
85  ! searching is done using a bucket search algorithm. The search buckets
86  ! are based on the bounding box for the associated grid and an optional
87  ! user defined approximate number of grid cells per search bucket.
88  !
89  ! Grid cells are identified by the cell's lower-left corner grid point.
90  ! The vertices (grid points) associated with a grid cell are assigned a
91  ! sequential index in a counterclockwise order beginning with the cell's
92  ! lower-left corner grid point. That is, when moving from vertex 1 to
93  ! vertex 2 to vertex 3, etc., the grid cell interior is always to the left.
94  ! Note that though cell will be counterclockwise w.r.t. indices, this does
95  ! not necessarily mean that the cell will be counterclockwise geographically,
96  ! specifically in situation of curvilinear grid.
97  !
98  ! (x4,y4) (x3,y3)
99  ! _____________________
100  ! / /
101  ! / /
102  ! / /
103  ! / /
104  ! /____________________/
105  ! (x1,y1) (x2,y2)
106  !
107  !
108  ! A simple interpolation example:
109  !
110  ! -----------------------------------------------------------
111  ! ! Define data
112  ! TYPE(T_GSU) :: GSU
113  ! LOGICAL :: IJG = .TRUE.
114  ! LOGICAL :: LLG = .TRUE.
115  ! LOGICAL :: ICLO = ICLO_NONE
116  ! REAL, POINTER :: XS(:,:), YS(:,:) !source grid coordinates
117  ! REAL :: FS(:,:) !source field
118  ! INTEGER :: NT !number of target points
119  ! REAL :: XT(NT), YT(NT), FT(NT) !target coordinates and field
120  ! INTEGER :: IS(4), JS(4) !interpolation points
121  ! REAL :: RW(4) !interpolation weights
122  !
123  ! ! Setup source grid and field and target points
124  ! < ... >
125  !
126  ! ! Create grid-search-utility object for source grid
127  ! GSU = W3GSUC( IJG, LLG, ICLO, XS, YS )
128  !
129  ! ! Interpolate source field to target points
130  ! DO K=1,NT
131  ! FT(K) = 0
132  ! IF ( W3GRMP( GSU, XT(K), YT(K), IS, JS, RW ) ) THEN
133  ! DO L=1,4
134  ! FT(K) = FT(K) + RW(L)*FS(IS(L),JS(L))
135  ! END DO
136  ! END IF
137  ! END DO
138  !
139  ! ! Destroy grid-search-utility object
140  ! CALL W3GSUD( GSU )
141  ! -----------------------------------------------------------
142  !
143  ! 2. Variables and types :
144  !
145  ! All module variables and types are scoped private by default.
146  ! The private module variables and types are not listed in this section.
147  !
148  ! Name Type Scope Description
149  ! ----------------------------------------------------------------
150  ! MSKC_NONE I.P. Public Named constant identifying a non-masked
151  ! enclosing grid cell
152  ! MSKC_PART I.P. Public Named constant identifying a partially
153  ! masked enclosing grid cell
154  ! MSKC_FULL I.P. Public Named constant identifying a fully
155  ! masked enclosing grid cell
156  ! ICLO_NONE I.P. Public Named constant identifying a grid with
157  ! no closure in index space
158  ! ICLO_SMPL I.P. Public Synonym for ICLO_GRDI
159  ! ICLO_GRDI I.P. Public Named constant identifying a grid with
160  ! closure in I-index: (UBX+1, j) => (LBX, j)
161  ! ICLO_GRDJ I.P. Public Named constant identifying a grid with
162  ! closure in J-index: (i, UBY+1) => (i, LBY)
163  ! ICLO_TRDL I.P. Public Named constant identifying a grid with
164  ! toroidal closure: (UBX+1, j) => (LBX, j) and
165  ! (i, UBY+1) => (i, LBY)
166  ! ICLO_TRPL I.P. Public Named constant identifying a grid with
167  ! tripole closure: (UBX+1, LBY<=j<=UBY) => (LBX, j)
168  ! and (LBX<=i<=UBX, UBY+1) => (UBX+LBX-i, UBY)
169  ! T_GSU TYPE Public Grid-search-utility type (opaque)
170  ! T_NNS TYPE Public Nearest-neighbor grid-point search type
171  ! ----------------------------------------------------------------
172  !
173  ! 3. Subroutines and functions :
174  !
175  ! All module subroutines and functions are scoped private by default.
176  !
177  ! Name Type Scope Description
178  ! ----------------------------------------------------------------
179  ! W3GSUC Func. Public Create grid-search-utility object.
180  ! W3GSUD Subr. Public Destroy grid-search-utility object.
181  ! W3GSUP Subr. Public Print grid-search-utility object to stdout.
182  ! W3BBOX Subr. Public Get bounding box associated with grid.
183  ! W3GFCL Func. Public Find grid cell that encloses target point (bucket search).
184  ! W3GFCD Func. Public Find grid cell that encloses target point (direct search).
185  ! W3GFPT Func. Public Find grid point that is closest to target point.
186  ! W3GFIJ Func. Public Compute coord of target point in source grid index space
187  ! W3GRMP Func. Public Compute bilinear interpolation coeff. from grid.
188  ! W3GRMC Func. Public Compute remapping coeff. from grid.
189  ! W3CKCL Func. Public Check if point lies within grid cell.
190  ! W3CGDM Func. Public Compute curvilinear grid derivatives and metric
191  ! W3GRD0 Func. Public Compute gradient of scalar field
192  ! W3DIV1 Func. Public Compute divergence of a vector field
193  ! W3DIV2 Func. Public Compute divergence of a tensor field
194  ! W3DIST Func. Public Compute distance between two points.
195  ! W3SPLX Func. Public Compute Cartesian coord using stereographic projection
196  ! W3SPXL Func. Public Compute (lon,lat) coord using stereographic projection
197  ! W3TRLL Func. Public Compute (lon,lat) in rotated coordinate system
198  ! W3LLAZ Func. Public Compute azimuth for pair of (lon,lat) points
199  ! W3FDWT Func. Public Compute finite-difference weights.
200  ! W3NNSC Func. Public Create nearest-neighbor-search object.
201  ! W3NNSD Subr. Public Destroy nearest-neighbor-search object.
202  ! W3NNSP Subr. Public Print nearest-neighbor-search object to stdout.
203  ! W3SORT Subr. Public Sort input arrays in increasing order.
204  ! W3ISRT Subr. Public Insert data into array.
205  ! W3INAN Func. Public Check if input is infinite or NaN.
206  ! ----------------------------------------------------------------
207  !
208  ! 4. Subroutines and functions used :
209  !
210  ! Name Type Module Description
211  ! ----------------------------------------------------------------
212  ! STRACE Subr. W3SERVMD Subroutine tracing.
213  ! EXTCDE Subr. W3SERVMD Abort program with exit code.
214  ! ----------------------------------------------------------------
215  !
216  ! 5. Remarks :
217  !
218  ! - The GSU object is an "opaque" object. This means that the
219  ! internals of the object are not accessible outside this module.
220  ! - The burden is upon the user to invoke the destroy method when
221  ! finished with a GSU object. If created GSU objects are
222  ! not properly destroyed, then memory leaks may be introduced.
223  !
224  ! 6. Switches :
225  !
226  ! !/S Enable subroutine tracing.
227  !
228  ! 7. Source code :
229  !
230  !/ =================================================================== /
231  !/
232  !/ Use associated modules
233  !/
234 #ifdef ENABLE_WW3
235  USE w3servmd, ONLY: extcde
236 #endif
237 #ifdef W3_S
238  USE w3servmd, ONLY: strace
239 #endif
240  !/
241  !/ Specify default data typing
242  !/
243  IMPLICIT NONE
244  !/
245  !/ Specify default accessibility
246  !/
247  PRIVATE
248  !/
249  !/ Public module methods
250  !/
251  PUBLIC w3gsuc
252  PUBLIC w3gsud
253  PUBLIC w3gsup
254  PUBLIC w3bbox
255  PUBLIC w3gfcl
256  PUBLIC w3gfcd
257  PUBLIC w3gfpt
258  PUBLIC w3gfij
259  PUBLIC w3grmp
260  PUBLIC w3grmc
261  PUBLIC w3ckcl
262  PUBLIC w3cgdm
263  PUBLIC w3grd0
264  PUBLIC w3div1
265  PUBLIC w3div2
266  PUBLIC w3dist
267  PUBLIC w3splx
268  PUBLIC w3spxl
269  PUBLIC w3trll
270  PUBLIC w3llaz
271  PUBLIC w3fdwt
272  PUBLIC w3nnsc
273  PUBLIC w3nnsd
274  PUBLIC w3nnsp
275  PUBLIC w3sort
276  PUBLIC w3isrt
277  PUBLIC w3inan
278  !/
279  !/ Public return codes
280  !/
281  INTEGER, PARAMETER, PUBLIC :: mskc_none = 0
282  INTEGER, PARAMETER, PUBLIC :: mskc_part = 1
283  INTEGER, PARAMETER, PUBLIC :: mskc_full = 2
284  !/
285  !/ Public index closure types (for lat/lon grids only)
286  !/ ICLO_NONE : no closure in index space
287  !/ ICLO_SMPL : synonym for ICLO_GRDI
288  !/ ICLO_GRDI : closure in i-index at i=UBX+1: (UBX+1, j) => (LBX, j)
289  !/ ICLO_GRDJ : closure in j-index at j=UBY+1: (i, UBY+1) => (i, LBY)
290  !/ ICLO_TRDL : toroidal grid closure: (UBX+1, j) => (LBX, j) and
291  !/ (i, UBY+1) => (i, LBY)
292  !/ ICLO_TRPL : tripole grid closure: (UBX+1, LBY<=j<=UBY) => (LBX, j) and
293  !/ (LBX<=i<=UBX, UBY+1) => (UBX+LBX-i, UBY)
294  !/
295  !/ Note that simple i-index closure types are set to multiples of 2.
296  !/ Note that simple j-index closure types are set to multiples of 3.
297  !/ These settings are used in the GSU methods to simplify checking.
298  !/
299  !/ Implementation notes on index closure:
300  !/ Simple closure in i-index means that a given integer i' is mapped to the
301  !/ range [LBX,UBX]. When i' >= LBX, the function i = LBX + MOD(i'-LBX,NX)
302  !/ maps i' to i in [LBX,UBX] (where, NX = UBX - LBX + 1). The function
303  !/ i = UBX + MOD(i'-LBX+1,NX) maps any integer i' to i in [LBX,INF). Hence,
304  !/ the following composition is used to map any integer i' to [LBX,UBX].
305  !/ i = LBX + MOD(NX - 1 + MOD(i' - LBX + 1, NX), NX)
306  !/ Similarly, for simple closure in j-index, the following composition is used
307  !/ to map any integer j' to [LBY,UBY].
308  !/ j = LBY + MOD(NY - 1 + MOD(j' - LBY + 1, NY), NY)
309  !/ For tripole type index closure, the simple closure in i-index is appied
310  !/ prior to computing the appropriate i and j-index mapping for closure across
311  !/ the seam at j = UBY. The j-index closure for i' in [LBX,UBX] and j' > UBY
312  !/ is computed as i = UBX + LBX - i' and j = 2*UBY - j' + 1.
313  !/
314  INTEGER, PARAMETER, PUBLIC :: iclo_none = -1
315  INTEGER, PARAMETER, PUBLIC :: iclo_smpl = 2
316  INTEGER, PARAMETER, PUBLIC :: iclo_grdi = iclo_smpl
317  INTEGER, PARAMETER, PUBLIC :: iclo_grdj = 3
318  INTEGER, PARAMETER, PUBLIC :: iclo_trdl = 6
319  INTEGER, PARAMETER, PUBLIC :: iclo_trpl = 8
320  !/
321  !/ Public grid-search-utility type
322  !/ This is an opaque type -- that is, it's internals are private and only
323  !/ accessible to subroutines in this module where the type is declared.
324  !/
325  TYPE, PUBLIC :: t_gsu
326  PRIVATE
327  TYPE(class_gsu), POINTER :: ptr => null()
328  END TYPE t_gsu
329  !/
330  !/ Private grid-search-utility class
331  !/
332  TYPE :: class_gsu
333  LOGICAL :: ijg ! grid array ordering flag: T = (NX,NY), F = (NY,NX)
334  LOGICAL :: llg ! spherical coordinate flag of associated grid
335  INTEGER :: iclo ! parameter indicating type of index space closure
336  ! this flag must be set by the user
337  LOGICAL :: lclo ! flag indicating longitudinal periodicity
338  ! this flag is calculated internally
339  ! LLG & ICLO != ICLO_NONE => LCLO = T
340  LOGICAL :: l360 ! flag indicating longitude range:
341  ! T = [0:360], F = [-180:180]
342  INTEGER :: gkind ! kind (precision: 4 or 8) of associated grid
343  INTEGER :: lbx, lby ! lower-bounds of associated grid
344  INTEGER :: ubx, uby ! upper-bounds of associated grid
345  INTEGER :: nx, ny ! dimensions of associated grid
346  REAL(4), POINTER :: xg4(:,:), yg4(:,:) ! coordinates of associated grid (r4)
347  REAL(8), POINTER :: xg8(:,:), yg8(:,:) ! coordinates of associated grid (r8)
348  TYPE(t_nns), POINTER :: nnp ! nearest-neighbor point search indices object
349  INTEGER :: nbx, nby ! number of buckets in each spatial direction
350  REAL(8) :: dxb, dyb ! spatial extent of each search bucket
351  REAL(8) :: xmin, ymin, xmax, ymax ! bounding box of search domain
352  TYPE(t_bkt), POINTER :: b(:,:) ! array of search buckets
353  TYPE(t_nns), POINTER :: nnb ! nearest-neighbor bucket search indices object
354  END TYPE class_gsu
355  !/
356  !/ Private search bucket type
357  !/
358  TYPE :: t_bkt
359  INTEGER :: n ! number of cells in bucket
360  INTEGER, POINTER :: i(:) ! i-index of cell c
361  INTEGER, POINTER :: j(:) ! j-index of cell c
362  END TYPE t_bkt
363  !/
364  !/ Public nearest-neighbor grid-point search type
365  !/
366  TYPE, PUBLIC :: t_nns
367  INTEGER :: nlvl ! number of nnbr levels
368  INTEGER :: nnbr ! total number of nnbr's
369  INTEGER, POINTER :: n1(:) ! starting nearest-nbr loop index for level l
370  INTEGER, POINTER :: n2(:) ! ending nearest-nbr loop index for level l
371  INTEGER, POINTER :: di(:) ! i-index delta for nearest-nbr n
372  INTEGER, POINTER :: dj(:) ! j-index delta for nearest-nbr n
373  END TYPE t_nns
374  !/
375  !/ Private module parameters
376  !/
377  REAL(8), PARAMETER :: pi = 3.14159265358979323846d0
378  REAL(8), PARAMETER :: pi2 = 2d0*pi
379  REAL(8), PARAMETER :: pi3h = 3d0*pi/2d0
380  REAL(8), PARAMETER :: pio2 = pi/2d0
381  REAL(8), PARAMETER :: pio4 = pi/4d0
382  REAL(8), PARAMETER :: d2r = pi/180d0
383  REAL(8), PARAMETER :: r2d = 1d0/d2r
384  REAL(8), PARAMETER :: d360 = 360d0
385  REAL(8), PARAMETER :: d270 = 270d0
386  REAL(8), PARAMETER :: d180 = 180d0
387  REAL(8), PARAMETER :: d90 = 90d0
388  REAL(8), PARAMETER :: zero = 0.0d0
389  REAL(8), PARAMETER :: half = 0.5d0
390  REAL(8), PARAMETER :: one = 1.0d0
391  REAL(8), PARAMETER :: two = 2.0d0
392  REAL(8), PARAMETER :: four = 4.0d0
393 #if defined(COAMPS)
394  REAL(8), PARAMETER :: rearth = 6371229.d0
395 #else
396  REAL(8), PARAMETER :: rearth = 4.d7/pi2 !this gives D2M = 111111.111111
397 #endif
398  REAL(8), PARAMETER :: d2m = rearth*d2r
399  REAL(8), PARAMETER :: m2d = 1d0/d2m
400  ! Default small non-zero tolerance used to check if
401  ! target point is in domain and for point coincidence.
402  REAL(8), PARAMETER :: eps_default = 1.0d-6
403  ! Distance (deg) from pole to consider a cell "near the pole"
404  REAL(8), PARAMETER :: near_pole = 10.0d0
405  ! Default number of grid cells (in each direction) per search bucket.
406  INTEGER, PARAMETER :: ncb_default = 10
407  ! Default maximum number of nearest-neighbor grid point search levels.
408  INTEGER, PARAMETER :: nnp_default = 2
409  ! Max number of non-empty levels for bucket search when target point
410  ! is outside source domain
411  INTEGER, PARAMETER :: max_fncl_level = 3
412  ! Default finite-difference order
413  INTEGER, PARAMETER :: nfd_default = 4
414  !/
415  !/ Module Interfaces
416  !/
417  INTERFACE w3gsuc
418  MODULE PROCEDURE w3gsuc_ptr_r4
419  MODULE PROCEDURE w3gsuc_ptr_r8
420  MODULE PROCEDURE w3gsuc_tgt_r4
421  MODULE PROCEDURE w3gsuc_tgt_r8
422  END INTERFACE w3gsuc
423  INTERFACE w3bbox
424  MODULE PROCEDURE w3bbox_gsu
425  MODULE PROCEDURE w3bbox_grd_ptr_r4
426  MODULE PROCEDURE w3bbox_grd_ptr_r8
427  MODULE PROCEDURE w3bbox_grd_tgt_r4
428  MODULE PROCEDURE w3bbox_grd_tgt_r8
429  END INTERFACE w3bbox
430  INTERFACE w3gfcl
431  MODULE PROCEDURE w3gfcl_r4
432  MODULE PROCEDURE w3gfcl_r8
433  END INTERFACE w3gfcl
434  INTERFACE w3gfcd
435  MODULE PROCEDURE w3gfcd_r4
436  MODULE PROCEDURE w3gfcd_r8
437  END INTERFACE w3gfcd
438  INTERFACE w3gfpt
439  MODULE PROCEDURE w3gfpt_r4
440  MODULE PROCEDURE w3gfpt_r8
441  END INTERFACE w3gfpt
442  INTERFACE w3gfij
443  MODULE PROCEDURE w3gfij_r4
444  MODULE PROCEDURE w3gfij_r8
445  END INTERFACE w3gfij
446  INTERFACE w3grmp
447  MODULE PROCEDURE w3grmp_r4
448  MODULE PROCEDURE w3grmp_r8
449  END INTERFACE w3grmp
450  INTERFACE w3grmc
451  MODULE PROCEDURE w3grmc_r4
452  MODULE PROCEDURE w3grmc_r8
453  END INTERFACE w3grmc
454  INTERFACE w3cgdm
455  MODULE PROCEDURE w3cgdm_r4
456  MODULE PROCEDURE w3cgdm_r8
457  END INTERFACE w3cgdm
458  INTERFACE w3grd0
459  MODULE PROCEDURE w3grd0_r4
460  MODULE PROCEDURE w3grd0_r8
461  END INTERFACE w3grd0
462  INTERFACE w3div1
463  MODULE PROCEDURE w3div1_r4
464  MODULE PROCEDURE w3div1_r8
465  END INTERFACE w3div1
466  INTERFACE w3div2
467  MODULE PROCEDURE w3div2_r4
468  MODULE PROCEDURE w3div2_r8
469  END INTERFACE w3div2
470  INTERFACE w3dist
471  MODULE PROCEDURE w3dist_r4
472  MODULE PROCEDURE w3dist_r8
473  END INTERFACE w3dist
474  INTERFACE w3splx
475  MODULE PROCEDURE w3splx_0d_r4
476  MODULE PROCEDURE w3splx_0d_r8
477  MODULE PROCEDURE w3splx_1d_r4
478  MODULE PROCEDURE w3splx_1d_r8
479  MODULE PROCEDURE w3splx_2d_r4
480  MODULE PROCEDURE w3splx_2d_r8
481  END INTERFACE w3splx
482  INTERFACE w3spxl
483  MODULE PROCEDURE w3spxl_0d_r4
484  MODULE PROCEDURE w3spxl_0d_r8
485  MODULE PROCEDURE w3spxl_1d_r4
486  MODULE PROCEDURE w3spxl_1d_r8
487  MODULE PROCEDURE w3spxl_2d_r4
488  MODULE PROCEDURE w3spxl_2d_r8
489  END INTERFACE w3spxl
490  INTERFACE w3trll
491  MODULE PROCEDURE w3trll_0d_r4
492  MODULE PROCEDURE w3trll_0d_r8
493  MODULE PROCEDURE w3trll_1d_r4
494  MODULE PROCEDURE w3trll_1d_r8
495  MODULE PROCEDURE w3trll_2d_r4
496  MODULE PROCEDURE w3trll_2d_r8
497  END INTERFACE w3trll
498  INTERFACE w3llaz
499  MODULE PROCEDURE w3llaz_r4
500  MODULE PROCEDURE w3llaz_r8
501  END INTERFACE w3llaz
502  INTERFACE w3fdwt
503  MODULE PROCEDURE w3fdwt_r4
504  MODULE PROCEDURE w3fdwt_r8
505  END INTERFACE w3fdwt
506  INTERFACE w3ckcl
507  MODULE PROCEDURE w3ckcl_r4
508  MODULE PROCEDURE w3ckcl_r8
509  END INTERFACE w3ckcl
510  INTERFACE w3sort
511  MODULE PROCEDURE w3sort_r4
512  MODULE PROCEDURE w3sort_r8
513  END INTERFACE w3sort
514  INTERFACE w3isrt
515  MODULE PROCEDURE w3isrt_r4
516  MODULE PROCEDURE w3isrt_r8
517  END INTERFACE w3isrt
518  INTERFACE w3inan
519  MODULE PROCEDURE w3inan_r4
520  MODULE PROCEDURE w3inan_r8
521  END INTERFACE w3inan
522 
523  !/
524 CONTAINS
525  !/
526  !/ =================================================================== /
527  !/
528 
529 
530 
531 
532 
533 
534 
535 
536  !/
537  !/ =================================================================== /
538  !/
539  !/ FUNCTION W3GSUC( IJG, LLG, ICLO, XG, YG, &
540  !/ NCB, NNP, DEBUG ) RESULT(GSU)
541  !/ OR
542  !/ FUNCTION W3GSUC( IJG, LLG, ICLO, LB, UB, XG, YG, &
543  !/ NCB, NNP, DEBUG ) RESULT(GSU)
544  !/
545  !/ =================================================================== /
546  !/
547  ! 1. Purpose :
548  !
549  ! Create grid-search-utility (GSU) object for a logically rectangular
550  ! grid defined by the input coordinates.
551  !
552  ! 2. Method :
553  !
554  ! 3. Parameters :
555  !
556  ! Return parameter
557  ! ----------------------------------------------------------------
558  ! GSU Type O Created grid-search-utility object.
559  ! ----------------------------------------------------------------
560  !
561  ! Parameter list
562  ! ----------------------------------------------------------------
563  ! IJG Log. I Logical flag indicating ordering of input
564  ! coord. arrays: T = (NX,NY) and F = (NY,NX).
565  ! LLG Log. I Logical flag indicating the coordinate system:
566  ! T = spherical lat/lon (degrees) and F = Cartesian.
567  ! ICLO Int. I Parameter indicating type of index space closure
568  !
569  ! Inputs (for W3GSUC_PTR):
570  ! XG R.A. I Pointer to array of x-coordinates of input grid.
571  ! YG R.A. I Pointer to array of y-coordinates of input grid.
572  !
573  ! Inputs (for W3GSUC_TGT):
574  ! LB I.A. I Lower bounds of XG and YG arrays
575  ! UB I.A. I Upper bounds of XG and YG arrays
576  ! XG R.A. I Array of x-coordinates of input grid.
577  ! YG R.A. I Array of y-coordinates of input grid.
578  !
579  ! NCB Int. I OPTIONAL (approximate) number of cells (in each
580  ! direction) per search bucket. (default is NCB_DEFAULT)
581  ! NCB >= 1 is required. NCB = 1 gives most efficient
582  ! searching, but uses more memory. Increasing NCB leads
583  ! to fewer buckets (less memory) but slower searching.
584  ! NNP Int. I OPTIONAL maximum number of nearest-neighbor grid
585  ! point search levels. (default is NNP_DEFAULT)
586  ! DEBUG Log. I OPTIONAL logical flag to turn on debug mode.
587  ! Default is FALSE.
588  ! ----------------------------------------------------------------
589  !
590  ! 4. Subroutines used :
591  !
592  ! See module documentation.
593  !
594  ! 5. Called by :
595  !
596  ! 6. Error messages :
597  !
598  ! - Check on correct coordinate system with global grid.
599  ! - Check on association of input grid coordinate array pointers.
600  !
601  ! 7. Remarks :
602  !
603  ! - LCLO is calculated internally.
604  ! - LLG & ICLO != ICLO_NONE => LCLO = T.
605  ! - Periodic Cartesian grids are not allowed.
606  !
607  ! 8. Structure :
608  !
609  ! -----------------------------------------------------------------
610  ! 1. Test input
611  ! 2. Allocate object and set grid related data and pointers
612  ! 3. Create nearest-neighbor point search object
613  ! 4. Construct bucket search "object"
614  ! 5. Set return parameter
615  ! -----------------------------------------------------------------
616  !
617  ! 9. Switches :
618  !
619  ! !/S Enable subroutine tracing.
620  !
621  ! 10. Source code :
622  !/
623  !/ ------------------------------------------------------------------- /
624  !/
625  FUNCTION w3gsuc_ptr_r4( IJG, LLG, ICLO, XG, YG, &
626  NCB, NNP, DEBUG ) RESULT(GSU)
627  ! Single precision pointer interface
628  TYPE(t_gsu) :: gsu
629  LOGICAL, INTENT(IN) :: ijg
630  LOGICAL, INTENT(IN) :: llg
631  INTEGER, INTENT(IN) :: iclo
632  REAL(4), POINTER :: xg(:,:)
633  REAL(4), POINTER :: yg(:,:)
634  INTEGER, INTENT(IN), OPTIONAL :: ncb
635  INTEGER, INTENT(IN), OPTIONAL :: nnp
636  LOGICAL, INTENT(IN), OPTIONAL :: debug
637 
638  ! Local parameters
639  INTEGER :: lb(2), ub(2)
640 #ifdef W3_S
641  INTEGER, SAVE :: ient = 0
642  CALL strace (ient, 'W3GSUC_PTR_R4')
643 #endif
644  !
645  lb(1) = lbound(xg,1); lb(2) = lbound(xg,2)
646  ub(1) = ubound(xg,1); ub(2) = ubound(xg,2)
647  gsu = gsu_create( ijg, llg, iclo, lb, ub, xg4=xg, yg4=yg, &
648  ncb=ncb, nnp=nnp, debug=debug)
649 
650  END FUNCTION w3gsuc_ptr_r4
651  !/
652  !/ ------------------------------------------------------------------- /
653  !/
654  FUNCTION w3gsuc_ptr_r8( IJG, LLG, ICLO, XG, YG, &
655  NCB, NNP, DEBUG ) RESULT(GSU)
656  ! Double precision pointer interface
657  TYPE(t_gsu) :: gsu
658  LOGICAL, INTENT(IN) :: ijg
659  LOGICAL, INTENT(IN) :: llg
660  INTEGER, INTENT(IN) :: iclo
661  REAL(8), POINTER :: xg(:,:)
662  REAL(8), POINTER :: yg(:,:)
663  INTEGER, INTENT(IN), OPTIONAL :: ncb
664  INTEGER, INTENT(IN), OPTIONAL :: nnp
665  LOGICAL, INTENT(IN), OPTIONAL :: debug
666 
667  ! Local parameters
668  INTEGER :: lb(2), ub(2)
669 #ifdef W3_S
670  INTEGER, SAVE :: ient = 0
671  CALL strace (ient, 'W3GSUC_PTR_R4')
672 #endif
673  !
674  lb(1) = lbound(xg,1); lb(2) = lbound(xg,2)
675  ub(1) = ubound(xg,1); ub(2) = ubound(xg,2)
676  gsu = gsu_create( ijg, llg, iclo, lb, ub, xg8=xg, yg8=yg, &
677  ncb=ncb, nnp=nnp, debug=debug)
678 
679  END FUNCTION w3gsuc_ptr_r8
680  !/
681  !/ ------------------------------------------------------------------- /
682  !/
683  FUNCTION w3gsuc_tgt_r4( IJG, LLG, ICLO, LB, UB, XG, YG, &
684  NCB, NNP, DEBUG ) RESULT(GSU)
685  ! Single precision target interface
686  TYPE(t_gsu) :: gsu
687  LOGICAL, INTENT(IN) :: ijg
688  LOGICAL, INTENT(IN) :: llg
689  INTEGER, INTENT(IN) :: iclo
690  INTEGER, INTENT(IN) :: lb(2)
691  INTEGER, INTENT(IN) :: ub(2)
692  REAL(4), TARGET :: xg(lb(1):ub(1),lb(2):ub(2))
693  REAL(4), TARGET :: yg(lb(1):ub(1),lb(2):ub(2))
694  INTEGER, INTENT(IN), OPTIONAL :: ncb
695  INTEGER, INTENT(IN), OPTIONAL :: nnp
696  LOGICAL, INTENT(IN), OPTIONAL :: debug
697 
698  ! Local parameters
699 #ifdef W3_S
700  INTEGER, SAVE :: ient = 0
701  CALL strace (ient, 'W3GSUC_TGT_R4')
702 #endif
703  !
704  gsu = gsu_create( ijg, llg, iclo, lb, ub, xg4=xg, yg4=yg, &
705  ncb=ncb, nnp=nnp, debug=debug)
706 
707  END FUNCTION w3gsuc_tgt_r4
708  !/
709  !/ ------------------------------------------------------------------- /
710  !/
711  FUNCTION w3gsuc_tgt_r8( IJG, LLG, ICLO, LB, UB, XG, YG, &
712  NCB, NNP, DEBUG ) RESULT(GSU)
713  ! Double precision target interface
714  TYPE(t_gsu) :: gsu
715  LOGICAL, INTENT(IN) :: ijg
716  LOGICAL, INTENT(IN) :: llg
717  INTEGER, INTENT(IN) :: iclo
718  INTEGER, INTENT(IN) :: lb(2)
719  INTEGER, INTENT(IN) :: ub(2)
720  REAL(8), TARGET :: xg(lb(1):ub(1),lb(2):ub(2))
721  REAL(8), TARGET :: yg(lb(1):ub(1),lb(2):ub(2))
722  INTEGER, INTENT(IN), OPTIONAL :: ncb
723  INTEGER, INTENT(IN), OPTIONAL :: nnp
724  LOGICAL, INTENT(IN), OPTIONAL :: debug
725 
726  ! Local parameters
727 #ifdef W3_S
728  INTEGER, SAVE :: ient = 0
729  CALL strace (ient, 'W3GSUC_TGT_R8')
730 #endif
731  !
732  gsu = gsu_create( ijg, llg, iclo, lb, ub, xg8=xg, yg8=yg, &
733  ncb=ncb, nnp=nnp, debug=debug)
734 
735  END FUNCTION w3gsuc_tgt_r8
736  !/
737  !/ End of W3GSUC ===================================================== /
738  !/
739 
740 
741 
742 
743 
744 
745 
746 
747  !/
748  !/ =================================================================== /
749  !/
750  !/ SUBROUTINE W3GSUD( GSU )
751  !/
752  !/ =================================================================== /
753  !/
754  ! 1. Purpose :
755  !
756  ! Destroy grid search utility (GSU) object.
757  !
758  ! 2. Method :
759  !
760  ! 3. Parameters :
761  !
762  ! Parameter list
763  ! ----------------------------------------------------------------
764  ! GSU Type I Grid-search-utility object.
765  ! ----------------------------------------------------------------
766  !
767  ! 4. Subroutines used :
768  !
769  ! See module documentation.
770  !
771  ! 5. Called by :
772  !
773  ! 6. Error messages :
774  !
775  ! - Check on previous creation of grid-search-utility object.
776  !
777  ! 7. Remarks :
778  !
779  ! 8. Structure :
780  !
781  ! 9. Switches :
782  !
783  ! !/S Enable subroutine tracing.
784  !
785  ! 10. Source code :
786  !/
787  !/ ------------------------------------------------------------------- /
788  !/
789  SUBROUTINE w3gsud( GSU )
790  TYPE(t_gsu), INTENT(INOUT) :: gsu
791 
792  ! Local parameters
793  INTEGER :: ib, jb
794 #ifdef W3_S
795  INTEGER, SAVE :: ient = 0
796  CALL strace (ient, 'W3GSUD')
797 #endif
798  !
799  IF ( ASSOCIATED(gsu%PTR) ) THEN
800  !
801  CALL w3nnsd(gsu%PTR%NNP)
802  !
803  IF ( ASSOCIATED(gsu%PTR%B) ) THEN
804  DO ib=1,gsu%PTR%NBX
805  DO jb=1,gsu%PTR%NBY
806  IF ( gsu%PTR%B(jb,ib)%N .GT. 0 ) THEN
807  DEALLOCATE(gsu%PTR%B(jb,ib)%I)
808  NULLIFY(gsu%PTR%B(jb,ib)%I)
809  DEALLOCATE(gsu%PTR%B(jb,ib)%J)
810  NULLIFY(gsu%PTR%B(jb,ib)%J)
811  END IF
812  END DO
813  END DO
814  DEALLOCATE(gsu%PTR%B)
815  NULLIFY(gsu%PTR%B)
816  END IF
817  !
818  CALL w3nnsd(gsu%PTR%NNB)
819  !
820  DEALLOCATE(gsu%PTR)
821  NULLIFY(gsu%PTR)
822  !
823  END IF
824 
825  END SUBROUTINE w3gsud
826  !/
827  !/ End of W3GSUD ===================================================== /
828  !/
829 
830 
831 
832 
833 
834 
835 
836 
837  !/
838  !/ =================================================================== /
839  !/
840  !/ SUBROUTINE W3GSUP( GSU, IUNIT, LFULL )
841  !/
842  !/ =================================================================== /
843  !/
844  ! 1. Purpose :
845  !
846  ! Print grid-search-utility (GSU) object to IUNIT.
847  !
848  ! 2. Method :
849  !
850  ! 3. Parameters :
851  !
852  ! Parameter list
853  ! ----------------------------------------------------------------
854  ! GSU Type I Grid-search-utility object.
855  ! IUNIT Int. I OPTIONAL unit for output. Default is stdout.
856  ! LFULL Log. I OPTIONAL logical flag to turn on full-output
857  ! mode. Default is FALSE. When full-output
858  ! is enabled the search bucket cell lists and
859  ! nearest-neighbor point search indices are output.
860  ! ----------------------------------------------------------------
861  !
862  ! 4. Subroutines used :
863  !
864  ! See module documentation.
865  !
866  ! 5. Called by :
867  !
868  ! 6. Error messages :
869  !
870  ! - Check on previous creation of grid-search-utility object.
871  !
872  ! 7. Remarks :
873  !
874  ! 8. Structure :
875  !
876  ! 9. Switches :
877  !
878  ! !/S Enable subroutine tracing.
879  !
880  ! 10. Source code :
881  !/
882  !/ ------------------------------------------------------------------- /
883  !/
884  SUBROUTINE w3gsup( GSU, IUNIT, LFULL )
885  TYPE(t_gsu), INTENT(IN) :: gsu
886  INTEGER, OPTIONAL, INTENT(IN) :: iunit
887  LOGICAL, OPTIONAL, INTENT(IN) :: lfull
888 
889  ! Local parameters
890  INTEGER, PARAMETER :: nbyte_ptr=4
891  INTEGER, PARAMETER :: nbyte_int=4
892  TYPE(class_gsu), POINTER :: ptr
893  INTEGER :: ndst, k, ib, jb, nbyte
894 #ifdef W3_S
895  INTEGER, SAVE :: ient = 0
896  CALL strace (ient, 'W3GSUP')
897 #endif
898  !
899  ! -------------------------------------------------------------------- /
900  ! 1. Test input
901  !
902  IF ( .NOT.ASSOCIATED(gsu%PTR) ) THEN
903  WRITE(0,'(/1A,1A/)') 'W3GSUP ERROR -- ', &
904  'grid search utility object not created'
905  CALL extcde (1)
906  END IF
907 
908  IF ( PRESENT(iunit) ) THEN
909  ndst = iunit
910  ELSE
911  ndst = 6
912  END IF
913 
914  ptr => gsu%PTR
915  !
916  ! -------------------------------------------------------------------- /
917  ! 2. Compute approximate memory usage
918  !
919  nbyte = (nbyte_int+nbyte_ptr*2)*SIZE(ptr%B)
920  DO ib=1,ptr%NBX
921  DO jb=1,ptr%NBY
922  nbyte = nbyte + nbyte_int*2*ptr%B(jb,ib)%N
923  END DO
924  END DO
925  !
926  ! -------------------------------------------------------------------- /
927  ! 3. Output
928  !
929  WRITE(ndst,'(//80A)') ('-',k=1,80)
930  WRITE(ndst,'(A)') 'Report on grid search utility object'
931  WRITE(ndst,'( 80A)') ('-',k=1,80)
932  WRITE(ndst,'(A,1L2)') 'Grid ijg:',ptr%IJG
933  WRITE(ndst,'(A,1L2)') 'Grid llg:',ptr%LLG
934  WRITE(ndst,'(A,1I2)') 'Grid iclo:',ptr%ICLO
935  WRITE(ndst,'(A,1L2)') 'Grid lclo:',ptr%LCLO
936  WRITE(ndst,'(A,1I2)') 'Grid precision:',ptr%GKIND
937  WRITE(ndst,'(A,2I6)') 'Grid lbx,lby:',ptr%LBX,ptr%LBY
938  WRITE(ndst,'(A,2I6)') 'Grid ubx,uby:',ptr%UBX,ptr%UBY
939  WRITE(ndst,'(A,2I6)') 'Grid nx, ny:',ptr%NX,ptr%NY
940  IF ( PRESENT(lfull) ) THEN
941  IF ( lfull ) THEN
942  WRITE(ndst,'( 80A)') ('-',k=1,80)
943  WRITE(ndst,'(A)') 'Nearest-neighbor point search indices'
944  WRITE(ndst,'( 80A)') ('-',k=1,80)
945  CALL w3nnsp(ptr%NNP,ndst)
946  END IF
947  END IF
948  WRITE(ndst,'( 80A)') ('-',k=1,80)
949  WRITE(ndst,'(A)') 'Bucket-search object'
950  WRITE(ndst,'( 80A)') ('-',k=1,80)
951  WRITE(ndst,'(A,4E24.16)') 'Spatial grid search domain: ', &
952  ptr%XMIN,ptr%YMIN,ptr%XMAX,ptr%YMAX
953  WRITE(ndst,'(A,2I6)') 'nbx,nby:',ptr%NBX,ptr%NBY
954  WRITE(ndst,'(A,2E24.16)') 'dxb,dyb:',ptr%DXB,ptr%DYB
955  WRITE(ndst,'(A,1F10.1)') 'Approximate memory usage (MB):', &
956  REAL(nbyte)/2**20
957  IF ( PRESENT(lfull) ) THEN
958  IF ( lfull ) THEN
959  WRITE(ndst,'( 80A)') ('-',k=1,80)
960  WRITE(ndst,'(A)') 'Search bucket bounds:'
961  WRITE(ndst,'( 80A)') ('-',k=1,80)
962  WRITE(ndst,'(2A4,4A24)') 'IB','JB','X1','Y1','X2','Y2'
963  DO ib=1,ptr%NBX
964  DO jb=1,ptr%NBY
965  WRITE(ndst,'(2I4,4E24.16)') ib,jb, &
966  ptr%XMIN+(ib-1)*ptr%DXB,ptr%YMIN+(jb-1)*ptr%DYB, &
967  ptr%XMIN+(ib )*ptr%DXB,ptr%YMIN+(jb )*ptr%DYB
968  END DO
969  END DO
970  WRITE(ndst,'( 80A)') ('-',k=1,80)
971  WRITE(ndst,'(A)') 'Number of cells in each search bucket:'
972  WRITE(ndst,'( 80A)') ('-',k=1,80)
973  DO jb=ptr%NBY,1,-1
974  WRITE(ndst,'(500I4)') (ptr%B(jb,ib)%N,ib=1,ptr%NBX)
975  END DO
976  WRITE(ndst,'( 80A)') ('-',k=1,80)
977  WRITE(ndst,'(A)') 'Search bucket cell lists:'
978  WRITE(ndst,'( 80A)') ('-',k=1,80)
979  WRITE(ndst,'(3A4,A)') 'IB','JB','NC',': ( IC, JC), ...'
980  DO jb=1,ptr%NBY
981  DO ib=1,ptr%NBX
982  WRITE(ndst,'(3I4,A,500(A,I3,A,I3,A))') ib,jb, &
983  ptr%B(jb,ib)%N, ': ', &
984  ( '(',ptr%B(jb,ib)%I(k),',',ptr%B(jb,ib)%J(k),') ', &
985  k=1,ptr%B(jb,ib)%N )
986  END DO
987  END DO
988  WRITE(ndst,'( 80A)') ('-',k=1,80)
989  WRITE(ndst,'(A)') 'Nearest-neighbor bucket search indices'
990  WRITE(ndst,'( 80A)') ('-',k=1,80)
991  CALL w3nnsp(ptr%NNB,ndst)
992  END IF !LFULL
993  END IF !PRESENT(LFULL)
994  WRITE(ndst,'( 80A)') ('-',k=1,80)
995  WRITE(ndst,'( 80A)') ('-',k=1,80)
996 
997  END SUBROUTINE w3gsup
998  !/
999  !/ End of W3GSUP ===================================================== /
1000  !/
1001 
1002 
1003 
1004 
1005 
1006 
1007 
1008 
1009  !/
1010  !/ =================================================================== /
1011  !/
1012  !/ SUBROUTINE W3BBOX( GSU, XMIN, YMIN, XMAX, YMAX )
1013  !/ OR
1014  !/ SUBROUTINE W3BBOX( IJG, LLG, ICLO, XG, YG, XMIN, YMIN, XMAX, YMAX )
1015  !/ OR
1016  !/ SUBROUTINE W3BBOX( IJG, LLG, ICLO, LB, UB, XG, YG, XMIN, YMIN, XMAX, YMAX )
1017  !/
1018  !/ =================================================================== /
1019  !/
1020  ! 1. Purpose :
1021  !
1022  ! Get bounding box associated with grid.
1023  !
1024  ! 2. Method :
1025  !
1026  ! 3. Parameters :
1027  !
1028  ! Parameter list
1029  ! ----------------------------------------------------------------
1030  ! Inputs (for W3BBOX_GSU):
1031  ! GSU Type I Grid-search-utility object
1032  !
1033  ! Inputs (for W3BBOX_GRD_PTR):
1034  ! IJG Log. I Logical flag indicating ordering of input
1035  ! coord. arrays: T = (NX,NY) and F = (NY,NX).
1036  ! LLG Log. I Logical flag indicating the coordinate system:
1037  ! T = spherical lat/lon (degrees) and F = Cartesian.
1038  ! ICLO Int. I Parameter indicating type of index space closure
1039  ! XG R.A. I Pointer to array of x-coordinates of input grid.
1040  ! YG R.A. I Pointer to array of y-coordinates of input grid.
1041  !
1042  ! Inputs (for W3BBOX_GRD_TGT):
1043  ! IJG Log. I Logical flag indicating ordering of input
1044  ! coord. arrays: T = (NX,NY) and F = (NY,NX).
1045  ! LLG Log. I Logical flag indicating the coordinate system:
1046  ! T = spherical lat/lon (degrees) and F = Cartesian.
1047  ! ICLO Int. I Parameter indicating type of index space closure
1048  ! LB I.A. I Lower bounds of XG and YG arrays
1049  ! UB I.A. I Upper bounds of XG and YG arrays
1050  ! XG R.A. I Array of x-coordinates of input grid.
1051  ! YG R.A. I Array of y-coordinates of input grid.
1052  !
1053  ! Outputs:
1054  ! XMIN Int. O Minimum X-coord of bounding box
1055  ! YMIN Int. O Minimum Y-coord of bounding box
1056  ! XMAX Int. O Maximum X-coord of bounding box
1057  ! YMAX Int. O Maximum Y-coord of bounding box
1058  ! ----------------------------------------------------------------
1059  !
1060  ! 4. Subroutines used :
1061  !
1062  ! See module documentation.
1063  !
1064  ! 5. Called by :
1065  !
1066  ! 6. Error messages :
1067  !
1068  ! - Check on previous creation of grid-search-utility object.
1069  !
1070  ! 7. Remarks :
1071  !
1072  ! 8. Structure :
1073  !
1074  ! 9. Switches :
1075  !
1076  ! !/S Enable subroutine tracing.
1077  !
1078  ! 10. Source code :
1079  !/
1080  !/ ------------------------------------------------------------------- /
1081  !/
1082  SUBROUTINE w3bbox_gsu( GSU, XMIN, YMIN, XMAX, YMAX )
1083  TYPE(t_gsu), INTENT(IN) :: gsu
1084  REAL(8), INTENT(OUT) :: xmin, ymin, xmax, ymax
1085 
1086  ! Local parameters
1087 #ifdef W3_S
1088  INTEGER, SAVE :: ient = 0
1089  CALL strace (ient, 'W3BBOX_GSU')
1090 #endif
1091  !
1092  ! -------------------------------------------------------------------- /
1093  ! 1. Test input
1094  !
1095  IF ( .NOT.ASSOCIATED(gsu%PTR) ) THEN
1096  WRITE(0,'(/1A,1A/)') 'W3BBOX_GSU ERROR -- ', &
1097  'grid search utility object not created'
1098  CALL extcde (1)
1099  END IF
1100  !
1101  ! -------------------------------------------------------------------- /
1102  ! 2. Set bounding box
1103  !
1104  xmin = gsu%PTR%XMIN
1105  ymin = gsu%PTR%YMIN
1106  xmax = gsu%PTR%XMAX
1107  ymax = gsu%PTR%YMAX
1108 
1109  END SUBROUTINE w3bbox_gsu
1110  !/
1111  !/ ------------------------------------------------------------------- /
1112  !/
1113  SUBROUTINE w3bbox_grd_ptr_r4( IJG, LLG, ICLO, XG, YG, &
1114  XMIN, YMIN, XMAX, YMAX )
1115  LOGICAL, INTENT(IN) :: ijg
1116  LOGICAL, INTENT(IN) :: llg
1117  INTEGER, INTENT(IN) :: iclo
1118  REAL(4), POINTER :: xg(:,:)
1119  REAL(4), POINTER :: yg(:,:)
1120  REAL(8), INTENT(OUT) :: xmin, ymin, xmax, ymax
1121 
1122  ! Local parameters
1123  TYPE(t_gsu) :: gsu
1124  INTEGER :: lb(2), ub(2)
1125 #ifdef W3_S
1126  INTEGER, SAVE :: ient = 0
1127  CALL strace (ient, 'W3BBOX_GRD_PTR_R4')
1128 #endif
1129  !
1130  ! -------------------------------------------------------------------- /
1131  ! 1. Set bounding box
1132  !
1133  lb(1) = lbound(xg,1); lb(2) = lbound(xg,2)
1134  ub(1) = ubound(xg,1); ub(2) = ubound(xg,2)
1135  gsu = gsu_create( ijg, llg, iclo, lb, ub, xg4=xg, yg4=yg, bbox_only=.true. )
1136  xmin = gsu%PTR%XMIN
1137  ymin = gsu%PTR%YMIN
1138  xmax = gsu%PTR%XMAX
1139  ymax = gsu%PTR%YMAX
1140  CALL w3gsud( gsu )
1141 
1142  END SUBROUTINE w3bbox_grd_ptr_r4
1143  !/
1144  !/ ------------------------------------------------------------------- /
1145  !/
1146  SUBROUTINE w3bbox_grd_ptr_r8( IJG, LLG, ICLO, XG, YG, &
1147  XMIN, YMIN, XMAX, YMAX )
1148  LOGICAL, INTENT(IN) :: ijg
1149  LOGICAL, INTENT(IN) :: llg
1150  INTEGER, INTENT(IN) :: iclo
1151  REAL(8), POINTER :: xg(:,:)
1152  REAL(8), POINTER :: yg(:,:)
1153  REAL(8), INTENT(OUT) :: xmin, ymin, xmax, ymax
1154 
1155  ! Local parameters
1156  TYPE(t_gsu) :: gsu
1157  INTEGER :: lb(2), ub(2)
1158 #ifdef W3_S
1159  INTEGER, SAVE :: ient = 0
1160  CALL strace (ient, 'W3BBOX_GRD_PTR_R8')
1161 #endif
1162  !
1163  ! -------------------------------------------------------------------- /
1164  ! 1. Set bounding box
1165  !
1166  lb(1) = lbound(xg,1); lb(2) = lbound(xg,2)
1167  ub(1) = ubound(xg,1); ub(2) = ubound(xg,2)
1168  gsu = gsu_create( ijg, llg, iclo, lb, ub, xg8=xg, yg8=yg, bbox_only=.true. )
1169  xmin = gsu%PTR%XMIN
1170  ymin = gsu%PTR%YMIN
1171  xmax = gsu%PTR%XMAX
1172  ymax = gsu%PTR%YMAX
1173  CALL w3gsud( gsu )
1174 
1175  END SUBROUTINE w3bbox_grd_ptr_r8
1176  !/
1177  !/ ------------------------------------------------------------------- /
1178  !/
1179  SUBROUTINE w3bbox_grd_tgt_r4( IJG, LLG, ICLO, LB, UB, XG, YG, &
1180  XMIN, YMIN, XMAX, YMAX )
1181  LOGICAL, INTENT(IN) :: ijg
1182  LOGICAL, INTENT(IN) :: llg
1183  INTEGER, INTENT(IN) :: iclo
1184  INTEGER, INTENT(IN) :: lb(2), ub(2)
1185  REAL(4), TARGET :: xg(lb(1):ub(1),lb(2):ub(2))
1186  REAL(4), TARGET :: yg(lb(1):ub(1),lb(2):ub(2))
1187  REAL(8), INTENT(OUT) :: xmin, ymin, xmax, ymax
1188 
1189  ! Local parameters
1190  TYPE(t_gsu) :: gsu
1191 #ifdef W3_S
1192  INTEGER, SAVE :: ient = 0
1193  CALL strace (ient, 'W3BBOX_GRD_TGT_R4')
1194 #endif
1195  !
1196  ! -------------------------------------------------------------------- /
1197  ! 1. Set bounding box
1198  !
1199  gsu = gsu_create( ijg, llg, iclo, lb, ub, xg4=xg, yg4=yg, bbox_only=.true. )
1200  xmin = gsu%PTR%XMIN
1201  ymin = gsu%PTR%YMIN
1202  xmax = gsu%PTR%XMAX
1203  ymax = gsu%PTR%YMAX
1204  CALL w3gsud( gsu )
1205 
1206  END SUBROUTINE w3bbox_grd_tgt_r4
1207  !/
1208  !/ ------------------------------------------------------------------- /
1209  !/
1210  SUBROUTINE w3bbox_grd_tgt_r8( IJG, LLG, ICLO, LB, UB, XG, YG, &
1211  XMIN, YMIN, XMAX, YMAX )
1212  LOGICAL, INTENT(IN) :: ijg
1213  LOGICAL, INTENT(IN) :: llg
1214  INTEGER, INTENT(IN) :: iclo
1215  INTEGER, INTENT(IN) :: lb(2), ub(2)
1216  REAL(8), TARGET :: xg(lb(1):ub(1),lb(2):ub(2))
1217  REAL(8), TARGET :: yg(lb(1):ub(1),lb(2):ub(2))
1218  REAL(8), INTENT(OUT) :: xmin, ymin, xmax, ymax
1219 
1220  ! Local parameters
1221  TYPE(t_gsu) :: gsu
1222 #ifdef W3_S
1223  INTEGER, SAVE :: ient = 0
1224  CALL strace (ient, 'W3BBOX_GRD_TGT_R8')
1225 #endif
1226  !
1227  ! -------------------------------------------------------------------- /
1228  ! 1. Set bounding box
1229  !
1230  gsu = gsu_create( ijg, llg, iclo, lb, ub, xg8=xg, yg8=yg, bbox_only=.true. )
1231  xmin = gsu%PTR%XMIN
1232  ymin = gsu%PTR%YMIN
1233  xmax = gsu%PTR%XMAX
1234  ymax = gsu%PTR%YMAX
1235  CALL w3gsud( gsu )
1236 
1237  END SUBROUTINE w3bbox_grd_tgt_r8
1238  !/
1239  !/ End of W3BBOX ===================================================== /
1240  !/
1241 
1242 
1243 
1244 
1245 
1246 
1247 
1248 
1249  !/
1250  !/ =================================================================== /
1251  !/
1252  !/ FUNCTION W3GFCL( GSU, XT, YT, IS, JS, XS, YS, &
1253  !/ POLE, EPS, FNCL, DEBUG ) RESULT(INGRID)
1254  !/
1255  !/ =================================================================== /
1256  !/
1257  ! 1. Purpose :
1258  !
1259  ! Find cell in grid, associated with the input grid-search-utility
1260  ! object (GSU), that encloses the target point (xt,yt).
1261  !
1262  ! 2. Method :
1263  !
1264  ! 3. Parameters :
1265  !
1266  ! Return parameter
1267  ! ----------------------------------------------------------------
1268  ! INGRID Log. O Logical flag indicating if target point lies
1269  ! within the source grid domain.
1270  ! ----------------------------------------------------------------
1271  !
1272  ! Parameter list
1273  ! ----------------------------------------------------------------
1274  ! GSU Type I Grid-search-utility object.
1275  ! XT Real I X-coordinate of target point.
1276  ! YT Real I Y-coordinate of target point.
1277  ! IS,JS I.A. O (I,J) indices of vertices of enclosing grid cell.
1278  ! XS,YS R.A. O (X,Y) coord. of vertices of enclosing grid cell.
1279  ! POLE Log. O OPTIONAL logical flag to indicate whether or not
1280  ! the enclosing grid cell includes a pole.
1281  ! EPS Real I OPTIONAL small non-zero tolerance used to check if
1282  ! target point is in domain and for point coincidence.
1283  ! FNCL Log. I OPTIONAL logical flag to enable finding cell that
1284  ! is shortest distance from target point when the
1285  ! target point is not located in the source grid.
1286  ! Default is FALSE.
1287  ! DEBUG Log. I OPTIONAL logical flag to turn on debug mode.
1288  ! Default is FALSE.
1289  ! ----------------------------------------------------------------
1290  !
1291  ! 4. Subroutines used :
1292  !
1293  ! See module documentation.
1294  !
1295  ! 5. Called by :
1296  !
1297  ! 6. Error messages :
1298  !
1299  ! - Check on previous creation of grid-search-utility object.
1300  !
1301  ! 7. Remarks :
1302  !
1303  ! - The target point coordinates may be modified by this routine.
1304  ! - The target point longitude will be shifted to the source grid
1305  ! longitudinal range.
1306  ! - If enclosing cell includes a branch cut, then the coordinates of
1307  ! of the cell vertices AND the target point will be adjusted so
1308  ! that the branch cut is shifted 180 degrees.
1309  !
1310  ! 8. Structure :
1311  !
1312  ! -----------------------------------------------------------------
1313  ! 1. Test input
1314  ! 2. Initialize search
1315  ! 3. Search for enclosing cell in central and nearest nbr buckets
1316  ! 4. If not in grid and find nearest cell is enabled, then
1317  ! identify cell closest to target point
1318  ! -----------------------------------------------------------------
1319  !
1320  ! 9. Switches :
1321  !
1322  ! !/S Enable subroutine tracing.
1323  !
1324  ! 10. Source code :
1325  !/
1326  !/ ------------------------------------------------------------------- /
1327  !/
1328  FUNCTION w3gfcl_r4( GSU, XT, YT, IS, JS, XS, YS, &
1329  POLE, EPS, FNCL, DEBUG ) RESULT(INGRID)
1330  ! Single precision interface
1331  LOGICAL :: ingrid
1332  TYPE(t_gsu), INTENT(IN) :: gsu
1333  REAL(4), INTENT(INOUT) :: xt
1334  REAL(4), INTENT(INOUT) :: yt
1335  INTEGER, INTENT(INOUT) :: is(4), js(4)
1336  REAL(4), INTENT(INOUT) :: xs(4), ys(4)
1337  LOGICAL, INTENT(OUT),OPTIONAL :: pole
1338  REAL(4), INTENT(IN), OPTIONAL :: eps
1339  LOGICAL, INTENT(IN), OPTIONAL :: fncl
1340  LOGICAL, INTENT(IN), OPTIONAL :: debug
1341 
1342  ! Local parameters
1343  REAL(8) :: xt8, yt8, xs8(4), ys8(4), eps8
1344 #ifdef W3_S
1345  INTEGER, SAVE :: ient = 0
1346  CALL strace (ient, 'W3GFCL_R4')
1347 #endif
1348  !
1349  !-----set inputs
1350  xt8 = xt; yt8 = yt;
1351  IF ( PRESENT(eps) ) THEN
1352  eps8 = eps
1353  ELSE
1354  eps8 = eps_default
1355  END IF
1356  !
1357  !-----call double precision method
1358  ingrid = w3gfcl( gsu, xt8, yt8, is, js, xs8, ys8, pole=pole, &
1359  eps=eps8, fncl=fncl, debug=debug )
1360  !
1361  !-----set outputs
1362  xt = xt8; yt = yt8;
1363  xs = xs8; ys = ys8;
1364 
1365  END FUNCTION w3gfcl_r4
1366  !/
1367  !/ ------------------------------------------------------------------- /
1368  !/
1369  FUNCTION w3gfcl_r8( GSU, XT, YT, IS, JS, XS, YS, &
1370  POLE, EPS, FNCL, DEBUG ) RESULT(INGRID)
1371  ! Double precision interface
1372  LOGICAL :: ingrid
1373  TYPE(t_gsu), INTENT(IN) :: gsu
1374  REAL(8), INTENT(INOUT) :: xt
1375  REAL(8), INTENT(INOUT) :: yt
1376  INTEGER, INTENT(INOUT) :: is(4), js(4)
1377  REAL(8), INTENT(INOUT) :: xs(4), ys(4)
1378  LOGICAL, INTENT(OUT),OPTIONAL :: pole
1379  REAL(8), INTENT(IN), OPTIONAL :: eps
1380  LOGICAL, INTENT(IN), OPTIONAL :: fncl
1381  LOGICAL, INTENT(IN), OPTIONAL :: debug
1382 
1383  ! Local parameters
1384  REAL(8) :: leps
1385  LOGICAL :: ldbg, lplc, lfncl, incell
1386  INTEGER :: i, j, k, l, n, ib, jb
1387  LOGICAL :: ijg, llg, lclo, l360
1388  INTEGER :: iclo, gkind
1389  INTEGER :: lbx, lby, ubx, uby, nx, ny
1390  REAL(4), POINTER :: xg4(:,:), yg4(:,:)
1391  REAL(8), POINTER :: xg8(:,:), yg8(:,:)
1392  INTEGER :: nbx, nby
1393  REAL(8) :: dxb, dyb, xmin, xmax, ymin, ymax
1394  TYPE(t_bkt), POINTER :: b(:,:)
1395  TYPE(t_nns), POINTER :: nnb
1396  LOGICAL :: found
1397  INTEGER :: nlevel, lvl, lvl1, n1, ib0, jb0, ib1, jb1, k1
1398  INTEGER :: is1(4), js1(4)
1399  REAL(8) :: xs1(4), ys1(4), xsm, ysm, dd, dd1
1400 #ifdef W3_S
1401  INTEGER, SAVE :: ient = 0
1402  CALL strace (ient, 'W3GFCL_R8')
1403 #endif
1404  !
1405  ! -------------------------------------------------------------------- /
1406  ! 1. Test input
1407  !
1408  IF ( .NOT.ASSOCIATED(gsu%PTR) ) THEN
1409  WRITE(0,'(/2A/)') 'W3GFCL_R8 ERROR -- ', &
1410  'grid search utility object not created'
1411  CALL extcde (1)
1412  END IF
1413  IF ( PRESENT(eps) ) THEN
1414  IF ( eps .LT. zero ) THEN
1415  WRITE(0,'(/2A/)') 'W3GFCL_R8 ERROR -- ', &
1416  'EPS parameter must be >= 0'
1417  CALL extcde (1)
1418  END IF
1419  leps = eps
1420  ELSE
1421  leps = eps_default
1422  END IF
1423  !
1424  ! -------------------------------------------------------------------- /
1425  ! 2. Initialize search
1426  !
1427  IF ( PRESENT(fncl) ) THEN
1428  lfncl = fncl
1429  ELSE
1430  lfncl = .false.
1431  END IF
1432  IF ( PRESENT(debug) ) THEN
1433  ldbg = debug
1434  ELSE
1435  ldbg = .false.
1436  END IF
1437  !
1438  ! Local pointers to grid search utility object data
1439  ijg = gsu%PTR%IJG
1440  llg = gsu%PTR%LLG
1441  iclo = gsu%PTR%ICLO
1442  lclo = gsu%PTR%LCLO
1443  l360 = gsu%PTR%L360
1444  gkind = gsu%PTR%GKIND
1445  lbx = gsu%PTR%LBX; lby = gsu%PTR%LBY;
1446  ubx = gsu%PTR%UBX; uby = gsu%PTR%UBY;
1447  nx = gsu%PTR%NX; ny = gsu%PTR%NY;
1448  IF ( gkind.EQ.4 ) THEN
1449  xg4 => gsu%PTR%XG4; yg4 => gsu%PTR%YG4;
1450  ELSE
1451  xg8 => gsu%PTR%XG8; yg8 => gsu%PTR%YG8;
1452  END IF
1453  nbx = gsu%PTR%NBX; nby = gsu%PTR%NBY;
1454  dxb = gsu%PTR%DXB; dyb = gsu%PTR%DYB;
1455  xmin = gsu%PTR%XMIN; ymin = gsu%PTR%YMIN;
1456  xmax = gsu%PTR%XMAX; ymax = gsu%PTR%YMAX;
1457  b => gsu%PTR%B
1458  nnb => gsu%PTR%NNB
1459  !
1460  ingrid = .false.
1461  !
1462  ! Shift target to appropriate longitude range
1463  IF ( llg ) THEN
1464  xt = mod(xt,real(d360,8))
1465  IF ( lclo .OR. l360 ) THEN
1466  IF ( xt.LT.zero ) xt = xt + d360
1467  ELSE
1468  IF ( xt.GT.d180 ) xt = xt - d360
1469  END IF
1470  END IF
1471  IF ( ldbg ) WRITE(*,'(/A,2E24.16)') 'W3GFCL_R8 - TARGET POINT:',xt,yt
1472  !
1473  ! Target point must lie within search domain
1474  IF ( .NOT.lfncl ) THEN
1475  IF ( xt.LT.xmin-leps .OR. xt.GT.xmax+leps .OR. &
1476  yt.LT.ymin-leps .OR. yt.GT.ymax+leps ) THEN
1477  IF ( ldbg ) WRITE(*,'(A)') &
1478  'W3GFCL_R8 - TARGET POINT OUTSIDE SEARCH DOMAIN'
1479  RETURN
1480  END IF
1481  END IF
1482  !
1483  ! Search bucket that contains the target point.
1484  ib = max(int((xt-xmin)/dxb)+1,1); IF ( .NOT.lclo ) ib = min(ib,nbx);
1485  jb = max(int((yt-ymin)/dyb)+1,1); jb = min(jb,nby);
1486  !
1487  ! -------------------------------------------------------------------- /
1488  ! 3. Search for enclosing cell in bucket
1489  !
1490  IF ( ldbg ) &
1491  WRITE(*,'(A,3I6,4E24.16)') &
1492  'W3GFCL_R8 - BUCKET SEARCH:',ib,jb,b(jb,ib)%N, &
1493  xmin+(ib-1)*dxb,ymin+(jb-1)*dyb,xmin+ib*dxb,ymin+jb*dyb
1494  cell_loop: DO k=1,b(jb,ib)%N
1495  !---------setup cell corner indices
1496  is(1) = b(jb,ib)%I(k) ; js(1) = b(jb,ib)%J(k) ;
1497  is(2) = b(jb,ib)%I(k)+1; js(2) = b(jb,ib)%J(k) ;
1498  is(3) = b(jb,ib)%I(k)+1; js(3) = b(jb,ib)%J(k)+1;
1499  is(4) = b(jb,ib)%I(k) ; js(4) = b(jb,ib)%J(k)+1;
1500  !---------setup cell corner coordinates and adjust for periodicity
1501  DO l=1,4
1502  !-------------apply index closure
1503  IF ( mod(iclo,2).EQ.0 ) &
1504  is(l) = lbx + mod(nx - 1 + mod(is(l) - lbx + 1, nx), nx)
1505  IF ( mod(iclo,3).EQ.0 ) &
1506  js(l) = lby + mod(ny - 1 + mod(js(l) - lby + 1, ny), ny)
1507  IF ( iclo.EQ.iclo_trpl .AND. js(l).GT.uby ) THEN
1508  is(l) = ubx + lbx - is(l)
1509  js(l) = 2*uby - js(l) + 1
1510  END IF
1511  !-------------copy cell vertex coordinates into local variables
1512  IF ( ijg ) THEN
1513  IF ( gkind.EQ.4 ) THEN
1514  xs(l) = xg4(is(l),js(l)); ys(l) = yg4(is(l),js(l));
1515  ELSE
1516  xs(l) = xg8(is(l),js(l)); ys(l) = yg8(is(l),js(l));
1517  END IF
1518  ELSE
1519  IF ( gkind.EQ.4 ) THEN
1520  xs(l) = xg4(js(l),is(l)); ys(l) = yg4(js(l),is(l));
1521  ELSE
1522  xs(l) = xg8(js(l),is(l)); ys(l) = yg8(js(l),is(l));
1523  END IF
1524  END IF
1525  !-------------shift longitudes to same range
1526  IF ( llg ) THEN
1527  xs(l) = mod(xs(l),real(d360,8))
1528  IF ( lclo .OR. l360 ) THEN
1529  IF ( xs(l).LT.zero ) xs(l) = xs(l) + d360
1530  ELSE
1531  IF ( xs(l).GT.d180 ) xs(l) = xs(l) - d360
1532  END IF
1533  END IF
1534  END DO !L
1535  IF ( ldbg ) &
1536  WRITE(*,'(A,3I6,4(/A,1I1,A,2I6,2E24.16))') &
1537  'W3GFCL_R8 - CHECK CELL:',ib,jb,k, &
1538  (' CORNER(',l,'):',is(l),js(l),xs(l),ys(l),l=1,4)
1539  !---------check if point is enclosed in cell defined by xs(1:4) & ys(1:4)
1540  incell = w3ckcl(llg,xt,yt,4,xs,ys,lplc,leps,ldbg)
1541  IF ( ldbg ) WRITE(*,'(A,1L2)')'W3GFCL_R8 - INCELL:',incell
1542  IF ( incell ) THEN
1543  !-------------exit search
1544  IF ( ldbg ) &
1545  WRITE(*,'(A,3I6,4(2I6))') &
1546  'W3GFCL_R8 - ENCLOSING CELL:',ib,jb,k,(is(l),js(l),l=1,4)
1547  IF ( PRESENT(pole) ) pole = lplc
1548  ingrid = .true.
1549  EXIT cell_loop
1550  END IF !point in cell
1551  END DO cell_loop
1552  IF ( ingrid ) RETURN
1553  IF ( .NOT.lfncl ) RETURN
1554  !
1555  ! -------------------------------------------------------------------- /
1556  ! 4. If not in grid, then identify cell closest to target point
1557  !
1558  !-----find closest cell by searching nearest-neighbor buckets
1559  nlevel = 0
1560  dd1 = huge(xt)
1561  ib0 = ib; jb0 = jb;
1562  ib1 = ib; jb1 = jb;
1563  nnb = w3nnsc(nint(half*max(nbx,nby)))
1564  IF ( ldbg ) WRITE(*,'(A,3I6)') &
1565  'W3GFCL_R8 - CLOSEST CELL SEARCH:',ib0,jb0,nnb%NLVL
1566  level_loop: DO lvl=0,nnb%NLVL
1567  found = .false.
1568  nnbr_loop: DO n=nnb%N1(lvl),nnb%N2(lvl)
1569  ib = ib0 + nnb%DI(n); jb = jb0 + nnb%DJ(n);
1570  IF ( ib.LT.1 .OR. ib.GT.nbx ) cycle nnbr_loop
1571  IF ( jb.LT.1 .OR. jb.GT.nby ) cycle nnbr_loop
1572  IF ( ldbg ) WRITE(*,'(A,5I6)') &
1573  'W3GFCL_R8 - CHECK BUCKET:',lvl,n,ib,jb,b(jb,ib)%N
1574  cell_loop2: DO k=1,b(jb,ib)%N
1575  !-----------------setup cell corner indices
1576  is(1) = b(jb,ib)%I(k) ; js(1) = b(jb,ib)%J(k) ;
1577  is(2) = b(jb,ib)%I(k)+1; js(2) = b(jb,ib)%J(k) ;
1578  is(3) = b(jb,ib)%I(k)+1; js(3) = b(jb,ib)%J(k)+1;
1579  is(4) = b(jb,ib)%I(k) ; js(4) = b(jb,ib)%J(k)+1;
1580  !-----------------setup cell corner coordinates and adjust for periodicity
1581  DO l=1,4
1582  !---------------------apply index closure
1583  IF ( mod(iclo,2).EQ.0 ) &
1584  is(l) = lbx + mod(nx - 1 + mod(is(l) - lbx + 1, nx), nx)
1585  IF ( mod(iclo,3).EQ.0 ) &
1586  js(l) = lby + mod(ny - 1 + mod(js(l) - lby + 1, ny), ny)
1587  IF ( iclo.EQ.iclo_trpl .AND. js(l).GT.uby ) THEN
1588  is(l) = ubx + lbx - is(l)
1589  js(l) = 2*uby - js(l) + 1
1590  END IF
1591  !---------------------copy cell vertex coordinates into local variables
1592  IF ( ijg ) THEN
1593  IF ( gkind.EQ.4 ) THEN
1594  xs(l) = xg4(is(l),js(l)); ys(l) = yg4(is(l),js(l));
1595  ELSE
1596  xs(l) = xg8(is(l),js(l)); ys(l) = yg8(is(l),js(l));
1597  END IF
1598  ELSE
1599  IF ( gkind.EQ.4 ) THEN
1600  xs(l) = xg4(js(l),is(l)); ys(l) = yg4(js(l),is(l));
1601  ELSE
1602  xs(l) = xg8(js(l),is(l)); ys(l) = yg8(js(l),is(l));
1603  END IF
1604  END IF
1605  !---------------------shift longitudes to same range
1606  IF ( llg ) THEN
1607  xs(l) = mod(xs(l),real(d360,8))
1608  IF ( lclo .OR. l360 ) THEN
1609  IF ( xs(l).LT.zero ) xs(l) = xs(l) + d360
1610  ELSE
1611  IF ( xs(l).GT.d180 ) xs(l) = xs(l) - d360
1612  END IF
1613  END IF
1614  END DO !L
1615  !-----------------check cell distance from target point
1616  xsm = sum(xs)/four; ysm = sum(ys)/four;
1617  dd = w3dist(llg,xt,yt,xsm,ysm)
1618  IF ( ldbg ) &
1619  WRITE(*,'(A,5I6,3E24.16,4(/A,1I1,A,2I6,2E24.16))') &
1620  'W3GFCL_R8 - CHECK CELL:',lvl,n,ib,jb,k,xsm,ysm,dd, &
1621  (' CORNER(',l,'):',is(l),js(l),xs(l),ys(l),l=1,4)
1622  IF (dd.LT.dd1) THEN
1623  lvl1 = lvl
1624  n1 = n
1625  ib1 = ib
1626  jb1 = jb
1627  k1 = k
1628  dd1 = dd
1629  is1(:) = is(:)
1630  js1(:) = js(:)
1631  xs1(:) = xs(:)
1632  ys1(:) = ys(:)
1633  ENDIF
1634  found = .true.
1635  END DO cell_loop2
1636  END DO nnbr_loop
1637  IF ( found ) nlevel = nlevel + 1
1638  IF ( nlevel .GE. max_fncl_level ) EXIT level_loop
1639  END DO level_loop
1640  !
1641  !-----return cell that is shortest distance from target point
1642  is(:) = is1(:)
1643  js(:) = js1(:)
1644  xs(:) = xs1(:)
1645  ys(:) = ys1(:)
1646  IF ( ldbg ) &
1647  WRITE(*,'(A,5I6,1E24.16,4(/A,1I1,A,2I6,2E24.16))') &
1648  'W3GFCL_R8 - CLOSEST CELL:',lvl1,n1,ib1,jb1,k1,dd1, &
1649  (' CORNER(',l,'):',is(l),js(l),xs(l),ys(l),l=1,4)
1650  !
1651  !-----check if cell includes a pole or branch cut
1652  IF ( llg ) THEN
1653  n = 0
1654  !---------count longitudinal branch cut crossings
1655  DO i=1,4
1656  j = mod(i,4) + 1
1657  IF ( abs(xs(j)-xs(i)) .GT. d180 ) n = n + 1
1658  END DO
1659  !---------single longitudinal branch cut crossing
1660  ! or single vertex at 90 degrees => cell includes pole
1661  lplc = n.EQ.1 .OR. count(abs(ys).EQ.d90).EQ.1
1662  IF ( lplc .AND. ldbg ) &
1663  WRITE(*,'(A)') 'W3GFCL_R8 - CELL INCLUDES A POLE'
1664  ELSE
1665  lplc = .false.
1666  END IF
1667  IF ( PRESENT(pole) ) pole = lplc
1668 
1669  END FUNCTION w3gfcl_r8
1670  !/
1671  !/ End of W3GFCL ===================================================== /
1672  !/
1673 
1674 
1675 
1676 
1677 
1678 
1679 
1680 
1681  !/
1682  !/ =================================================================== /
1683  !/
1684  !/ FUNCTION W3GFCD_R4( GSU, XT, YT, IS, JS, XS, YS, POLE, EPS, DEBUG ) &
1685  !/ RESULT(INGRID)
1686  !/
1687  !/ =================================================================== /
1688  !/
1689  ! 1. Purpose :
1690  !
1691  ! Find cell in grid, associated with the input grid-search-utility
1692  ! object (GSU), that encloses the target point (xt,yt), using direct
1693  ! grid search (i.e., no bucket search).
1694  !
1695  ! 2. Method :
1696  !
1697  ! 3. Parameters :
1698  !
1699  ! Return parameter
1700  ! ----------------------------------------------------------------
1701  ! INGRID Log. O Logical flag indicating if target point lies
1702  ! within the source grid domain.
1703  ! ----------------------------------------------------------------
1704  !
1705  ! Parameter list
1706  ! ----------------------------------------------------------------
1707  ! GSU Type I Grid-search-utility object.
1708  ! XT Real I X-coordinate of target point.
1709  ! YT Real I Y-coordinate of target point.
1710  ! IS,JS I.A. O (I,J) indices of vertices of enclosing grid cell.
1711  ! XS,YS R.A. O (X,Y) coord. of vertices of enclosing grid cell.
1712  ! POLE Log. O OPTIONAL logical flag to indicate whether or not
1713  ! the enclosing grid cell includes a pole.
1714  ! EPS Real I OPTIONAL small non-zero tolerance used to check if
1715  ! target point is in domain and for point coincidence.
1716  ! DEBUG Log. I OPTIONAL logical flag to turn on debug mode.
1717  ! Default is FALSE.
1718  ! ----------------------------------------------------------------
1719  !
1720  ! 4. Subroutines used :
1721  !
1722  ! See module documentation.
1723  !
1724  ! 5. Called by :
1725  !
1726  ! 6. Error messages :
1727  !
1728  ! - Check on previous creation of grid-search-utility object.
1729  !
1730  ! 7. Remarks :
1731  !
1732  ! - The target point coordinates may be modified by this routine.
1733  ! - The target point longitude will be shifted to the source grid
1734  ! longitudinal range.
1735  ! - If enclosing cell includes a branch cut, then the coordinates of
1736  ! of the cell vertices AND the target point will be adjusted so
1737  ! that the branch cut is shifted 180 degrees.
1738  !
1739  ! 8. Structure :
1740  !
1741  ! -----------------------------------------------------------------
1742  ! 1. Test input
1743  ! 2. Initialize search
1744  ! 3. Search for enclosing cell
1745  ! -----------------------------------------------------------------
1746  !
1747  ! 9. Switches :
1748  !
1749  ! !/S Enable subroutine tracing.
1750  !
1751  ! 10. Source code :
1752  !/
1753  !/ ------------------------------------------------------------------- /
1754  !/
1755  FUNCTION w3gfcd_r4( GSU, XT, YT, IS, JS, XS, YS, &
1756  POLE, EPS, DEBUG ) RESULT(INGRID)
1757  ! Single precision interface
1758  LOGICAL :: ingrid
1759  TYPE(t_gsu), INTENT(IN) :: gsu
1760  REAL(4), INTENT(INOUT) :: xt
1761  REAL(4), INTENT(INOUT) :: yt
1762  INTEGER, INTENT(INOUT) :: is(4), js(4)
1763  REAL(4), INTENT(INOUT) :: xs(4), ys(4)
1764  LOGICAL, INTENT(OUT),OPTIONAL :: pole
1765  REAL(4), INTENT(IN), OPTIONAL :: eps
1766  LOGICAL, INTENT(IN), OPTIONAL :: debug
1767 
1768  ! Local parameters
1769  REAL(8) :: xt8, yt8, xs8(4), ys8(4), eps8
1770 #ifdef W3_S
1771  INTEGER, SAVE :: ient = 0
1772  CALL strace (ient, 'W3GFCD_R4')
1773 #endif
1774  !
1775  !-----set inputs
1776  xt8 = xt; yt8 = yt;
1777  IF ( PRESENT(eps) ) THEN
1778  eps8 = eps
1779  ELSE
1780  eps8 = eps_default
1781  END IF
1782  !
1783  !-----call double precision method
1784  ingrid = w3gfcd( gsu, xt8, yt8, is, js, xs8, ys8, pole=pole, &
1785  eps=eps8, debug=debug )
1786  !
1787  !-----set outputs
1788  xt = xt8; yt = yt8;
1789  xs = xs8; ys = ys8;
1790 
1791  END FUNCTION w3gfcd_r4
1792  !/
1793  !/ ------------------------------------------------------------------- /
1794  !/
1795  FUNCTION w3gfcd_r8( GSU, XT, YT, IS, JS, XS, YS, &
1796  POLE, EPS, DEBUG ) RESULT(INGRID)
1797  ! Double precision interface
1798  LOGICAL :: ingrid
1799  TYPE(t_gsu), INTENT(IN) :: gsu
1800  REAL(8), INTENT(INOUT) :: xt
1801  REAL(8), INTENT(INOUT) :: yt
1802  INTEGER, INTENT(INOUT) :: is(4), js(4)
1803  REAL(8), INTENT(INOUT) :: xs(4), ys(4)
1804  LOGICAL, INTENT(OUT),OPTIONAL :: pole
1805  REAL(8), INTENT(IN), OPTIONAL :: eps
1806  LOGICAL, INTENT(IN), OPTIONAL :: debug
1807 
1808  ! Local parameters
1809  REAL(8) :: leps
1810  LOGICAL :: ldbg, lplc
1811  INTEGER :: i, j, l
1812  LOGICAL :: ijg, llg, lclo, l360
1813  INTEGER :: iclo, gkind
1814  INTEGER :: lbx, lby, ubx, uby, nx, ny
1815  INTEGER :: lxc, lyc, uxc, uyc
1816  REAL(4), POINTER :: xg4(:,:), yg4(:,:)
1817  REAL(8), POINTER :: xg8(:,:), yg8(:,:)
1818 #ifdef W3_S
1819  INTEGER, SAVE :: ient = 0
1820  CALL strace (ient, 'W3GFCD_R8')
1821 #endif
1822  !
1823  ! -------------------------------------------------------------------- /
1824  ! 1. Test input
1825  !
1826  IF ( .NOT.ASSOCIATED(gsu%PTR) ) THEN
1827  WRITE(0,'(/2A/)') 'W3GFCD_R8 ERROR -- ', &
1828  'grid search utility object not created'
1829  CALL extcde (1)
1830  END IF
1831  IF ( PRESENT(eps) ) THEN
1832  IF ( eps .LT. zero ) THEN
1833  WRITE(0,'(/2A/)') 'W3GFCD_R8 ERROR -- ', &
1834  'EPS parameter must be >= 0'
1835  CALL extcde (1)
1836  END IF
1837  leps = eps
1838  ELSE
1839  leps = eps_default
1840  END IF
1841  !
1842  ! -------------------------------------------------------------------- /
1843  ! 2. Initialize search
1844  !
1845  IF ( PRESENT(debug) ) THEN
1846  ldbg = debug
1847  ELSE
1848  ldbg = .false.
1849  END IF
1850  !
1851  ! Local pointers to grid search utility object data
1852  ijg = gsu%PTR%IJG
1853  llg = gsu%PTR%LLG
1854  iclo = gsu%PTR%ICLO
1855  lclo = gsu%PTR%LCLO
1856  l360 = gsu%PTR%L360
1857  gkind = gsu%PTR%GKIND
1858  lbx = gsu%PTR%LBX; lby = gsu%PTR%LBY;
1859  ubx = gsu%PTR%UBX; uby = gsu%PTR%UBY;
1860  nx = gsu%PTR%NX; ny = gsu%PTR%NY;
1861  IF ( gkind.EQ.4 ) THEN
1862  xg4 => gsu%PTR%XG4; yg4 => gsu%PTR%YG4;
1863  ELSE
1864  xg8 => gsu%PTR%XG8; yg8 => gsu%PTR%YG8;
1865  END IF
1866  !
1867  ingrid = .false.
1868  !
1869  ! Shift target to appropriate longitude range
1870  IF ( llg ) THEN
1871  xt = mod(xt,real(d360,8))
1872  IF ( lclo .OR. l360 ) THEN
1873  IF ( xt.LT.zero ) xt = xt + d360
1874  ELSE
1875  IF ( xt.GT.d180 ) xt = xt - d360
1876  END IF
1877  END IF
1878  IF ( ldbg ) &
1879  WRITE(*,'(/A,2E24.16)') 'W3GFCD_R8 - TARGET POINT:',xt,yt
1880 
1881  !-----number of cells
1882  lxc = lbx; lyc = lby;
1883  SELECT CASE ( iclo )
1884  CASE ( iclo_none )
1885  uxc = ubx-1; uyc = uby-1;
1886  CASE ( iclo_grdi )
1887  uxc = ubx; uyc = uby-1;
1888  CASE ( iclo_grdj )
1889  uxc = ubx-1; uyc = uby;
1890  CASE ( iclo_trdl )
1891  uxc = ubx; uyc = uby;
1892  CASE ( iclo_trpl )
1893  uxc = ubx; uyc = uby;
1894  END SELECT
1895  !
1896  ! -------------------------------------------------------------------- /
1897  ! 3. Search for enclosing cell
1898  !
1899  cell_loop: DO i=lxc,uxc
1900  DO j=lyc,uyc
1901  !-------------create list of cell vertices
1902  is(1) = i ; js(1) = j ;
1903  is(2) = i+1; js(2) = j ;
1904  is(3) = i+1; js(3) = j+1;
1905  is(4) = i ; js(4) = j+1;
1906  !-------------setup cell corner coordinates and adjust for periodicity
1907  DO l=1,4
1908  !-----------------apply index closure
1909  IF ( mod(iclo,2).EQ.0 ) &
1910  is(l) = lbx + mod(nx - 1 + mod(is(l) - lbx + 1, nx), nx)
1911  IF ( mod(iclo,3).EQ.0 ) &
1912  js(l) = lby + mod(ny - 1 + mod(js(l) - lby + 1, ny), ny)
1913  IF ( iclo.EQ.iclo_trpl .AND. js(l).GT.uby ) THEN
1914  is(l) = ubx + lbx - is(l)
1915  js(l) = 2*uby - js(l) + 1
1916  END IF
1917  !-----------------copy cell vertex coordinates into local variables
1918  IF ( ijg ) THEN
1919  IF ( gkind.EQ.4 ) THEN
1920  xs(l) = xg4(is(l),js(l)); ys(l) = yg4(is(l),js(l));
1921  ELSE
1922  xs(l) = xg8(is(l),js(l)); ys(l) = yg8(is(l),js(l));
1923  END IF
1924  ELSE
1925  IF ( gkind.EQ.4 ) THEN
1926  xs(l) = xg4(js(l),is(l)); ys(l) = yg4(js(l),is(l));
1927  ELSE
1928  xs(l) = xg8(js(l),is(l)); ys(l) = yg8(js(l),is(l));
1929  END IF
1930  END IF
1931  !-----------------shift longitudes to same range
1932  IF ( llg ) THEN
1933  xs(l) = mod(xs(l),real(d360,8))
1934  IF ( lclo .OR. l360 ) THEN
1935  IF ( xs(l).LT.zero ) xs(l) = xs(l) + d360
1936  ELSE
1937  IF ( xs(l).GT.d180 ) xs(l) = xs(l) - d360
1938  END IF
1939  END IF
1940  END DO !L
1941  IF ( ldbg ) &
1942  WRITE(*,'(A,4(/A,1I1,A,2I6,2E24.16))') &
1943  'W3GFCD_R8 - CHECK CELL:', &
1944  (' CORNER(',l,'):',is(l),js(l),xs(l),ys(l),l=1,4)
1945  !-------------check if point is enclosed in cell defined by xs(1:4) & ys(1:4)
1946  ingrid = w3ckcl(llg,xt,yt,4,xs,ys,lplc,leps,ldbg)
1947  IF ( ldbg ) WRITE(*,'(A,1L2)')'W3GFCD_R8 - INGRID:',ingrid
1948  IF ( ingrid ) THEN
1949  !-----------------exit search
1950  IF ( ldbg ) &
1951  WRITE(*,'(A,4(2I6))') &
1952  'W3GFCD_R8 - ENCLOSING CELL:',(is(l),js(l),l=1,4)
1953  IF ( PRESENT(pole) ) pole = lplc
1954  EXIT cell_loop
1955  END IF !point in cell
1956  END DO !J
1957  END DO cell_loop
1958 
1959  END FUNCTION w3gfcd_r8
1960  !/
1961  !/ End of W3GFCD ===================================================== /
1962  !/
1963 
1964 
1965 
1966 
1967 
1968 
1969 
1970 
1971  !/
1972  !/ =================================================================== /
1973  !/
1974  !/ FUNCTION W3GFPT( GSU, XTIN, YTIN, IX, IY, EPS, DCIN, DEBUG ) &
1975  !/ RESULT(INGRID)
1976  !/
1977  !/ =================================================================== /
1978  !/
1979  ! 1. Purpose :
1980  !
1981  ! Find point in grid, associated with the input grid-search-utility
1982  ! object (GSU), that is closest to the target point (xtin,ytin).
1983  !
1984  ! 2. Method :
1985  !
1986  ! 3. Parameters :
1987  !
1988  ! Return parameter
1989  ! ----------------------------------------------------------------
1990  ! INGRID Log. O Logical flag indicating if target point lies
1991  ! within the source grid domain.
1992  ! ----------------------------------------------------------------
1993  !
1994  ! Parameter list
1995  ! ----------------------------------------------------------------
1996  ! GSU Type I Grid-search-utility object.
1997  ! XTIN Real I X-coordinate of target point.
1998  ! YTIN Real I Y-coordinate of target point.
1999  ! IX,JX I.A. O (I,J) indices of nearest grid point.
2000  ! EPS Real I OPTIONAL small non-zero tolerance used to check if
2001  ! target point is in domain and for point coincidence.
2002  ! DCIN Real I OPTIONAL distance outside of source grid in
2003  ! units of cell width to treat target point as
2004  ! inside the source grid.
2005  ! Default is 0.
2006  ! DEBUG Log. I OPTIONAL logical flag to turn on debug mode.
2007  ! Default is FALSE.
2008  ! ----------------------------------------------------------------
2009  !
2010  ! 4. Subroutines used :
2011  !
2012  ! See module documentation.
2013  !
2014  ! 5. Called by :
2015  !
2016  ! 6. Error messages :
2017  !
2018  ! - Check on previous initialization of grid search utility object.
2019  !
2020  ! 7. Remarks :
2021  !
2022  ! 8. Structure :
2023  !
2024  ! -----------------------------------------------------------------
2025  ! 1. Test input
2026  ! 2. Initialize search
2027  ! 3. Find enclosing cell and compute closest point
2028  ! -----------------------------------------------------------------
2029  !
2030  ! 9. Switches :
2031  !
2032  ! !/S Enable subroutine tracing.
2033  !
2034  ! 10. Source code :
2035  !/
2036  !/ ------------------------------------------------------------------- /
2037  !/
2038  FUNCTION w3gfpt_r4( GSU, XTIN, YTIN, IX, IY, EPS, DCIN, DEBUG ) &
2039  result(ingrid)
2040  ! Single precision interface
2041  LOGICAL :: ingrid
2042  TYPE(t_gsu), INTENT(IN) :: gsu
2043  REAL(4), INTENT(IN) :: xtin
2044  REAL(4), INTENT(IN) :: ytin
2045  INTEGER, INTENT(OUT) :: ix, iy
2046  REAL(4), INTENT(IN), OPTIONAL :: eps
2047  REAL(4), INTENT(IN), OPTIONAL :: dcin
2048  LOGICAL, INTENT(IN), OPTIONAL :: debug
2049 
2050  ! Local parameters
2051  REAL(8) :: xt8, yt8, eps8, dcin8
2052 #ifdef W3_S
2053  INTEGER, SAVE :: ient = 0
2054  CALL strace (ient, 'W3GFPT_R4')
2055 #endif
2056  !
2057  !-----set inputs
2058  xt8 = xtin; yt8 = ytin;
2059  IF ( PRESENT(eps) ) THEN
2060  eps8 = eps
2061  ELSE
2062  eps8 = eps_default
2063  END IF
2064  IF ( PRESENT(dcin) ) THEN
2065  dcin8 = dcin
2066  ELSE
2067  dcin8 = zero
2068  END IF
2069  !
2070  !-----call double precision method
2071  ingrid = w3gfpt( gsu, xt8, yt8, ix, iy, eps=eps8, dcin=dcin8, &
2072  debug=debug )
2073 
2074  END FUNCTION w3gfpt_r4
2075  !/
2076  !/ ------------------------------------------------------------------- /
2077  !/
2078  FUNCTION w3gfpt_r8( GSU, XTIN, YTIN, IX, IY, EPS, DCIN, DEBUG ) &
2079  result(ingrid)
2080  ! Single precision interface
2081  LOGICAL :: ingrid
2082  TYPE(t_gsu), INTENT(IN) :: gsu
2083  REAL(8), INTENT(IN) :: xtin
2084  REAL(8), INTENT(IN) :: ytin
2085  INTEGER, INTENT(OUT) :: ix, iy
2086  REAL(8), INTENT(IN), OPTIONAL :: eps
2087  REAL(8), INTENT(IN), OPTIONAL :: dcin
2088  LOGICAL, INTENT(IN), OPTIONAL :: debug
2089 
2090  ! Local parameters
2091  REAL(8), PARAMETER :: big = 1d16
2092  REAL(8) :: leps, ldcin
2093  LOGICAL :: ldbg, fncl
2094  INTEGER :: i, l
2095  INTEGER :: is(4), js(4)
2096  REAL(8) :: xt, yt, xs(4), ys(4)
2097  REAL(8) :: xtc, ytc, xsc(4), ysc(4)
2098  REAL(8) :: ixr, jxr, dd, lon0, lat0, dmin
2099  LOGICAL :: ijg, llg
2100 #ifdef W3_S
2101  INTEGER, SAVE :: ient = 0
2102  CALL strace (ient, 'W3GFPT_R8')
2103 #endif
2104  !
2105  ! -------------------------------------------------------------------- /
2106  ! 1. Test input
2107  !
2108  IF ( .NOT.ASSOCIATED(gsu%PTR) ) THEN
2109  WRITE(0,'(/2A/)') 'W3GFPT_R8 ERROR -- ', &
2110  'grid search utility object not created'
2111  CALL extcde (1)
2112  END IF
2113  IF ( PRESENT(eps) ) THEN
2114  IF ( eps .LT. zero ) THEN
2115  WRITE(0,'(/2A/)') 'W3GFPT_R8 ERROR -- ', &
2116  'EPS parameter must be >= 0'
2117  CALL extcde (1)
2118  END IF
2119  leps = eps
2120  ELSE
2121  leps = eps_default
2122  END IF
2123  IF ( PRESENT(dcin) ) THEN
2124  IF ( dcin .LT. zero ) THEN
2125  WRITE(0,'(/2A/)') 'W3GFPT_R8 ERROR -- ', &
2126  'DCIN parameter must be >= 0'
2127  CALL extcde (1)
2128  END IF
2129  ldcin = dcin
2130  ELSE
2131  ldcin = zero
2132  END IF
2133  !
2134  ! -------------------------------------------------------------------- /
2135  ! 2. Initialize search
2136  !
2137  IF ( PRESENT(debug) ) THEN
2138  ldbg = debug
2139  ELSE
2140  ldbg = .false.
2141  END IF
2142  !
2143  ! Local pointers to grid search utility object data
2144  ijg = gsu%PTR%IJG
2145  llg = gsu%PTR%LLG
2146  !
2147  ingrid = .false.
2148  ix = gsu%PTR%LBX-1
2149  iy = gsu%PTR%LBY-1
2150  !
2151  xt = xtin; yt = ytin;
2152  IF ( ldbg ) &
2153  WRITE(*,'(/A,2E24.16)') 'W3GFPT_R8 - TARGET POINT:',xt,yt
2154  !
2155  ! -------------------------------------------------------------------- /
2156  ! 3. Find enclosing cell and compute closest point
2157  !
2158  fncl = ldcin .GT. zero
2159  ingrid = w3gfcl( gsu, xt, yt, is, js, xs, ys, eps=leps, fncl=fncl, debug=ldbg )
2160  IF ( .NOT.ingrid .AND. .NOT.fncl ) RETURN
2161  !
2162  !-----Set in grid if point is within DCIN cell width distance of closest cell
2163  IF ( .NOT.ingrid .AND. fncl ) THEN
2164  !-------Compute cell relative index space location
2165  lon0 = sum(xs)/four; lat0 = sum(ys)/four;
2166  IF ( d90-abs(lat0).GT.near_pole ) THEN
2167  !-----------non-pole cell: compute relative location using (lon,lat)
2168  CALL getpqr(xt,yt,xs,ys,ixr,jxr,eps=leps,debug=ldbg)
2169  ELSE
2170  !-----------pole cell: compute relative location using stereographic projection
2171  CALL w3splx(lon0,lat0,zero,xt,yt,xtc,ytc)
2172  DO i=1,4
2173  CALL w3splx(lon0,lat0,zero,xs(i),ys(i),xsc(i),ysc(i))
2174  END DO
2175  CALL getpqr(xtc,ytc,xsc,ysc,ixr,jxr,eps=leps,debug=ldbg)
2176  ENDIF
2177  dd = half + ldcin
2178  ingrid = abs(ixr-half).LE.dd .AND. abs(jxr-half).LE.dd
2179  END IF
2180  !
2181  !-----Compute indices of closest point in cell
2182  IF ( ingrid ) THEN
2183  dmin = big
2184  DO l=1,4
2185  dd = w3dist( llg, xt, yt, xs(l), ys(l) )
2186  IF ( dd .LT. dmin ) THEN
2187  dmin = dd; ix = is(l); iy = js(l);
2188  END IF
2189  END DO !L
2190  END IF
2191 
2192  END FUNCTION w3gfpt_r8
2193  !/
2194  !/ End of W3GFPT ===================================================== /
2195  !/
2196 
2197 
2198 
2199 
2200 
2201 
2202 
2203 
2204  !/
2205  !/ =================================================================== /
2206  !/
2207  !/ FUNCTION W3GFIJ( GSU, XTIN, YTIN, IX, JX, EPS, DCIN, DEBUG ) &
2208  !/ RESULT(INGRID)
2209  !/
2210  !/ =================================================================== /
2211  !/
2212  ! 1. Purpose :
2213  !
2214  ! Compute coordinates ( ix, jx ) of target point ( xtin, ytin ) in
2215  ! source grid index space from source grid associated with the input
2216  ! grid search utility object (GSU).
2217  !
2218  ! 2. Method :
2219  !
2220  ! 3. Parameters :
2221  !
2222  ! Return parameter
2223  ! ----------------------------------------------------------------
2224  ! INGRID Log. O Logical flag indicating if target point lies
2225  ! within the source grid domain.
2226  ! ----------------------------------------------------------------
2227  !
2228  ! Parameter list
2229  ! ----------------------------------------------------------------
2230  ! GSU Type I Grid-search-utility object.
2231  ! XTIN Real I X-coordinate of target point.
2232  ! YTIN Real I Y-coordinate of target point.
2233  ! IX Real O X-coordinate of target point in source grid
2234  ! index space.
2235  ! JX Real O Y-coordinate of target point in source grid
2236  ! index space.
2237  ! EPS Real I OPTIONAL small non-zero tolerance used to check if
2238  ! target point is in domain and for point coincidence.
2239  ! DCIN Real I OPTIONAL distance outside of source grid in
2240  ! units of cell width to treat target point as
2241  ! inside the source grid.
2242  ! Default is 0.
2243  ! DEBUG Log. I OPTIONAL logical flag to turn on debug mode.
2244  ! Default is FALSE.
2245  ! ----------------------------------------------------------------
2246  !
2247  ! 4. Subroutines used :
2248  !
2249  ! See module documentation.
2250  !
2251  ! 5. Called by :
2252  !
2253  ! 6. Error messages :
2254  !
2255  ! - Check on previous initialization of grid search utility object.
2256  ! - Check on appropriate input of optional arguments.
2257  !
2258  ! 7. Remarks :
2259  !
2260  ! 8. Structure :
2261  !
2262  ! -----------------------------------------------------------------
2263  ! 1. Test input
2264  ! 2. Initialize search
2265  ! 3. Find enclosing cell and compute index coordinates
2266  ! -----------------------------------------------------------------
2267  !
2268  ! 9. Switches :
2269  !
2270  ! !/S Enable subroutine tracing.
2271  !
2272  ! 10. Source code :
2273  !/
2274  !/ ------------------------------------------------------------------- /
2275  !/
2276  FUNCTION w3gfij_r4( GSU, XTIN, YTIN, IX, JX, EPS, DCIN, DEBUG ) &
2277  result(ingrid)
2278  ! Single precision interface
2279  LOGICAL :: ingrid
2280  TYPE(t_gsu), INTENT(IN) :: gsu
2281  REAL(4), INTENT(IN) :: xtin
2282  REAL(4), INTENT(IN) :: ytin
2283  REAL(4), INTENT(OUT) :: ix
2284  REAL(4), INTENT(OUT) :: jx
2285  REAL(4), INTENT(IN), OPTIONAL :: eps
2286  REAL(4), INTENT(IN), OPTIONAL :: dcin
2287  LOGICAL, INTENT(IN), OPTIONAL :: debug
2288 
2289  ! Local parameters
2290  REAL(8) :: xt8, yt8, ix8, jx8, eps8, dcin8
2291 #ifdef W3_S
2292  INTEGER, SAVE :: ient = 0
2293  CALL strace (ient, 'W3GFIJ_R4')
2294 #endif
2295  !
2296  !-----set inputs
2297  xt8 = xtin; yt8 = ytin;
2298  IF ( PRESENT(eps) ) THEN
2299  eps8 = eps
2300  ELSE
2301  eps8 = eps_default
2302  END IF
2303  IF ( PRESENT(dcin) ) THEN
2304  dcin8 = dcin
2305  ELSE
2306  dcin8 = zero
2307  END IF
2308  !
2309  !-----call double precision method
2310  ingrid = w3gfij( gsu, xt8, yt8, ix8, jx8, eps=eps8, dcin=dcin8, &
2311  debug=debug )
2312  !
2313  !-----set outputs
2314  ix = ix8; jx = jx8;
2315 
2316  END FUNCTION w3gfij_r4
2317  !/
2318  !/ ------------------------------------------------------------------- /
2319  !/
2320  FUNCTION w3gfij_r8( GSU, XTIN, YTIN, IX, JX, EPS, DCIN, DEBUG ) &
2321  result(ingrid)
2322  ! Double precision interface
2323  LOGICAL :: ingrid
2324  TYPE(t_gsu), INTENT(IN) :: gsu
2325  REAL(8), INTENT(IN) :: xtin
2326  REAL(8), INTENT(IN) :: ytin
2327  REAL(8), INTENT(OUT) :: ix
2328  REAL(8), INTENT(OUT) :: jx
2329  REAL(8), INTENT(IN), OPTIONAL :: eps
2330  REAL(8), INTENT(IN), OPTIONAL :: dcin
2331  LOGICAL, INTENT(IN), OPTIONAL :: debug
2332 
2333  ! Local parameters
2334  REAL(8) :: leps, ldcin
2335  INTEGER :: i
2336  LOGICAL :: ldbg, fncl, pole
2337  INTEGER :: is(4), js(4)
2338  REAL(8) :: xt, yt, xs(4), ys(4)
2339  REAL(8) :: xtc, ytc, xsc(4), ysc(4)
2340  REAL(8) :: ixr, jxr, dd, lon0, lat0
2341 #ifdef W3_S
2342  INTEGER, SAVE :: ient = 0
2343  CALL strace (ient, 'W3GFIJ_R8')
2344 #endif
2345  !
2346  ! -------------------------------------------------------------------- /
2347  ! 1. Test input
2348  !
2349  IF ( .NOT.ASSOCIATED(gsu%PTR) ) THEN
2350  WRITE(0,'(/2A/)') 'W3GFIJ_R8 ERROR -- ', &
2351  'grid search utility object not created'
2352  CALL extcde (1)
2353  END IF
2354  IF ( PRESENT(eps) ) THEN
2355  IF ( eps .LT. zero ) THEN
2356  WRITE(0,'(/2A/)') 'W3GFIJ_R8 ERROR -- ', &
2357  'EPS parameter must be >= 0'
2358  CALL extcde (1)
2359  END IF
2360  leps = eps
2361  ELSE
2362  leps = eps_default
2363  END IF
2364  IF ( PRESENT(dcin) ) THEN
2365  IF ( dcin .LT. zero ) THEN
2366  WRITE(0,'(/2A/)') 'W3GFIJ_R8 ERROR -- ', &
2367  'DCIN parameter must be >= 0'
2368  CALL extcde (1)
2369  END IF
2370  ldcin = dcin
2371  ELSE
2372  ldcin = zero
2373  END IF
2374  !
2375  ! -------------------------------------------------------------------- /
2376  ! 2. Initialize search
2377  !
2378  IF ( PRESENT(debug) ) THEN
2379  ldbg = debug
2380  ELSE
2381  ldbg = .false.
2382  END IF
2383  !
2384  xt = xtin; yt = ytin;
2385  IF ( ldbg ) WRITE(*,'(/A,2E24.16)') 'W3GFIJ_R8 - TARGET POINT:',xt,yt
2386  !
2387  ! -------------------------------------------------------------------- /
2388  ! 3. Find enclosing cell and compute point location
2389  !
2390  fncl = ldcin .GT. zero
2391  ingrid = w3gfcl(gsu,xt,yt,is,js,xs,ys,pole=pole,eps=leps,fncl=fncl,debug=ldbg)
2392  IF ( .NOT.ingrid .AND. .NOT.fncl ) RETURN
2393  !
2394  !-----Compute cell relative index space location
2395  lon0 = sum(xs)/four; lat0 = sum(ys)/four;
2396  IF ( d90-abs(lat0).GT.near_pole ) THEN
2397  !---------non-pole cell: compute relative location using (lon,lat)
2398  CALL getpqr(xt,yt,xs,ys,ixr,jxr,eps=leps,debug=ldbg)
2399  ELSE
2400  !---------pole cell: compute relative location using stereographic projection
2401  CALL w3splx(lon0,lat0,zero,xt,yt,xtc,ytc)
2402  DO i=1,4
2403  CALL w3splx(lon0,lat0,zero,xs(i),ys(i),xsc(i),ysc(i))
2404  END DO
2405  CALL getpqr(xtc,ytc,xsc,ysc,ixr,jxr,eps=leps,debug=ldbg)
2406  ENDIF
2407  IF ( ldbg ) &
2408  WRITE(*,'(A,2L2,2E24.16)') 'W3GFIJ_R8 - RELATIVE:',ingrid,fncl,ixr,jxr
2409  !
2410  !-----Set in grid if point is within DCIN cell width distance of closest cell
2411  IF ( .NOT.ingrid .AND. fncl ) THEN
2412  dd = half + ldcin
2413  ingrid = abs(ixr-half).LE.dd .AND. abs(jxr-half).LE.dd
2414  END IF
2415  !
2416  !-----Compute absolute index space location
2417  ix = is(1)+ixr; jx = js(1)+jxr;
2418  IF ( ldbg ) &
2419  WRITE(*,'(A,2L2,2E24.16)') 'W3GFIJ_R8 - ABSOLUTE:',ingrid,fncl,ix,jx
2420 
2421  END FUNCTION w3gfij_r8
2422  !/
2423  !/ End of W3GFIJ ===================================================== /
2424  !/
2425 
2426 
2427 
2428 
2429 
2430 
2431 
2432 
2433  !/
2434  !/ =================================================================== /
2435  !/
2436  !/ FUNCTION W3GRMP( GSU, XTIN, YTIN, IS, JS, RW, EPS, &
2437  !/ DCIN, MASK, MSKC, NNBR, DEBUG ) RESULT(INGRID)
2438  !/
2439  !/ =================================================================== /
2440  !/
2441  ! 1. Purpose :
2442  !
2443  ! Compute bilinear remapping for target point (xtin,ytin) from source
2444  ! grid associated with the input grid search utility object (GSU).
2445  ! The indices of the source points used for remapping are returned in
2446  ! is(1:4) and js(1:4). The remapping weights are returned in rw(1:4).
2447  !
2448  ! 2. Method :
2449  !
2450  ! 3. Parameters :
2451  !
2452  ! Return parameter
2453  ! ----------------------------------------------------------------
2454  ! INGRID Log. O Logical flag indicating if target point lies
2455  ! within the source grid domain.
2456  ! ----------------------------------------------------------------
2457  !
2458  ! Parameter list
2459  ! ----------------------------------------------------------------
2460  ! GSU Type I Grid-search-utility object.
2461  ! XTIN Real I X-coordinate of target point.
2462  ! YTIN Real I Y-coordinate of target point.
2463  ! IS,JS I.A. O (I,J) indices of vertices of enclosing grid cell.
2464  ! RW R.A. O Array of interpolation weights.
2465  ! EPS Real I OPTIONAL small non-zero tolerance used to check if
2466  ! target point is in domain and for point coincidence.
2467  ! DCIN Real I OPTIONAL distance outside of source grid in
2468  ! units of cell width to treat target point as
2469  ! inside the source grid. Default is 0.
2470  ! MASK L.A. I OPTIONAL logical mask for source grid.
2471  ! MSKC Int. O OPTIONAL output integer parameter indicating how
2472  ! the enclosing cell is masked. Possible values
2473  ! are MSKC_NONE, MSKC_PART and MSKC_FULL.
2474  ! MSKC is required when MASK is specified.
2475  ! NNBR Int. I/O OPTIONAL integer parameter indicating the number
2476  ! of nearest-neighbor non-masked points used for
2477  ! distance-weighted averaging.
2478  ! Input: Requested number of nearest-neighbor
2479  ! non-masked points (0 < NNBR <= 4).
2480  ! Output: Actual number of nearest-neighbor
2481  ! non-masked points used.
2482  ! DEBUG Log. I OPTIONAL logical flag to turn on debug mode.
2483  ! Default is FALSE.
2484  ! ----------------------------------------------------------------
2485  !
2486  ! 4. Subroutines used :
2487  !
2488  ! See module documentation.
2489  !
2490  ! 5. Called by :
2491  !
2492  ! 6. Error messages :
2493  !
2494  ! - Check on previous initialization of grid search utility object.
2495  ! - Check on appropriate input of optional arguments.
2496  !
2497  ! 7. Remarks :
2498  !
2499  ! 8. Structure :
2500  !
2501  ! -----------------------------------------------------------------
2502  ! 1. Test input
2503  ! 2. Initialize search
2504  ! 3. Find enclosing cell and compute remapping weights
2505  ! - if enclosing cell does not includes a pole, then
2506  ! compute bilinear remapping
2507  ! - if enclosing cell includes a pole, then
2508  ! compute distance weighted remapping
2509  ! 4. Handle case of target point located within a partially masked cell.
2510  ! 5. Handle case of target point located within a fully masked cell.
2511  ! -----------------------------------------------------------------
2512  !
2513  ! 9. Switches :
2514  !
2515  ! !/S Enable subroutine tracing.
2516  !
2517  ! 10. Source code :
2518  !/
2519  !/ ------------------------------------------------------------------- /
2520  !/
2521  FUNCTION w3grmp_r4( GSU, XTIN, YTIN, IS, JS, RW, EPS, &
2522  DCIN, MASK, MSKC, NNBR, DEBUG ) RESULT(INGRID)
2523  ! Single precision interface
2524  LOGICAL :: ingrid
2525  TYPE(t_gsu), INTENT(IN) :: gsu
2526  REAL(4), INTENT(IN) :: xtin
2527  REAL(4), INTENT(IN) :: ytin
2528  INTEGER, INTENT(OUT) :: is(4)
2529  INTEGER, INTENT(OUT) :: js(4)
2530  REAL(4), INTENT(OUT) :: rw(4)
2531  REAL(4), INTENT(IN) , OPTIONAL :: eps
2532  REAL(4), INTENT(IN) , OPTIONAL :: dcin
2533  LOGICAL, INTENT(IN) , OPTIONAL :: mask(:,:)
2534  INTEGER, INTENT(OUT) , OPTIONAL :: mskc
2535  INTEGER, INTENT(INOUT), OPTIONAL :: nnbr
2536  LOGICAL, INTENT(IN) , OPTIONAL :: debug
2537 
2538  ! Local parameters
2539  REAL(8) :: xt8, yt8, rw8(4), eps8, dcin8
2540 #ifdef W3_S
2541  INTEGER, SAVE :: ient = 0
2542  CALL strace (ient, 'W3GRMP_R4')
2543 #endif
2544  !
2545  !-----set inputs
2546  xt8 = xtin; yt8 = ytin;
2547  IF ( PRESENT(eps) ) THEN
2548  eps8 = eps
2549  ELSE
2550  eps8 = eps_default
2551  END IF
2552  IF ( PRESENT(dcin) ) THEN
2553  dcin8 = dcin
2554  ELSE
2555  dcin8 = zero
2556  END IF
2557  !
2558  !-----call double precision method
2559  ingrid = w3grmp( gsu, xt8, yt8, is, js, rw8, &
2560  eps=eps8, dcin=dcin8, &
2561  mask=mask, mskc=mskc, nnbr=nnbr, debug=debug )
2562  !
2563  !-----set outputs
2564  rw = rw8
2565 
2566  END FUNCTION w3grmp_r4
2567  !/
2568  !/ ------------------------------------------------------------------- /
2569  !/
2570  FUNCTION w3grmp_r8( GSU, XTIN, YTIN, IS, JS, RW, EPS, &
2571  DCIN, MASK, MSKC, NNBR, DEBUG ) RESULT(INGRID)
2572  ! Double precision interface
2573  LOGICAL :: ingrid
2574  TYPE(t_gsu), INTENT(IN) :: gsu
2575  REAL(8), INTENT(IN) :: xtin
2576  REAL(8), INTENT(IN) :: ytin
2577  INTEGER, INTENT(OUT) :: is(4)
2578  INTEGER, INTENT(OUT) :: js(4)
2579  REAL(8), INTENT(OUT) :: rw(4)
2580  REAL(8), INTENT(IN) , OPTIONAL :: eps
2581  REAL(8), INTENT(IN) , OPTIONAL :: dcin
2582  LOGICAL, INTENT(IN) , OPTIONAL :: mask(:,:)
2583  INTEGER, INTENT(OUT) , OPTIONAL :: mskc
2584  INTEGER, INTENT(INOUT), OPTIONAL :: nnbr
2585  LOGICAL, INTENT(IN) , OPTIONAL :: debug
2586 
2587  ! Local parameters
2588  REAL(8), PARAMETER :: big = 1d16
2589  REAL(8), PARAMETER :: small = 1d-6
2590  REAL(8) :: leps
2591  LOGICAL :: ldbg, fncl, pole
2592  INTEGER :: i, j, l
2593  LOGICAL :: m, msk(4)
2594  INTEGER :: lvl, n, ns, icc, jcc
2595  REAL(8) :: xt, yt, xs(4), ys(4), dw(4)
2596  REAL(8) :: xtc, ytc, xsc(4), ysc(4)
2597  REAL(8) :: ldcin, ixr, jxr, x, y, d(4), dd, dmin, dsum, lon0, lat0
2598  LOGICAL :: ijg, llg, lclo
2599  INTEGER :: iclo, gkind
2600  INTEGER :: lbx, lby, ubx, uby, nx, ny
2601  REAL(4), POINTER :: xg4(:,:), yg4(:,:)
2602  REAL(8), POINTER :: xg8(:,:), yg8(:,:)
2603  TYPE(t_nns), POINTER :: nnp
2604 #ifdef W3_S
2605  INTEGER, SAVE :: ient = 0
2606  CALL strace (ient, 'W3GRMP_R8')
2607 #endif
2608  !
2609  ! -------------------------------------------------------------------- /
2610  ! 1. Test input
2611  !
2612  IF ( .NOT.ASSOCIATED(gsu%PTR) ) THEN
2613  WRITE(0,'(/2A/)') 'W3GRMP_R8 ERROR -- ', &
2614  'grid search utility object not created'
2615  CALL extcde (1)
2616  END IF
2617  !
2618  IF ( PRESENT(eps) ) THEN
2619  IF ( eps .LT. zero ) THEN
2620  WRITE(0,'(/2A/)') 'W3GRMP_R8 ERROR -- ', &
2621  'EPS parameter must be >= 0'
2622  CALL extcde (1)
2623  END IF
2624  leps = eps
2625  ELSE
2626  leps = eps_default
2627  END IF
2628  !
2629  IF ( PRESENT(dcin) ) THEN
2630  IF ( dcin .LT. zero ) THEN
2631  WRITE(0,'(/2A/)') 'W3GRMP_R4 ERROR -- ', &
2632  'DCIN parameter must be >= 0'
2633  CALL extcde (1)
2634  END IF
2635  ldcin = dcin
2636  ELSE
2637  ldcin = zero
2638  END IF
2639  !
2640  IF ( PRESENT(mask) ) THEN
2641  IF ( .NOT.PRESENT(mskc) ) THEN
2642  WRITE(0,'(/2A/)') 'W3GRMP_R8 ERROR -- ', &
2643  'MSKC must be specified with MASK'
2644  CALL extcde (1)
2645  END IF
2646  IF ( PRESENT(nnbr) ) THEN
2647  IF ( .NOT.ASSOCIATED(gsu%PTR%NNP) ) THEN
2648  WRITE(0,'(/3A/)') 'W3GRMP_R8 ERROR -- ', &
2649  'MASK and NNBR input specified, ', &
2650  'but grid point-search object not created'
2651  CALL extcde (1)
2652  END IF
2653  IF ( nnbr .LE. 0 .OR. nnbr .GT. 4 ) THEN
2654  WRITE(0,'(/2A/)') 'W3GRMP_R8 ERROR -- ', &
2655  'NNBR must be >= 1 AND <= 4'
2656  CALL extcde (1)
2657  END IF
2658  END IF
2659  END IF
2660  !
2661  ! -------------------------------------------------------------------- /
2662  ! 2. Initialize search
2663  !
2664  IF ( PRESENT(debug) ) THEN
2665  ldbg = debug
2666  ELSE
2667  ldbg = .false.
2668  END IF
2669  !
2670  ! Local pointers to grid search utility object data
2671  ijg = gsu%PTR%IJG
2672  llg = gsu%PTR%LLG
2673  iclo = gsu%PTR%ICLO
2674  lclo = gsu%PTR%LCLO
2675  gkind = gsu%PTR%GKIND
2676  lbx = gsu%PTR%LBX; lby = gsu%PTR%LBY;
2677  ubx = gsu%PTR%UBX; uby = gsu%PTR%UBY;
2678  nx = gsu%PTR%NX; ny = gsu%PTR%NY;
2679  IF ( gkind.EQ.4 ) THEN
2680  xg4 => gsu%PTR%XG4; yg4 => gsu%PTR%YG4;
2681  ELSE
2682  xg8 => gsu%PTR%XG8; yg8 => gsu%PTR%YG8;
2683  END IF
2684  nnp => gsu%PTR%NNP
2685  !
2686  IF ( PRESENT(mask) ) THEN
2687  IF ( ijg ) THEN
2688  IF ( .NOT.(ubound(mask,1).EQ.nx.AND. &
2689  ubound(mask,2).EQ.ny) ) THEN
2690  WRITE(0,'(/2A/)') 'W3GRMP_R8 ERROR -- ', &
2691  'MASK array size does not agree with GSU index bounds'
2692  CALL extcde (1)
2693  END IF
2694  ELSE
2695  IF ( .NOT.(ubound(mask,2).EQ.nx.AND. &
2696  ubound(mask,1).EQ.ny) ) THEN
2697  WRITE(0,'(/2A/)') 'W3GRMP_R8 ERROR -- ', &
2698  'MASK array size does not agree with GSU index bounds'
2699  CALL extcde (1)
2700  END IF
2701  END IF
2702  END IF
2703  !
2704  rw = zero;
2705  !
2706  xt = xtin; yt = ytin;
2707  IF ( ldbg ) WRITE(*,'(/A,2E24.16)') 'W3GRMP_R8 - TARGET POINT:',xt,yt
2708  !
2709  ! -------------------------------------------------------------------- /
2710  ! 3. Find enclosing cell and compute remapping
2711  !
2712  fncl = ldcin .GT. zero
2713  ingrid = w3gfcl(gsu,xt,yt,is,js,xs,ys,pole=pole,eps=leps,fncl=fncl,debug=ldbg)
2714  IF ( .NOT.ingrid .AND. .NOT.fncl ) RETURN
2715  !
2716  !-----Compute remapping
2717  lon0 = sum(xs)/four; lat0 = sum(ys)/four;
2718  IF ( d90-abs(lat0).GT.near_pole ) THEN
2719  !---------non-pole cell: compute remapping using (lon,lat)
2720  CALL getpqr(xt,yt,xs,ys,ixr,jxr,eps=leps,debug=ldbg)
2721  ELSE
2722  !---------pole cell: compute remapping using stereographic projection
2723  CALL w3splx(lon0,lat0,zero,xt,yt,xtc,ytc)
2724  DO i=1,4
2725  CALL w3splx(lon0,lat0,zero,xs(i),ys(i),xsc(i),ysc(i))
2726  END DO
2727  CALL getpqr(xtc,ytc,xsc,ysc,ixr,jxr,eps=leps,debug=ldbg)
2728  ENDIF
2729  dw(1) = (one-ixr)*(one-jxr)
2730  dw(2) = ixr*(one-jxr)
2731  dw(3) = ixr*jxr
2732  dw(4) = (one-ixr)*jxr
2733  rw = dw
2734  IF ( ldbg ) THEN
2735  WRITE(*,'(A,2E24.16)') 'W3GRMP_R8 - REMAP (TGT):',xt,yt
2736  DO l=1,4
2737  WRITE(*,'(A,3I6,E24.16)') 'W3GRMP_R8 - REMAP (SRC):', &
2738  l,is(l),js(l),dw(l)
2739  END DO
2740  END IF !LDBG
2741  !
2742  !-----Set in grid if point is within DCIN cell width distance of closest cell
2743  IF ( .NOT.ingrid .AND. fncl ) THEN
2744  dd = half + ldcin
2745  ingrid = abs(ixr-half).LE.dd .AND. abs(jxr-half).LE.dd
2746  END IF
2747  IF ( .NOT.ingrid ) RETURN
2748  !
2749  IF ( .NOT.PRESENT(mask) ) RETURN
2750  !
2751  ! -------------------------------------------------------------------- /
2752  ! 4. Handle case of target point located within a partially masked cell.
2753  !
2754  !-----copy cell mask values according to array ordering
2755  IF ( ijg ) THEN
2756  DO l=1,4
2757  msk(l) = mask(is(l)-lbx+1,js(l)-lby+1)
2758  END DO
2759  ELSE
2760  DO l=1,4
2761  msk(l) = mask(js(l)-lby+1,is(l)-lbx+1)
2762  END DO
2763  END IF
2764  !
2765  !-----adjust weights for a partially masked cell
2766  dsum = zero
2767  ns = 4
2768  DO l=1,4
2769  IF ( msk(l) ) THEN
2770  ns = ns - 1
2771  dw(l) = zero
2772  END IF
2773  dsum = dsum + dw(l)
2774  END DO
2775  IF ( ns .EQ. 4 ) THEN
2776  mskc = mskc_none
2777  RETURN
2778  END IF
2779  IF ( ns .GT. 0 .AND. dsum .GT. small ) THEN
2780  dw = dw / dsum
2781  rw = dw
2782  IF ( ldbg ) &
2783  WRITE(*,'(A,2E24.16,4(2I6,E24.16))') &
2784  'W3GRMP_R8 - PARTIAL MASKED CELL:', &
2785  xt,yt,(is(l),js(l),dw(l),l=1,4)
2786  mskc = mskc_part
2787  RETURN
2788  ELSE
2789  mskc = mskc_full
2790  IF ( .NOT.PRESENT(nnbr) ) RETURN
2791  END IF
2792  !
2793  ! -------------------------------------------------------------------- /
2794  ! 5. Handle case of target point located within a fully masked cell.
2795  !
2796  ! Choose closest point in enclosing land cell to be the central point
2797  dmin = big
2798  DO l=1,4
2799  dd = w3dist(llg,xt,yt,xs(l),ys(l))
2800  IF ( dd .LT. dmin ) THEN
2801  dmin = dd; icc = is(l); jcc = js(l);
2802  END IF
2803  END DO !L
2804  !
2805  ! Search nearest-neighbor source points for closest nnbr un-masked
2806  ! points and compute distance-weighted average remapping.
2807  IF ( ldbg ) &
2808  WRITE(*,'(A,2I6)') &
2809  'W3GRMP_R8 - BEGIN POINT NNBR SEARCH:',icc,jcc
2810  ns = 0; d(:) = big;
2811  level_loop: DO lvl=0,nnp%NLVL
2812  nnbr_loop: DO n=nnp%N1(lvl),nnp%N2(lvl)
2813  i = icc + nnp%DI(n); j = jcc + nnp%DJ(n);
2814  IF ( iclo.EQ.iclo_none ) THEN
2815  IF ( i.LT.lbx .OR. i.GT.ubx ) cycle nnbr_loop
2816  IF ( j.LT.lby .OR. j.GT.uby ) cycle nnbr_loop
2817  END IF
2818  !-------------apply index closure
2819  IF ( mod(iclo,2).EQ.0 ) &
2820  i = lbx + mod(nx - 1 + mod(i - lbx + 1, nx), nx)
2821  IF ( mod(iclo,3).EQ.0 ) &
2822  j = lby + mod(ny - 1 + mod(j - lby + 1, ny), ny)
2823  IF ( iclo.EQ.iclo_trpl .AND. j.GT.uby ) THEN
2824  i = ubx + lbx - i
2825  j = 2*uby - j + 1
2826  END IF
2827  !-------------set mask
2828  IF ( ijg ) THEN
2829  m = mask(i-lbx+1,j-lby+1)
2830  ELSE
2831  m = mask(j-lby+1,i-lbx+1)
2832  END IF
2833  IF ( ldbg ) &
2834  WRITE(*,'(A,4I6,1L6)') &
2835  'W3GRMP_R8 - POINT NNBR SEARCH:',lvl,n,i,j,m
2836  !-------------if masked point, then skip
2837  IF ( m ) cycle nnbr_loop
2838  !-------------compute distance
2839  IF ( ijg ) THEN
2840  IF ( gkind.EQ.4 ) THEN
2841  x = xg4(i,j); y = yg4(i,j);
2842  ELSE
2843  x = xg8(i,j); y = yg8(i,j);
2844  END IF
2845  ELSE
2846  IF ( gkind.EQ.4 ) THEN
2847  x = xg4(j,i); y = yg4(j,i);
2848  ELSE
2849  x = xg8(j,i); y = yg8(j,i);
2850  END IF
2851  END IF
2852  dd = w3dist(llg,xt,yt,x,y)
2853  !-------------still need nnbr points
2854  IF ( ns .LT. nnbr ) THEN
2855  !-----------------add to list
2856  ns = ns + 1
2857  is(ns) = i; js(ns) = j; d(ns) = dd;
2858  !-----------------once list is full sort according to increasing distance
2859  IF ( ns .EQ. nnbr ) CALL w3sort(ns,is,js,d)
2860  !---------------we have found nnbr points
2861  ELSE !list is full
2862  !-----------------insert into list if the newest point is closer
2863  CALL w3isrt(i,j,dd,ns,is,js,d)
2864  END IF !list is full
2865  IF ( ldbg ) &
2866  WRITE(*,'(A,I2,I3,I6,4(2I6,E24.16))') &
2867  'W3GRMP_R8 - POINT NNBR LIST:', &
2868  lvl,n,ns,(is(l),js(l),d(l),l=1,ns)
2869  END DO nnbr_loop
2870  !---------if we have found nnbr_rqd points, then exit the search
2871  IF ( ns .EQ. nnbr ) EXIT level_loop
2872  END DO level_loop
2873  nnbr = ns
2874  !
2875  ! If zero unmasked points found, then return nnbr=0 as error indicator
2876  IF ( nnbr .EQ. 0 ) RETURN
2877  !
2878  ! Compute distance-weighted remapping for nnbr points
2879  dsum = zero
2880  DO l=1,nnbr
2881  dsum = dsum + one/(d(l)+small)
2882  END DO
2883  dw(1:nnbr) = one/(d(1:nnbr)+small)/dsum
2884  rw = dw
2885  IF ( ldbg ) THEN
2886  WRITE(*,'(A,2E24.16,I6)') &
2887  'W3GRMP_R8 - FULLY MASKED CELL (TGT):',xt,yt,nnbr
2888  DO l=1,nnbr
2889  WRITE(*,'(A,3I6,E24.16)') &
2890  'W3GRMP_R8 - FULLY MASKED CELL (SRC):', &
2891  l,is(l),js(l),dw(l)
2892  END DO
2893  END IF !LDBG
2894 
2895  END FUNCTION w3grmp_r8
2896  !/
2897  !/ End of W3GRMP ===================================================== /
2898  !/
2899 
2900 
2901 
2902 
2903 
2904 
2905 
2906 
2907  !/
2908  !/ =================================================================== /
2909  !/
2910  !/ FUNCTION W3GRMC( GSU, XTIN, YTIN, RTYP, NS, IS, JS, CS, EPS, &
2911  !/ DCIN, WDTH, MASK, NMSK, DEBUG ) RESULT(INGRID)
2912  !/
2913  !/ =================================================================== /
2914  !/
2915  ! 1. Purpose :
2916  !
2917  ! Compute remapping coefficients for target point (XTIN,YTIN) from
2918  ! source grid associated with the input grid search utility object
2919  ! (GSU). The type of remapping is specified by RTYP. The indices
2920  ! of the source points used for remapping are returned in IS(1:NS)
2921  ! and JS(1:NS). The remapping coefficients are returned in CS(1:NS).
2922  !
2923  ! 2. Method :
2924  !
2925  ! 3. Parameters :
2926  !
2927  ! Return parameter
2928  ! ----------------------------------------------------------------
2929  ! INGRID Log. O Logical flag indicating if target point lies
2930  ! within the source grid domain.
2931  ! ----------------------------------------------------------------
2932  !
2933  ! Parameter list
2934  ! ----------------------------------------------------------------
2935  ! GSU Type I Grid-search-utility object.
2936  ! XTIN Real I X-coordinate of target point.
2937  ! YTIN Real I Y-coordinate of target point.
2938  ! RTYP Str. I Remap type: 'nearpt', 'bilinr', 'bicubc',
2939  ! 'filter'
2940  ! NS Int. O Number of vertices for remapping
2941  ! IS,JS I.A. O (I,J) indices of vertices for remapping
2942  ! CS R.A. O Array of remapping coefficients
2943  ! EPS Real I OPTIONAL small non-zero tolerance used to check if
2944  ! target point is in domain and for point coincidence.
2945  ! DCIN Real I OPTIONAL distance outside of source grid in
2946  ! units of cell width to treat target point as
2947  ! inside the source grid. Default is 0.
2948  ! WDTH Real I OPTIONAL width for gaussian filter in units of
2949  ! source grid cell width. Required if RTYP='filter'.
2950  ! Actual width used is MIN(WDTH,1.5).
2951  ! MASK L.A. I OPTIONAL logical mask for source grid.
2952  ! (T = invalid, F = valid)
2953  ! DIMENSION must be same as GSU coordinate arrays.
2954  ! NMSK Int. I OPTIONAL maximum number of masked points for
2955  ! treating an enclosing source grid cell as partially
2956  ! masked. Must be >= 0 and < 4. Default is 2.
2957  ! DEBUG Log. I OPTIONAL logical flag to turn on debug mode.
2958  ! Default is FALSE.
2959  ! ----------------------------------------------------------------
2960  !
2961  ! 4. Subroutines used :
2962  !
2963  ! See module documentation.
2964  !
2965  ! 5. Called by :
2966  !
2967  ! 6. Error messages :
2968  !
2969  ! - Check on previous initialization of grid search utility object.
2970  ! - Check on appropriate input of optional arguments.
2971  !
2972  ! 7. Remarks :
2973  !
2974  ! 8. Structure :
2975  !
2976  ! -----------------------------------------------------------------
2977  ! 1. Test input
2978  ! 2. Initialize search
2979  ! 3. Find enclosing cell and compute relative index space location
2980  ! 4. Compute source grid points and remapping coefficients
2981  ! 5. Adjust for partially masked cell and enforce normalization
2982  ! 6. Load into return arrays and release work arrays
2983  ! -----------------------------------------------------------------
2984  !
2985  ! 9. Switches :
2986  !
2987  ! !/S Enable subroutine tracing.
2988  !
2989  ! 10. Source code :
2990  !/
2991  !/ ------------------------------------------------------------------- /
2992  !/
2993  FUNCTION w3grmc_r4( GSU, XTIN, YTIN, RTYP, NS, IS, JS, CS, EPS, &
2994  DCIN, WDTH, MASK, NMSK, DEBUG ) RESULT(INGRID)
2995  ! Single precision interface
2996  LOGICAL :: ingrid
2997  TYPE(t_gsu), INTENT(IN) :: gsu
2998  REAL(4), INTENT(IN) :: xtin
2999  REAL(4), INTENT(IN) :: ytin
3000  CHARACTER(6), INTENT(IN):: rtyp
3001  INTEGER, INTENT(OUT) :: ns
3002  INTEGER, INTENT(INOUT), POINTER :: is(:)
3003  INTEGER, INTENT(INOUT), POINTER :: js(:)
3004  REAL(4), INTENT(INOUT), POINTER :: cs(:)
3005  REAL(4), INTENT(IN) , OPTIONAL :: eps
3006  REAL(4), INTENT(IN) , OPTIONAL :: dcin
3007  REAL(4), INTENT(IN) , OPTIONAL :: wdth
3008  LOGICAL, INTENT(IN) , OPTIONAL :: mask(:,:)
3009  INTEGER, INTENT(IN) , OPTIONAL :: nmsk
3010  LOGICAL, INTENT(IN) , OPTIONAL :: debug
3011 
3012  ! Local parameters
3013  REAL(8) :: leps, ldcin, lwdth=zero
3014  REAL(8) :: xt, yt
3015  REAL(8), POINTER :: cs8(:) => null()
3016 #ifdef W3_S
3017  INTEGER, SAVE :: ient = 0
3018  CALL strace (ient, 'W3GRMC_R4')
3019 #endif
3020  !
3021  ! -------------------------------------------------------------------- /
3022  ! 1. Test input
3023  !
3024  IF ( .NOT.ASSOCIATED(gsu%PTR) ) THEN
3025  WRITE(0,'(/2A/)') 'W3GRMC_R4 ERROR -- ', &
3026  'grid search utility object not created'
3027  CALL extcde (1)
3028  END IF
3029  !
3030  SELECT CASE (rtyp)
3031  CASE ('nearpt')
3032  CASE ('bilinr')
3033  CASE ('bicubc')
3034  CASE ('filter')
3035  IF ( .NOT.PRESENT(wdth) ) THEN
3036  WRITE(0,'(/2A/)') 'W3GRMC_R4 ERROR -- ', &
3037  'WDTH parameter is required with RTYP = filter'
3038  CALL extcde (1)
3039  ELSE
3040  lwdth = wdth
3041  END IF
3042  CASE DEFAULT
3043  WRITE(0,'(/2A/)') 'W3GRMC_R4 ERROR -- ', &
3044  'RTYP = '//rtyp//' not supported'
3045  CALL extcde (1)
3046  END SELECT
3047  !
3048  IF ( PRESENT(eps) ) THEN
3049  IF ( eps .LT. zero ) THEN
3050  WRITE(0,'(/2A/)') 'W3GRMC_R4 ERROR -- ', &
3051  'EPS parameter must be >= 0'
3052  CALL extcde (1)
3053  END IF
3054  leps = eps
3055  ELSE
3056  leps = eps_default
3057  END IF
3058  !
3059  IF ( PRESENT(dcin) ) THEN
3060  IF ( dcin .LT. zero ) THEN
3061  WRITE(0,'(/2A/)') 'W3GRMC_R4 ERROR -- ', &
3062  'DCIN parameter must be >= 0'
3063  CALL extcde (1)
3064  END IF
3065  ldcin = dcin
3066  ELSE
3067  ldcin = zero
3068  END IF
3069  !
3070  ! -------------------------------------------------------------------- /
3071  ! 2. Call into double precision method
3072  !
3073  xt = xtin; yt = ytin;
3074  ingrid = w3grmc( gsu, xt, yt, rtyp, ns, is, js, cs8, &
3075  eps=leps, dcin=ldcin, wdth=lwdth, &
3076  mask=mask, nmsk=nmsk, debug=debug )
3077  IF ( ns.GT.0 ) THEN
3078  ALLOCATE( cs(ns) )
3079  cs(:) = cs8(:)
3080  DEALLOCATE( cs8 )
3081  END IF
3082 
3083  END FUNCTION w3grmc_r4
3084  !/
3085  !/ ------------------------------------------------------------------- /
3086  !/
3087  FUNCTION w3grmc_r8( GSU, XTIN, YTIN, RTYP, NS, IS, JS, CS, EPS, &
3088  DCIN, WDTH, MASK, NMSK, DEBUG ) RESULT(INGRID)
3089  ! Double precision interface
3090  LOGICAL :: ingrid
3091  TYPE(t_gsu), INTENT(IN) :: gsu
3092  REAL(8), INTENT(IN) :: xtin
3093  REAL(8), INTENT(IN) :: ytin
3094  CHARACTER(6), INTENT(IN):: rtyp
3095  INTEGER, INTENT(OUT) :: ns
3096  INTEGER, INTENT(INOUT), POINTER :: is(:)
3097  INTEGER, INTENT(INOUT), POINTER :: js(:)
3098  REAL(8), INTENT(INOUT), POINTER :: cs(:)
3099  REAL(8), INTENT(IN) , OPTIONAL :: eps
3100  REAL(8), INTENT(IN) , OPTIONAL :: dcin
3101  REAL(8), INTENT(IN) , OPTIONAL :: wdth
3102  LOGICAL, INTENT(IN) , OPTIONAL :: mask(:,:)
3103  INTEGER, INTENT(IN) , OPTIONAL :: nmsk
3104  LOGICAL, INTENT(IN) , OPTIONAL :: debug
3105 
3106  ! Local parameters
3107  LOGICAL, PARAMETER :: lcmp = .true.
3108  INTEGER, PARAMETER :: nmsk_default = 2
3109  REAL(8), PARAMETER :: big = 1d16
3110  REAL(8) :: leps, lwdth=zero
3111  LOGICAL :: ldbg, fncl, pole, doblc, lmsk
3112  INTEGER :: i, ii, jj, k, kk, mcs, mcsmax
3113  INTEGER :: ic(4), jc(4)
3114  REAL(8) :: xt, yt, xc(4), yc(4)
3115  REAL(8) :: xtc, ytc, xsc(4), ysc(4)
3116  REAL(8) :: ldcin, ixr, jxr, dd, lon0, lat0, dmin
3117  REAL(8) :: ix, jx, czs
3118  INTEGER :: nz
3119  LOGICAL, POINTER :: lz(:)=>null()
3120  INTEGER, POINTER :: iz(:)=>null(), jz(:)=>null()
3121  REAL(8), POINTER :: cz(:)=>null()
3122  LOGICAL :: ijg, llg, lclo
3123  INTEGER :: iclo, gkind
3124  INTEGER :: lbx, lby, ubx, uby, nx, ny
3125 #ifdef W3_S
3126  INTEGER, SAVE :: ient = 0
3127  CALL strace (ient, 'W3GRMC_R8')
3128 #endif
3129  !
3130  ! -------------------------------------------------------------------- /
3131  ! 1. Test input
3132  !
3133  IF ( .NOT.ASSOCIATED(gsu%PTR) ) THEN
3134  WRITE(0,'(/2A/)') 'W3GRMC_R8 ERROR -- ', &
3135  'grid search utility object not created'
3136  CALL extcde (1)
3137  END IF
3138  !
3139  SELECT CASE (rtyp)
3140  CASE ('nearpt')
3141  CASE ('bilinr')
3142  CASE ('bicubc')
3143  CASE ('filter')
3144  IF ( .NOT.PRESENT(wdth) ) THEN
3145  WRITE(0,'(/2A/)') 'W3GRMC_R8 ERROR -- ', &
3146  'WDTH parameter is required with RTYP = filter'
3147  CALL extcde (1)
3148  ELSE
3149  lwdth = wdth
3150  END IF
3151  CASE DEFAULT
3152  WRITE(0,'(/2A/)') 'W3GRMC_R8 ERROR -- ', &
3153  'RTYP = '//rtyp//' not supported'
3154  CALL extcde (1)
3155  END SELECT
3156  !
3157  IF ( PRESENT(eps) ) THEN
3158  IF ( eps .LT. zero ) THEN
3159  WRITE(0,'(/2A/)') 'W3GRMC_R8 ERROR -- ', &
3160  'EPS parameter must be >= 0'
3161  CALL extcde (1)
3162  END IF
3163  leps = eps
3164  ELSE
3165  leps = eps_default
3166  END IF
3167  !
3168  IF ( PRESENT(dcin) ) THEN
3169  IF ( dcin .LT. zero ) THEN
3170  WRITE(0,'(/2A/)') 'W3GRMC_R8 ERROR -- ', &
3171  'DCIN parameter must be >= 0'
3172  CALL extcde (1)
3173  END IF
3174  ldcin = dcin
3175  ELSE
3176  ldcin = zero
3177  END IF
3178  !
3179  IF ( PRESENT(nmsk) ) THEN
3180  IF ( nmsk .LT. zero .OR. nmsk .GE. 4 ) THEN
3181  WRITE(0,'(/2A/)') 'W3GRMC_R8 ERROR -- ', &
3182  'NMSK parameter must be >= 0 and < 4'
3183  CALL extcde (1)
3184  END IF
3185  mcsmax = nmsk
3186  ELSE
3187  mcsmax = nmsk_default
3188  END IF
3189  !
3190  ! -------------------------------------------------------------------- /
3191  ! 2. Initialize search
3192  !
3193  IF ( PRESENT(debug) ) THEN
3194  ldbg = debug
3195  ELSE
3196  ldbg = .false.
3197  END IF
3198  !
3199  ! Local pointers to grid search utility object data
3200  ijg = gsu%PTR%IJG
3201  llg = gsu%PTR%LLG
3202  iclo = gsu%PTR%ICLO
3203  lclo = gsu%PTR%LCLO
3204  gkind = gsu%PTR%GKIND
3205  lbx = gsu%PTR%LBX; lby = gsu%PTR%LBY;
3206  ubx = gsu%PTR%UBX; uby = gsu%PTR%UBY;
3207  nx = gsu%PTR%NX; ny = gsu%PTR%NY;
3208  !
3209  IF ( PRESENT(mask) ) THEN
3210  IF ( ijg ) THEN
3211  IF ( .NOT.(ubound(mask,1).EQ.nx.AND. &
3212  ubound(mask,2).EQ.ny) ) THEN
3213  WRITE(0,'(/2A/)') 'W3GRMC_R8 ERROR -- ', &
3214  'MASK array size does not agree with GSU index bounds'
3215  CALL extcde (1)
3216  END IF
3217  ELSE
3218  IF ( .NOT.(ubound(mask,2).EQ.nx.AND. &
3219  ubound(mask,1).EQ.ny) ) THEN
3220  WRITE(0,'(/2A/)') 'W3GRMC_R8 ERROR -- ', &
3221  'MASK array size does not agree with GSU index bounds'
3222  CALL extcde (1)
3223  END IF
3224  END IF
3225  END IF
3226  !
3227  ns = 0
3228  IF ( ASSOCIATED(is) ) THEN
3229  DEALLOCATE( is )
3230  NULLIFY( is )
3231  END IF
3232  IF ( ASSOCIATED(js) ) THEN
3233  DEALLOCATE( js )
3234  NULLIFY( js )
3235  END IF
3236  IF ( ASSOCIATED(cs) ) THEN
3237  DEALLOCATE( cs )
3238  NULLIFY( cs )
3239  END IF
3240  !
3241  xt = xtin; yt = ytin;
3242  IF ( ldbg ) WRITE(*,'(/A,2E24.16)') 'W3GRMC_R8 - TARGET POINT:',xt,yt
3243  !
3244  ! -------------------------------------------------------------------- /
3245  ! 3. Find enclosing cell and compute relative index space location
3246  !
3247  fncl = ldcin .GT. zero
3248  ingrid = w3gfcl(gsu,xt,yt,ic,jc,xc,yc,pole=pole,eps=leps,fncl=fncl,debug=ldbg)
3249  IF ( .NOT.ingrid .AND. .NOT.fncl ) RETURN
3250  !
3251  !-----Compute cell relative index space location
3252  lon0 = sum(xc)/four; lat0 = sum(yc)/four;
3253  IF ( d90-abs(lat0).GT.near_pole ) THEN
3254  !---------non-pole cell: compute relative location using (lon,lat)
3255  CALL getpqr(xt,yt,xc,yc,ixr,jxr,eps=leps,debug=ldbg)
3256  ELSE
3257  !---------pole cell: compute relative location using stereographic projection
3258  CALL w3splx(lon0,lat0,zero,xt,yt,xtc,ytc)
3259  DO i=1,4
3260  CALL w3splx(lon0,lat0,zero,xc(i),yc(i),xsc(i),ysc(i))
3261  END DO
3262  CALL getpqr(xtc,ytc,xsc,ysc,ixr,jxr,eps=leps,debug=ldbg)
3263  ENDIF
3264  IF ( ldbg ) &
3265  WRITE(*,'(A,2L2,2E24.16)') 'W3GRMC_R8 - RELATIVE:',ingrid,fncl,ixr,jxr
3266  !
3267  !-----Set in grid if point is within DCIN cell width distance of closest cell
3268  IF ( .NOT.ingrid .AND. fncl ) THEN
3269  dd = half + ldcin
3270  ingrid = abs(ixr-half).LE.dd .AND. abs(jxr-half).LE.dd
3271  END IF
3272  IF ( .NOT.ingrid ) RETURN
3273  !
3274  !-----Compute absolute index space location
3275  ix = ic(1) + ixr; jx = jc(1) + jxr;
3276  !
3277  !-----Determine if target point is coincident with an
3278  ! unmasked source grid cell point (KK)
3279  kk_loop: DO kk=1,4
3280  IF ( abs(ic(kk)-ix).LE.leps .AND. &
3281  abs(jc(kk)-jx).LE.leps ) THEN
3282  IF ( PRESENT(mask) ) THEN
3283  IF ( ijg ) THEN
3284  IF ( .NOT.mask(ic(kk)-lbx+1,jc(kk)-lby+1) ) EXIT kk_loop
3285  ELSE
3286  IF ( .NOT.mask(jc(kk)-lby+1,ic(kk)-lbx+1) ) EXIT kk_loop
3287  END IF
3288  ELSE
3289  EXIT kk_loop
3290  END IF
3291  END IF
3292  END DO kk_loop
3293  !
3294  !-----Count number of masked points in source cell
3295  mcs = 0
3296  IF ( PRESENT(mask) ) THEN
3297  DO k=1,4
3298  IF ( ijg ) THEN
3299  IF ( mask(ic(k)-lbx+1,jc(k)-lby+1) ) mcs = mcs+1
3300  ELSE
3301  IF ( mask(jc(k)-lby+1,ic(k)-lbx+1) ) mcs = mcs+1
3302  END IF
3303  END DO
3304  END IF
3305  !
3306  ! -------------------------------------------------------------------- /
3307  ! 4. Compute source grid points and remapping coefficients
3308  !
3309  SELECT CASE (rtyp)
3310  CASE ('nearpt')
3311  ! *** nearest point ***
3312  dmin = big
3313  DO k=1,4
3314  dd = (ix - ic(k))**2 + (jx - jc(k))**2
3315  IF ( dd .LT. dmin ) THEN
3316  dmin = dd; ii = ic(k); jj = jc(k);
3317  END IF
3318  END DO
3319  nz = 1
3320  IF ( PRESENT(mask) ) THEN
3321  IF ( ijg ) THEN
3322  IF ( mask(ii-lbx+1,jj-lby+1) ) nz = 0
3323  ELSE
3324  IF ( mask(jj-lby+1,ii-lbx+1) ) nz = 0
3325  END IF
3326  END IF
3327  IF ( nz.EQ.1 ) THEN
3328  ! nearest point is unmasked
3329  ! set number of points to one and coefficient to one
3330  ALLOCATE( lz(nz), iz(nz), jz(nz), cz(nz) )
3331  lz(nz) = .true.
3332  iz(nz) = ii
3333  jz(nz) = jj
3334  cz(nz) = one
3335  ELSE
3336  ! nearest point is masked
3337  ! set number of points to zero and return
3338  ns = 0
3339  RETURN
3340  END IF
3341  CASE ('bilinr')
3342  ! *** bilinear interpolation ***
3343  IF ( kk.LE.4 ) THEN
3344  ! coincident with unmasked point kk
3345  ! set number of points to one and coefficient to one
3346  nz = 1
3347  ALLOCATE( lz(nz), iz(nz), jz(nz), cz(nz) )
3348  lz(nz) = .true.
3349  iz(nz) = ic(kk)
3350  jz(nz) = jc(kk)
3351  cz(nz) = one
3352  ELSE
3353  ! no coincident points
3354  IF ( mcs.LE.mcsmax ) THEN
3355  ! unmasked or partially masked cell
3356  ! set bilinear interpolation
3357  CALL getblc( gsu, ic(1), jc(1), ixr, jxr, &
3358  lcmp, nz, lz, iz, jz, cz )
3359  ELSE
3360  ! fully masked cell
3361  ! set number of points to zero and return
3362  ns = 0
3363  RETURN
3364  END IF
3365  END IF
3366  CASE ('bicubc')
3367  ! *** bicubic interpolation ***
3368  IF ( kk.LE.4 ) THEN
3369  ! coincident with unmasked point kk
3370  ! set number of points to one and coefficient to one
3371  nz = 1
3372  ALLOCATE( lz(nz), iz(nz), jz(nz), cz(nz) )
3373  lz(nz) = .true.
3374  iz(nz) = ic(kk)
3375  jz(nz) = jc(kk)
3376  cz(nz) = one
3377  ELSE
3378  ! no coincident points
3379  IF ( mcs.EQ.0 ) THEN
3380  ! unmasked cell
3381  ! get bicubic interpolation
3382  CALL getbcc( gsu, ic(1), jc(1), ixr, jxr, &
3383  lcmp, nz, lz, iz, jz, cz )
3384  ! check for masked points in bicubic stencil
3385  doblc = .false.
3386  IF ( PRESENT(mask) ) THEN
3387  check: DO k=1,nz
3388  IF ( lz(k) ) THEN
3389  IF ( ijg ) THEN
3390  lmsk = mask(iz(k)-lbx+1,jz(k)-lby+1)
3391  ELSE
3392  lmsk = mask(jz(k)-lby+1,iz(k)-lbx+1)
3393  END IF
3394  IF ( lmsk ) THEN
3395  doblc = .true.
3396  EXIT check
3397  END IF
3398  END IF
3399  END DO check
3400  END IF
3401  IF ( doblc ) THEN
3402  ! masked points in bicubic stencil
3403  ! set bilinear interpolation
3404  CALL getblc( gsu, ic(1), jc(1), ixr, jxr, &
3405  lcmp, nz, lz, iz, jz, cz )
3406  END IF
3407  ELSE IF ( mcs.LE.mcsmax ) THEN
3408  ! partially masked cell
3409  ! set bilinear interpolation
3410  CALL getblc( gsu, ic(1), jc(1), ixr, jxr, &
3411  lcmp, nz, lz, iz, jz, cz )
3412  ELSE
3413  ! fully masked cell
3414  ! set number of points to zero and return
3415  ns = 0
3416  RETURN
3417  END IF
3418  END IF
3419  case ('filter')
3420  ! *** gaussian filter ***
3421  IF ( mcs.LE.mcsmax ) THEN
3422  ! unmasked or partially masked cell
3423  ! get gaussian filter
3424  CALL getgfc( gsu, ic(1), jc(1), ixr, jxr, &
3425  lwdth, lcmp, nz, lz, iz, jz, cz )
3426  ELSE
3427  ! fully masked cell
3428  ! set number of points to zero and return
3429  ns = 0
3430  RETURN
3431  END IF
3432  END SELECT
3433  !
3434  ! -------------------------------------------------------------------- /
3435  ! 5. Adjust for partially masked cell and enforce normalization
3436  !
3437  IF ( nz .GT. 1 ) THEN
3438  czs = zero
3439  DO k=1,nz
3440  IF ( lz(k) ) THEN
3441  IF ( PRESENT(mask) ) THEN
3442  IF ( ijg ) THEN
3443  lmsk = mask(iz(k)-lbx+1,jz(k)-lby+1)
3444  ELSE
3445  lmsk = mask(jz(k)-lby+1,iz(k)-lbx+1)
3446  END IF
3447  IF ( lmsk ) THEN
3448  lz(k) = .false.
3449  cz(k) = zero
3450  ELSE
3451  czs = czs + cz(k)
3452  END IF
3453  ELSE
3454  czs = czs + cz(k)
3455  END IF
3456  END IF
3457  END DO
3458  IF ( czs .GT. zero ) THEN
3459  DO k=1,nz
3460  IF ( lz(k) ) cz(k) = cz(k)/czs
3461  ENDDO
3462  END IF
3463  END IF
3464  !
3465  ! -------------------------------------------------------------------- /
3466  ! 6. Load into return arrays and release work arrays
3467  !
3468  ns = 0
3469  DO k=1,nz
3470  IF ( lz(k) ) ns = ns + 1
3471  END DO
3472  IF ( ns.GT.0 ) THEN
3473  ALLOCATE( is(ns), js(ns), cs(ns) )
3474  ns = 0
3475  DO k=1,nz
3476  IF ( lz(k) ) THEN
3477  ns = ns + 1
3478  is(ns) = iz(k)
3479  js(ns) = jz(k)
3480  cs(ns) = cz(k)
3481  END IF
3482  END DO
3483  END IF
3484 
3485  DEALLOCATE( lz, iz, jz, cz )
3486 
3487  END FUNCTION w3grmc_r8
3488  !/
3489  !/ End of W3GRMC ===================================================== /
3490  !/
3491 
3492 
3493 
3494 
3495 
3496 
3497 
3498 
3499  !/
3500  !/ =================================================================== /
3501  !/
3502  !/ FUNCTION W3CKCL( LLG, XT, YT, NS, XS, YS, POLE, EPS, DEBUG ) &
3503  !/ RESULT(INCELL)
3504  !/
3505  !/ =================================================================== /
3506  !/
3507  ! 1. Purpose :
3508  !
3509  ! Check if point lies within grid cell.
3510  !
3511  ! 2. Method :
3512  !
3513  ! Calculates cross products for vertex to vertex (i.e. cell side)
3514  ! vs vertex to target. If all cross products have the same sign,
3515  ! the point is considered to be within the cell. Since they can
3516  ! be "all positive" *or* "all negative", there are no pre-conditions
3517  ! that the order of specification of the vertices be clockwise vs.
3518  ! counter-clockwise geographically. The logical variable POLE is
3519  ! set to true if the grid cell includes a pole.
3520  !
3521  ! 3. Parameters :
3522  !
3523  ! Return parameter
3524  ! ----------------------------------------------------------------
3525  ! INCELL Log. O Logical flag indicating point is in the cell
3526  ! ----------------------------------------------------------------
3527  !
3528  ! Parameter list
3529  ! ----------------------------------------------------------------
3530  ! LLG Log. I Logical flag indicating the coordinate system:
3531  ! T = spherical lat/lon (degrees) and F = Cartesian.
3532  ! XT Real I X-coordinate of target point.
3533  ! YT Real I Y-coordinate of target point.
3534  ! XS R.A. I X-coordinates of source cell vertices.
3535  ! YS R.A. I Y-coordinates of source cell vertices.
3536  ! POLE Log. O OPTIONAL output logical flag to indicate
3537  ! the source cell contains a pole.
3538  ! EPS Real I OPTIONAL small non-zero tolerance used to check
3539  ! for point coincidence.
3540  ! DEBUG Log. I OPTIONAL logical flag to turn on debug mode.
3541  ! Default is FALSE.
3542  ! ----------------------------------------------------------------
3543  !
3544  ! 4. Subroutines used :
3545  !
3546  ! See module documentation.
3547  !
3548  ! 5. Called by :
3549  !
3550  ! 6. Error messages :
3551  !
3552  ! 7. Remarks :
3553  !
3554  ! - For LL grids, this method assumes that the longitudes of point
3555  ! and grid cell vertices lie in the same range (i.e., both in [0:360]
3556  ! or [-180:180]). If the longitudes are not in the same range, then
3557  ! this method may result in a false positive. The burden is upon the
3558  ! caller to ensure that the longitude range of the point is the same
3559  ! as that of the grid cell vertices.
3560  ! - If enclosing cell includes a branch cut, then the coordinates of
3561  ! of the cell vertices AND the target point will be adjusted so
3562  ! that the branch cut is shifted 180 degrees.
3563  ! - If the enclosing cell includes a pole, then the cross-product check
3564  ! is performed using coordinates in a stereographic projection.
3565  !
3566  ! 8. Structure :
3567  !
3568  ! 9. Switches :
3569  !
3570  ! !/S Enable subroutine tracing.
3571  !
3572  ! 10. Source code :
3573  !/
3574  !/ ------------------------------------------------------------------- /
3575  !/
3576  FUNCTION w3ckcl_r4( LLG, XT, YT, NS, XS, YS, POLE, EPS, DEBUG ) &
3577  result(incell)
3578  ! Single precision interface
3579  LOGICAL :: incell
3580  LOGICAL, INTENT(IN) :: llg
3581  REAL(4), INTENT(INOUT) :: xt, yt
3582  INTEGER, INTENT(IN) :: ns
3583  REAL(4), INTENT(INOUT) :: xs(ns), ys(ns)
3584  LOGICAL, INTENT(OUT) :: pole
3585  REAL(4), INTENT(IN), OPTIONAL :: eps
3586  LOGICAL, INTENT(IN), OPTIONAL :: debug
3587 
3588  ! Local parameters
3589  REAL(8) :: xt8, yt8, xs8(ns), ys8(ns), eps8
3590 #ifdef W3_S
3591  INTEGER, SAVE :: ient = 0
3592  CALL strace (ient, 'W3CKCL_R4')
3593 #endif
3594  !
3595  !-----set inputs
3596  xt8 = xt; xs8 = xs;
3597  yt8 = yt; ys8 = ys;
3598  IF ( PRESENT(eps) ) THEN
3599  eps8 = eps
3600  ELSE
3601  eps8 = eps_default
3602  END IF
3603  !
3604  !-----call double precision method
3605  incell = w3ckcl( llg, xt8, yt8, ns, xs8, ys8, pole, &
3606  eps=eps8, debug=debug )
3607  !
3608  !-----return branch cut shifted coordinates
3609  xt = xt8; xs = xs8;
3610 
3611  END FUNCTION w3ckcl_r4
3612  !/
3613  !/ ------------------------------------------------------------------- /
3614  !/
3615  FUNCTION w3ckcl_r8( LLG, XT, YT, NS, XS, YS, POLE, EPS, DEBUG ) &
3616  result(incell)
3617  ! Double precision interface
3618  LOGICAL :: incell
3619  LOGICAL, INTENT(IN) :: llg
3620  REAL(8), INTENT(INOUT) :: xt, yt
3621  INTEGER, INTENT(IN) :: ns
3622  REAL(8), INTENT(INOUT) :: xs(ns), ys(ns)
3623  LOGICAL, INTENT(OUT) :: pole
3624  REAL(8), INTENT(IN), OPTIONAL :: eps
3625  LOGICAL, INTENT(IN), OPTIONAL :: debug
3626 
3627  ! Local parameters
3628  REAL(8) :: leps
3629  LOGICAL :: ldbg, lsbc, bcut
3630  INTEGER :: i, j, k, n
3631  REAL(8) :: xxt, yyt, xxs(ns), yys(ns)
3632  REAL(8) :: xct, yct, xcs(ns), ycs(ns)
3633  REAL(8) :: v1x, v1y, v2x, v2y, s90
3634  REAL(8) :: cross
3635  REAL(8) :: sign1
3636 #ifdef W3_S
3637  INTEGER, SAVE :: ient = 0
3638  CALL strace (ient, 'W3CKCL_R8')
3639 #endif
3640 
3641  incell = .true.
3642  !
3643  !-----must have >= 3 points to be a cell
3644  IF ( ns .LT. 3 ) THEN
3645  incell = .false.
3646  RETURN
3647  END IF
3648  !
3649  IF ( PRESENT(eps) ) THEN
3650  IF ( eps .LT. zero ) THEN
3651  WRITE(0,'(/2A/)') 'W3CKCL_R8 ERROR -- ', &
3652  'EPS parameter must be >= 0'
3653  CALL extcde (1)
3654  END IF
3655  leps = eps
3656  ELSE
3657  leps = eps_default
3658  END IF
3659  IF ( PRESENT(debug) ) THEN
3660  ldbg = debug
3661  ELSE
3662  ldbg = .false.
3663  END IF
3664  !
3665  !-----set local copies
3666  xxt = xt; xxs = xs;
3667  yyt = yt; yys = ys;
3668  !
3669  !-----check if cell includes a pole or branch cut
3670  IF ( llg ) THEN
3671  n = 0
3672  !---------count longitudinal branch cut crossings
3673  DO i=1,ns
3674  j = mod(i,ns) + 1
3675  IF ( abs(xxs(j)-xxs(i)) .GT. d180 ) n = n + 1
3676  END DO
3677  !---------multiple longitudinal branch cut crossing => cell includes branch cut
3678  bcut = n.GT.1
3679  !---------single longitudinal branch cut crossing
3680  ! or single vertex at 90 degrees => cell includes pole
3681  pole = n.EQ.1 .OR. count(abs(d90-abs(yys)).LE.leps).EQ.1
3682  ELSE
3683  pole = .false.
3684  bcut = .false.
3685  END IF
3686  !
3687  !-----shift branch cut if necessary
3688  IF ( bcut ) THEN
3689  IF ( minval(xxs) .GE. zero ) THEN
3690  WHERE ( xxs .GT. d180 ) xxs = xxs - d360
3691  IF ( xxt .GT. d180 ) xxt = xxt - d360
3692  ELSE
3693  WHERE ( xxs .LT. zero ) xxs = xxs + d360
3694  IF ( xxt .LT. zero ) xxt = xxt + d360
3695  END IF
3696  IF ( ldbg ) THEN
3697  WRITE(*,'(A)') 'W3CKCL_R8 - CELL INCLUDES A BRANCH CUT'
3698  WRITE(*,'(A,2E24.16,4(/A,1I1,A,2E24.16))') &
3699  'W3CKCL_R8 - SHIFT BRANCH CUT:',xxt,yyt, &
3700  (' CORNER(',k,'):',xxs(k),yys(k),k=1,4)
3701  END IF
3702  END IF
3703  !
3704  !-----check for coincidence with a cell vertex
3705  DO i=1,ns
3706  !---------if target point is coincident a cell vertex, then
3707  ! flag as in cell and return
3708  IF ( abs(xxt-xxs(i)).LE.leps .AND. abs(yyt-yys(i)).LE.leps ) THEN
3709  IF ( ldbg ) &
3710  WRITE(*,'(A,I1,A,2E24.16)') &
3711  'W3CKCL_R8 - COINCIDENT WITH CORNER(',i,'): ', &
3712  abs(xxt-xxs(i)),abs(yyt-yys(i))
3713  !-------------return branch cut shifted coordinates
3714  IF ( bcut ) THEN
3715  xt = xxt; xs = xxs;
3716  END IF
3717  incell = .true.
3718  RETURN
3719  END IF
3720  END DO
3721  !
3722  !-----handle cell that includes a pole
3723  IF ( pole ) THEN
3724  !---------perform cross-product check for each subcell
3725  IF ( ldbg ) &
3726  WRITE(*,'(A)') 'W3CKCL_R8 - CELL INCLUDES A POLE'
3727  s90 = d90; IF ( maxval(ys).LT.zero ) s90 = -d90;
3728  subcell_loop: DO i=1,ns
3729  lsbc = .true.
3730  j = mod(i,ns) + 1
3731  sign1 = 0.0
3732  DO k=1,4
3733  SELECT CASE (k)
3734  CASE (1)
3735  !---------------------vector from (xi,yi) to (xj,yj)
3736  v1x = xxs(j) - xxs(i)
3737  v1y = yys(j) - yys(i)
3738  !---------------------vector from (xi,yi) to (xt,yt)
3739  v2x = xxt - xxs(i)
3740  v2y = yyt - yys(i)
3741  CASE (2)
3742  !---------------------vector from (xj,yj) to (xj,90)
3743  v1x = xxs(j) - xxs(j)
3744  v1y = s90 - yys(j)
3745  !---------------------vector from (xj,yj) to (xt,yt)
3746  v2x = xxt - xxs(j)
3747  v2y = yyt - yys(j)
3748  CASE (3)
3749  !---------------------vector from (xj,90) to (xi,90)
3750  v1x = xxs(i) - xxs(j)
3751  v1y = s90 - s90
3752  !---------------------vector from (xj,90) to (xt,yt)
3753  v2x = xxt - xxs(j)
3754  v2y = yyt - s90
3755  CASE (4)
3756  !---------------------vector from (xi,90) to (xi,yi)
3757  v1x = xxs(i) - xxs(i)
3758  v1y = yys(i) - s90
3759  !---------------------vector from (xi,90) to (xt,yt)
3760  v2x = xxt - xxs(i)
3761  v2y = yyt - s90
3762  END SELECT
3763  !-----------------check for longitudinal branch cut crossing
3764  IF ( abs(v1x) .GT. d180 ) THEN
3765  v1x = v1x - sign(d360,v1x)
3766  END IF
3767  IF ( abs(v2x) .GT. d180 ) THEN
3768  v2x = v2x - sign(d360,v2x)
3769  END IF
3770  !-----------------cross product
3771  cross = v1x*v2y - v1y*v2x
3772  !-----------------handle point that lies exacly on side or zero length side
3773  IF ( abs(cross) .LT. leps ) cross = zero
3774  IF ( ldbg ) &
3775  WRITE(*,'(A,3(I1,A),5E24.16)') 'W3CKCL_R8 - CROSS(', &
3776  i,',',j,',',k,'):',v1x,v1y,v2x,v2y,cross
3777  !-----------------if sign of cross product is not "unanimous" among the
3778  ! subcell sides, then target is outside the subcell
3779  IF ( abs(sign1) .LE. leps ) THEN
3780  IF (abs(cross) .GT. leps) sign1 = sign(one,cross)
3781  ELSE
3782  ! If point lies along a border, the cross product
3783  ! is zero and its sign is not well defined
3784  IF ( abs(cross) .GT. leps ) THEN
3785  IF ( sign(one,cross) .NE. sign1 ) THEN
3786  lsbc = .false.
3787  cycle subcell_loop
3788  END IF
3789  END IF
3790  END IF
3791  END DO !K
3792  IF ( lsbc ) RETURN
3793  END DO subcell_loop
3794  incell = .false.
3795  RETURN
3796  ELSE
3797  !---------use input coordinates
3798  xct = xxt; yct = yyt;
3799  xcs = xxs; ycs = yys;
3800  END IF !POLE
3801  !
3802  !-----perform cross-product cell check
3803  sign1 = 0.0
3804  DO i=1,ns
3805  j = mod(i,ns) + 1
3806  !---------vector from (xi,yi) to (xj,yj)
3807  v1x = xcs(j) - xcs(i)
3808  v1y = ycs(j) - ycs(i)
3809  !---------vector from (xi,yi) to (xt,yt)
3810  v2x = xct - xcs(i)
3811  v2y = yct - ycs(i)
3812  !---------cross product
3813  cross = v1x*v2y - v1y*v2x
3814  !---------handle point that lies exacly on side or zero length side
3815  IF ( abs(cross) .LT. leps ) cross = zero
3816  IF ( ldbg ) &
3817  WRITE(*,'(A,2(I1,A),5E24.16)') 'W3CKCL_R8 - CROSS(', &
3818  i,',',j,'):',v1x,v1y,v2x,v2y,cross
3819  !---------if sign of cross product is not "unanimous" among the cell sides,
3820  ! then target is outside the cell
3821  IF ( abs(sign1) .LE. leps ) THEN
3822  IF (abs(cross) .GT. leps) sign1 = sign(one,cross)
3823  ELSE
3824  ! If point lies along a border, the cross product
3825  ! is zero and its sign is not well defined
3826  IF ( abs(cross) .GT. leps ) THEN
3827  IF ( sign(one,cross) .NE. sign1 ) THEN
3828  incell = .false.
3829  RETURN
3830  END IF
3831  END IF
3832  END IF
3833  END DO
3834  !
3835  !-----return branch cut shifted coordinates
3836  IF ( bcut ) THEN
3837  xt = xxt; xs = xxs;
3838  END IF
3839 
3840  END FUNCTION w3ckcl_r8
3841  !/
3842  !/ End of W3CKCL ===================================================== /
3843  !/
3844 
3845 
3846 
3847 
3848 
3849 
3850 
3851 
3852  !/
3853  !/ =================================================================== /
3854  !/
3855  !/ SUBROUTINE W3CGDM( IJG, LLG, ICLO, PTILED, QTILED, &
3856  !/ PRANGE, QRANGE, LBI, UBI, LBO, UBO, X, Y, &
3857  !/ MASK, NFD, SPHERE, RADIUS, DX, DY, &
3858  !/ GPPC, GQQC, GPQC, GSQR, &
3859  !/ HPFC, HQFC, APPC, AQQC, APQC, &
3860  !/ DXDP, DYDP, DXDQ, DYDQ, &
3861  !/ DPDX, DPDY, DQDX, DQDY, &
3862  !/ COSA, COSC, SINC, ANGL, RC )
3863  !/
3864  !/ =================================================================== /
3865  !/
3866  ! 1. Purpose :
3867  !
3868  ! Compute curvilinear grid derivatives and metric.
3869  !
3870  ! 2. Method :
3871  !
3872  ! Curvilinear grid is defined by the input coordinates as a function
3873  ! of the (P,Q) index coordinates:
3874  !
3875  ! x = x(p,q), y = y(p,q), dp = dq = 1.
3876  !
3877  ! When using spherical coordinates (llg=T) x = longitude and
3878  ! y = latitude in degrees. The optional sphere input (default is true)
3879  ! controls whether or not the spherical coordinate metric is applied.
3880  ! If sphere is true, then the spherical coordinate metric is applied
3881  ! to the coordinate derivatives with respect to p & q. In other words,
3882  !
3883  ! dx/dp <= d2r*radius*cos(y)*(dx/dp),
3884  ! dx/dq <= d2r*radius*cos(y)*(dx/dq),
3885  ! dy/dp <= d2r*radius*(dy/dp), and
3886  ! dy/dq <= d2r*radius*(dy/dq).
3887  !
3888  ! The default radius is Rearth.
3889  !
3890  ! The covariant metric tensor components are
3891  !
3892  ! g_pp = (dx/dp)*(dx/dp) + (dy/dp)*(dy/dp),
3893  ! g_qq = (dx/dq)*(dx/dq) + (dy/dq)*(dy/dq),
3894  ! g_pq = (dx/dp)*(dx/dq) + (dy/dp)*(dy/dq).
3895  !
3896  ! The contravariant (associated) metric tensor components are
3897  !
3898  ! g^pp = (dp/dx)*(dp/dx) + (dp/dy)*(dp/dy),
3899  ! g^qq = (dq/dx)*(dq/dx) + (dq/dy)*(dq/dy),
3900  ! g^pq = (dp/dx)*(dq/dx) + (dp/dy)*(dq/dy).
3901  !
3902  ! The curvilinear scale factors are h_p = sqrt(g_pp) and h_q = sqrt(g_qq).
3903  ! The square root of determinant of metric tensor is
3904  !
3905  ! sqrt(|g|) = sqrt( g_pp*g_qq - g_pq^2 )
3906  ! = (dx/dp)(dy/dq) - (dx/dq)(dy/dp)
3907  ! = h_p*h_q*sqrt(sin(alpha))
3908  ! = cell area.
3909  !
3910  ! The curvilinear derivatives are computed as
3911  !
3912  ! dp/dx = (1/sqrt(g))*(dy/dq),
3913  ! dp/dy = -(1/sqrt(g))*(dx/dq),
3914  ! dq/dx = -(1/sqrt(g))*(dy/dp),
3915  ! dq/dy = (1/sqrt(g))*(dx/dp).
3916  !
3917  ! Orthogonality of grid can be checked by computing angle between the
3918  ! curvilinear coordinate unit vectors:
3919  !
3920  ! cos(alpha) = g_pq/(h_p*h_q) = uvec_p \dot uvec_q,
3921  !
3922  ! where
3923  !
3924  ! uvec_p = (1/h_p)*(dx/dp)*uvec_x + (1/h_p)*(dy/dp)*uvec_y,
3925  ! uvec_q = (1/h_q)*(dx/dq)*uvec_x + (1/h_q)*(dy/dq)*uvec_y.
3926  !
3927  ! The local cell rotation angle is (assuming orthogonal):
3928  !
3929  ! cos(theta) = (1/h_p)*dx/dp,
3930  ! sin(theta) = (1/h_q)*dy/dp,
3931  ! theta = atan2((1/h_q)*dy/dp,(1/h_p)*dx/dp).
3932  !
3933  ! 3. Parameters :
3934  !
3935  ! Parameter list
3936  ! ----------------------------------------------------------------
3937  ! IJG Log. I Logical flag indicating ordering of input
3938  ! coord. arrays: T = (NP,NQ) and F = (NP,NQ)
3939  ! LLG Log. I Spherical coordinate (lon,lat) flag
3940  ! ICLO Int. I Parameter indicating type of index space closure
3941  ! PTILED Log. I Logical flag indicating that input arrays are tiled
3942  ! in P-axis with halos of width >= NFD/2
3943  ! QTILED Log. I Logical flag indicating that input arrays are tiled
3944  ! in Q-axis with halos of width >= NFD/2
3945  ! PRANGE I.A. I Range of P index coordinate: P in [PRANGE(1),PRANGE(2)]
3946  ! QRANGE I.A. I Range of Q index coordinate: Q in [QRANGE(1),QRANGE(2)]
3947  ! LBI I.A. I Lower-bound of input arrays, DIMENSION(2)
3948  ! UBI I.A. I Upper-bound of input arrays, DIMENSION(2)
3949  ! LBO I.A. I Lower-bound of output arrays, DIMENSION(2)
3950  ! UBO I.A. I Upper-bound of output arrays, DIMENSION(2)
3951  ! X R.A. I Gridded X-coordinates, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
3952  ! Y R.A. I Gridded Y-coordinates, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
3953  ! MASK L.A. I OPTIONAL logical mask (T = invalid, F = valid)
3954  ! DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
3955  ! NFD Int. I OPTIONAL finite-difference order (even), Default is NFD_DEFAULT.
3956  ! SPHERE Log. I OPTIONAL apply spherical coord metric if LLG, Default is T
3957  ! RADIUS Real I OPTIONAL radius for sphere. Default is REARTH
3958  ! DX Real I OPTIONAL constant spacing in x-direction
3959  ! DY Real I OPTIONAL constant spacing in y-direction
3960  ! GPPC R.A. O OPTIONAL g_pp, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3961  ! GQQC R.A. O OPTIONAL g_qq, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3962  ! GPQC R.A. O OPTIONAL g_pq, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3963  ! GSQR R.A. O OPTIONAL sqrt(|g|), DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3964  ! HPFC R.A. O OPTIONAL h_p, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3965  ! HQFC R.A. O OPTIONAL h_q, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3966  ! APPC R.A. O OPTIONAL g^pp, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3967  ! AQQC R.A. O OPTIONAL g^qq, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3968  ! APQC R.A. O OPTIONAL g^pq, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3969  ! DXDP R.A. O OPTIONAL dx/dp, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3970  ! DYDP R.A. O OPTIONAL dy/dp, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3971  ! DXDQ R.A. O OPTIONAL dx/dq, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3972  ! DYDQ R.A. O OPTIONAL dy/dq, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3973  ! DPDX R.A. O OPTIONAL dp/dx, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3974  ! DPDY R.A. O OPTIONAL dp/dy, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3975  ! DQDX R.A. O OPTIONAL dq/dx, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3976  ! DQDY R.A. O OPTIONAL dq/dy, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3977  ! COSA R.A. O OPTIONAL cos(alpha), DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3978  ! COSC R.A. O OPTIONAL cos(theta), DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3979  ! SINC R.A. O OPTIONAL sin(theta), DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3980  ! ANGL R.A. O OPTIONAL theta, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
3981  ! RC Int. O OPTIONAL return code (!= 0 if error occurs)
3982  ! ----------------------------------------------------------------
3983  !
3984  ! 4. Subroutines used :
3985  !
3986  ! See module documentation.
3987  !
3988  ! 5. Called by :
3989  !
3990  ! 6. Error messages :
3991  !
3992  ! 7. Remarks :
3993  !
3994  ! - The derivatives and metric will be computed using the constant
3995  ! spacing DX and/or DY if they are specified. DX & DY are assumed
3996  ! to be in degrees when LLG = T.
3997  ! - The grid derivatives (dx/dp, dy/dp, dx/dq, dy/dq) are computed
3998  ! using a finite difference method.
3999  ! - When LLG = T, the finite differences are done in a polar
4000  ! stereographic projection.
4001  ! - If RC is not provided and an error occurs, then the routine will
4002  ! report error to stderr and attempt to abort the calling program.
4003  !
4004  ! 8. Structure :
4005  !
4006  ! 9. Switches :
4007  !
4008  ! !/S Enable subroutine tracing.
4009  !
4010  ! 10. Source code :
4011  !/
4012  !/ ------------------------------------------------------------------- /
4013  !/
4014  SUBROUTINE w3cgdm_r4( IJG, LLG, ICLO, PTILED, QTILED, &
4015  PRANGE, QRANGE, LBI, UBI, LBO, UBO, X, Y, &
4016  MASK, NFD, SPHERE, RADIUS, DX, DY, &
4017  GPPC, GQQC, GPQC, GSQR, &
4018  HPFC, HQFC, APPC, AQQC, APQC, &
4019  DXDP, DYDP, DXDQ, DYDQ, &
4020  DPDX, DPDY, DQDX, DQDY, &
4021  COSA, COSC, SINC, ANGL, RC )
4022  ! Single precision interface
4023  LOGICAL, INTENT(IN) :: ijg
4024  LOGICAL, INTENT(IN) :: llg
4025  INTEGER, INTENT(IN) :: iclo
4026  LOGICAL, INTENT(IN) :: ptiled, qtiled
4027  INTEGER, INTENT(IN) :: prange(2), qrange(2)
4028  INTEGER, INTENT(IN) :: lbi(2), ubi(2)
4029  INTEGER, INTENT(IN) :: lbo(2), ubo(2)
4030  REAL(4), INTENT(IN) :: x(lbi(1):ubi(1),lbi(2):ubi(2))
4031  REAL(4), INTENT(IN) :: y(lbi(1):ubi(1),lbi(2):ubi(2))
4032  LOGICAL, INTENT(IN), OPTIONAL :: mask(lbi(1):ubi(1),lbi(2):ubi(2))
4033  INTEGER, INTENT(IN), OPTIONAL :: nfd
4034  LOGICAL, INTENT(IN), OPTIONAL :: sphere
4035  REAL(4), INTENT(IN), OPTIONAL :: radius
4036  REAL(4), INTENT(IN), OPTIONAL :: dx, dy
4037  REAL(4), INTENT(OUT), OPTIONAL :: gppc(lbo(1):ubo(1),lbo(2):ubo(2))
4038  REAL(4), INTENT(OUT), OPTIONAL :: gqqc(lbo(1):ubo(1),lbo(2):ubo(2))
4039  REAL(4), INTENT(OUT), OPTIONAL :: gpqc(lbo(1):ubo(1),lbo(2):ubo(2))
4040  REAL(4), INTENT(OUT), OPTIONAL :: gsqr(lbo(1):ubo(1),lbo(2):ubo(2))
4041  REAL(4), INTENT(OUT), OPTIONAL :: hpfc(lbo(1):ubo(1),lbo(2):ubo(2))
4042  REAL(4), INTENT(OUT), OPTIONAL :: hqfc(lbo(1):ubo(1),lbo(2):ubo(2))
4043  REAL(4), INTENT(OUT), OPTIONAL :: appc(lbo(1):ubo(1),lbo(2):ubo(2))
4044  REAL(4), INTENT(OUT), OPTIONAL :: aqqc(lbo(1):ubo(1),lbo(2):ubo(2))
4045  REAL(4), INTENT(OUT), OPTIONAL :: apqc(lbo(1):ubo(1),lbo(2):ubo(2))
4046  REAL(4), INTENT(OUT), OPTIONAL :: dxdp(lbo(1):ubo(1),lbo(2):ubo(2))
4047  REAL(4), INTENT(OUT), OPTIONAL :: dydp(lbo(1):ubo(1),lbo(2):ubo(2))
4048  REAL(4), INTENT(OUT), OPTIONAL :: dxdq(lbo(1):ubo(1),lbo(2):ubo(2))
4049  REAL(4), INTENT(OUT), OPTIONAL :: dydq(lbo(1):ubo(1),lbo(2):ubo(2))
4050  REAL(4), INTENT(OUT), OPTIONAL :: dpdx(lbo(1):ubo(1),lbo(2):ubo(2))
4051  REAL(4), INTENT(OUT), OPTIONAL :: dpdy(lbo(1):ubo(1),lbo(2):ubo(2))
4052  REAL(4), INTENT(OUT), OPTIONAL :: dqdx(lbo(1):ubo(1),lbo(2):ubo(2))
4053  REAL(4), INTENT(OUT), OPTIONAL :: dqdy(lbo(1):ubo(1),lbo(2):ubo(2))
4054  REAL(4), INTENT(OUT), OPTIONAL :: cosa(lbo(1):ubo(1),lbo(2):ubo(2))
4055  REAL(4), INTENT(OUT), OPTIONAL :: cosc(lbo(1):ubo(1),lbo(2):ubo(2))
4056  REAL(4), INTENT(OUT), OPTIONAL :: sinc(lbo(1):ubo(1),lbo(2):ubo(2))
4057  REAL(4), INTENT(OUT), OPTIONAL :: angl(lbo(1):ubo(1),lbo(2):ubo(2))
4058  INTEGER, INTENT(OUT), OPTIONAL :: rc
4059 
4060  ! Local parameters
4061  INTEGER, PARAMETER :: m = 1 ! order of derivative
4062  REAL(8), PARAMETER :: small = 1d-15
4063  INTEGER :: istat=0, n, np, nq, i1, i2, p, q
4064  LOGICAL :: sphr
4065  REAL(8) :: r, facx, facy
4066  INTEGER, ALLOCATABLE :: k(:,:,:), k2(:,:,:)
4067  REAL(8), ALLOCATABLE :: c(:,:,:), c2(:,:,:)
4068  REAL(8) :: gppcl, gqqcl, gpqcl
4069  REAL(8) :: gsqrl, hpfcl, hqfcl
4070  REAL(8) :: appcl, aqqcl, apqcl
4071  REAL(8) :: dxdpl, dydpl, dxdql, dydql
4072  REAL(8) :: dpdxl, dpdyl, dqdxl, dqdyl
4073  REAL(8) :: cosal, sinal, costp, sintp, coscl, sincl, angll
4074 #ifdef W3_S
4075  INTEGER, SAVE :: ient = 0
4076  CALL strace (ient, 'W3CGDM_R4')
4077 #endif
4078  ! -------------------------------------------------------------------- /
4079  ! 1. Check and setup inputs
4080  !
4081  IF ( PRESENT(rc) ) rc = 0
4082 
4083  IF ( PRESENT(nfd) ) THEN
4084  n = nfd
4085  ELSE
4086  n = nfd_default
4087  END IF
4088  IF ( n.LE.0 .OR. mod(n,2).NE.0 ) THEN
4089  WRITE(0,'(/1A,1A/)') 'W3CGDM ERROR -- ', &
4090  'NFD must be even and greater than zero'
4091  istat = 1
4092  IF ( PRESENT(rc) ) THEN
4093  rc = istat
4094  RETURN
4095  ELSE
4096  CALL extcde (istat)
4097  END IF
4098  END IF
4099 
4100  np = prange(2) - prange(1) + 1
4101  nq = qrange(2) - qrange(1) + 1
4102 
4103  SELECT CASE ( iclo )
4105  CONTINUE
4106  CASE DEFAULT
4107  WRITE(0,'(/1A,1A,1I2/)') 'W3CGDM ERROR -- ', &
4108  'unsupported ICLO: ',iclo
4109  istat = 1
4110  IF ( PRESENT(rc) ) THEN
4111  rc = istat
4112  RETURN
4113  ELSE
4114  CALL extcde (istat)
4115  END IF
4116  END SELECT
4117 
4118  IF ( iclo.EQ.iclo_trpl .AND. mod(np,2).NE.0 ) THEN
4119  WRITE(0,'(/1A,1A/)') 'W3CGDM ERROR -- ', &
4120  'tripole grid closure requires NP even'
4121  istat = 1
4122  IF ( PRESENT(rc) ) THEN
4123  rc = istat
4124  RETURN
4125  ELSE
4126  CALL extcde (istat)
4127  END IF
4128  END IF
4129 
4130  IF ( PRESENT(sphere) ) THEN
4131  sphr = sphere
4132  ELSE
4133  sphr = .true.
4134  END IF
4135 
4136  IF ( PRESENT(radius) ) THEN
4137  r = radius
4138  ELSE
4139  r = rearth
4140  END IF
4141  facy = r*d2r
4142 
4143  IF ( PRESENT(dx) ) THEN
4144  IF ( dx.LE.zero ) THEN
4145  WRITE(0,'(/1A,1A/)') 'W3CGDM ERROR -- ','DX must be > 0'
4146  istat = 1
4147  IF ( PRESENT(rc) ) THEN
4148  rc = istat
4149  RETURN
4150  ELSE
4151  CALL extcde (istat)
4152  END IF
4153  END IF
4154  END IF
4155 
4156  IF ( PRESENT(dy) ) THEN
4157  IF ( dy.LE.zero ) THEN
4158  WRITE(0,'(/1A,1A/)') 'W3CGDM ERROR -- ','DY must be > 0'
4159  istat = 1
4160  IF ( PRESENT(rc) ) THEN
4161  rc = istat
4162  RETURN
4163  ELSE
4164  CALL extcde (istat)
4165  END IF
4166  END IF
4167  END IF
4168  !
4169  ! -------------------------------------------------------------------- /
4170  ! 2. Setup finite difference coefficients
4171  !
4172  ALLOCATE ( k(0:n,0:n,1:n), c(0:n,0:n,1:n), stat=istat )
4173  IF ( istat .NE. 0 ) THEN
4174  WRITE(0,'(/1A,1A/)') 'W3CGDM ERROR -- ', &
4175  'finite difference coeff allocation failed'
4176  IF ( PRESENT(rc) ) THEN
4177  rc = istat
4178  RETURN
4179  ELSE
4180  CALL extcde (istat)
4181  END IF
4182  END IF
4183  CALL get_fdw3 ( n, m, k, c )
4184 
4185  ALLOCATE ( k2(0:2,0:2,1:2), c2(0:2,0:2,1:2), stat=istat )
4186  IF ( istat .NE. 0 ) THEN
4187  WRITE(0,'(/1A,1A/)') 'W3CGDM ERROR -- ', &
4188  'finite difference coeff allocation for N=2 failed'
4189  IF ( PRESENT(rc) ) THEN
4190  rc = istat
4191  RETURN
4192  ELSE
4193  CALL extcde (istat)
4194  END IF
4195  END IF
4196  CALL get_fdw3 ( 2, m, k2, c2 )
4197  !
4198  ! -------------------------------------------------------------------- /
4199  ! 3. Compute optional return quantities
4200  !
4201  DO i2 = lbo(2), ubo(2)
4202  DO i1 = lbo(1), ubo(1)
4203  IF ( ijg ) THEN
4204  p = i1
4205  q = i2
4206  ELSE
4207  p = i2
4208  q = i1
4209  END IF
4210  IF ( PRESENT(dx) ) THEN
4211  dxdpl = dx
4212  dydpl = zero
4213  ELSE
4214  CALL dxydp( n, k, c, ijg, llg, iclo, ptiled, qtiled, &
4215  prange, qrange, lbi, ubi, p, q, dxdpl, dydpl, &
4216  mask=mask, x4=x, y4=y, rc=istat )
4217  IF ( istat .NE. 0 ) THEN
4218  IF ( PRESENT(rc) ) THEN
4219  rc = istat
4220  RETURN
4221  ELSE
4222  CALL extcde (istat)
4223  END IF
4224  END IF
4225  END IF
4226  IF ( PRESENT(dy) ) THEN
4227  dxdql = zero
4228  dydql = dy
4229  ELSE
4230  CALL dxydq( n, k, c, ijg, llg, iclo, ptiled, qtiled, &
4231  prange, qrange, lbi, ubi, p, q, dxdql, dydql, &
4232  mask=mask, x4=x, y4=y, rc=istat )
4233  IF ( istat .NE. 0 ) THEN
4234  IF ( PRESENT(rc) ) THEN
4235  rc = istat
4236  RETURN
4237  ELSE
4238  CALL extcde (istat)
4239  END IF
4240  END IF
4241  END IF
4242  IF ( llg .AND. sphr ) THEN
4243  facx = facy*cos(real(y(i1,i2),8)*d2r)
4244  dxdpl = dxdpl*facx
4245  dydpl = dydpl*facy
4246  dxdql = dxdql*facx
4247  dydql = dydql*facy
4248  END IF
4249  gsqrl = dxdpl*dydql - dxdql*dydpl
4250  IF ( gsqrl .LT. zero .AND. n .GT. 2 ) THEN
4251  ! WRITE(0,'(1A,1I0,1A,1I0,1A,1I0,2A)') &
4252  ! 'W3CGDM WARNING -- NFD = ',N, &
4253  ! ' yields GSQRL < 0 at (',P,',',Q,'):', &
4254  ! ' computing metrics using NFD = 2'
4255  IF ( PRESENT(dx) ) THEN
4256  dxdpl = dx
4257  dydpl = zero
4258  ELSE
4259  CALL dxydp( 2, k2, c2, ijg, llg, iclo, ptiled, qtiled, &
4260  prange, qrange, lbi, ubi, p, q, dxdpl, dydpl, &
4261  mask=mask, x4=x, y4=y, rc=istat )
4262  IF ( istat .NE. 0 ) THEN
4263  IF ( PRESENT(rc) ) THEN
4264  rc = istat
4265  RETURN
4266  ELSE
4267  CALL extcde (istat)
4268  END IF
4269  END IF
4270  END IF
4271  IF ( PRESENT(dy) ) THEN
4272  dxdql = zero
4273  dydql = dy
4274  ELSE
4275  CALL dxydq( 2, k2, c2, ijg, llg, iclo, ptiled, qtiled, &
4276  prange, qrange, lbi, ubi, p, q, dxdql, dydql, &
4277  mask=mask, x4=x, y4=y, rc=istat )
4278  IF ( istat .NE. 0 ) THEN
4279  IF ( PRESENT(rc) ) THEN
4280  rc = istat
4281  RETURN
4282  ELSE
4283  CALL extcde (istat)
4284  END IF
4285  END IF
4286  END IF
4287  IF ( llg .AND. sphr ) THEN
4288  facx = facy*cos(real(y(i1,i2),8)*d2r)
4289  dxdpl = dxdpl*facx
4290  dydpl = dydpl*facy
4291  dxdql = dxdql*facx
4292  dydql = dydql*facy
4293  END IF
4294  gsqrl = dxdpl*dydql - dxdql*dydpl
4295  END IF
4296  IF ( gsqrl .LT. zero ) THEN
4297  istat = 1
4298  WRITE(0,'(/1A,1A)') 'W3CGDM ERROR -- ', &
4299  'input coordinates do not define a '// &
4300  'right-handed coordinate system'
4301  WRITE(0,'(1A,2A6,5A16)') 'W3CGDM ERROR --', &
4302  'P','Q','GSQRL','DXDPL','DYDQL','DXDQL','DYDPL'
4303  WRITE(0,'(1A,2I6,5E16.8/)') 'W3CGDM ERROR --', &
4304  p,q,gsqrl,dxdpl,dydql,dxdql,dydpl
4305  IF ( PRESENT(rc) ) THEN
4306  rc = istat
4307  RETURN
4308  ELSE
4309  CALL extcde (istat)
4310  END IF
4311  END IF
4312  gppcl = dxdpl*dxdpl + dydpl*dydpl
4313  gqqcl = dxdql*dxdql + dydql*dydql
4314  gpqcl = dxdpl*dxdql + dydpl*dydql
4315  gsqrl = max(gsqrl,small)
4316  gppcl = max(gppcl,small)
4317  gqqcl = max(gqqcl,small)
4318  dpdxl = dydql/gsqrl
4319  dpdyl =-dxdql/gsqrl
4320  dqdxl =-dydpl/gsqrl
4321  dqdyl = dxdpl/gsqrl
4322  appcl = dpdxl*dpdxl + dpdyl*dpdyl
4323  aqqcl = dqdxl*dqdxl + dqdyl*dqdyl
4324  apqcl = dpdxl*dqdxl + dpdyl*dqdyl
4325  hpfcl = sqrt(gppcl)
4326  hqfcl = sqrt(gqqcl)
4327  cosal = gpqcl/(hpfcl*hqfcl)
4328  sinal = gsqrl**2/(gppcl*gqqcl)
4329  costp = dxdpl/hpfcl
4330  sintp = dydpl/hqfcl
4331  coscl = sinal*costp + cosal*sintp
4332  sincl = sinal*sintp - cosal*costp
4333  angll = atan2(sincl,coscl)*r2d
4334  IF (PRESENT(gppc)) gppc(i1,i2) = gppcl
4335  IF (PRESENT(gqqc)) gqqc(i1,i2) = gqqcl
4336  IF (PRESENT(gpqc)) gpqc(i1,i2) = gpqcl
4337  IF (PRESENT(appc)) appc(i1,i2) = appcl
4338  IF (PRESENT(aqqc)) aqqc(i1,i2) = aqqcl
4339  IF (PRESENT(apqc)) apqc(i1,i2) = apqcl
4340  IF (PRESENT(gsqr)) gsqr(i1,i2) = gsqrl
4341  IF (PRESENT(hpfc)) hpfc(i1,i2) = hpfcl
4342  IF (PRESENT(hqfc)) hqfc(i1,i2) = hqfcl
4343  IF (PRESENT(dxdp)) dxdp(i1,i2) = dxdpl
4344  IF (PRESENT(dydp)) dydp(i1,i2) = dydpl
4345  IF (PRESENT(dxdq)) dxdq(i1,i2) = dxdql
4346  IF (PRESENT(dydq)) dydq(i1,i2) = dydql
4347  IF (PRESENT(dpdx)) dpdx(i1,i2) = dpdxl
4348  IF (PRESENT(dpdy)) dpdy(i1,i2) = dpdyl
4349  IF (PRESENT(dqdx)) dqdx(i1,i2) = dqdxl
4350  IF (PRESENT(dqdy)) dqdy(i1,i2) = dqdyl
4351  IF (PRESENT(cosa)) cosa(i1,i2) = cosal
4352  IF (PRESENT(cosc)) cosc(i1,i2) = coscl
4353  IF (PRESENT(sinc)) sinc(i1,i2) = sincl
4354  IF (PRESENT(angl)) angl(i1,i2) = angll
4355  END DO !I1
4356  END DO !I2
4357  !
4358  ! -------------------------------------------------------------------- /
4359  ! 4. Clean up
4360  !
4361  DEALLOCATE ( k, c, k2, c2 )
4362 
4363  END SUBROUTINE w3cgdm_r4
4364  !/
4365  !/ ------------------------------------------------------------------- /
4366  !/
4367  SUBROUTINE w3cgdm_r8( IJG, LLG, ICLO, PTILED, QTILED, &
4368  PRANGE, QRANGE, LBI, UBI, LBO, UBO, X, Y, &
4369  MASK, NFD, SPHERE, RADIUS, DX, DY, &
4370  GPPC, GQQC, GPQC, GSQR, &
4371  HPFC, HQFC, APPC, AQQC, APQC, &
4372  DXDP, DYDP, DXDQ, DYDQ, &
4373  DPDX, DPDY, DQDX, DQDY, &
4374  COSA, COSC, SINC, ANGL, RC )
4375  ! Double precision interface
4376  LOGICAL, INTENT(IN) :: ijg
4377  LOGICAL, INTENT(IN) :: llg
4378  INTEGER, INTENT(IN) :: iclo
4379  LOGICAL, INTENT(IN) :: ptiled, qtiled
4380  INTEGER, INTENT(IN) :: prange(2), qrange(2)
4381  INTEGER, INTENT(IN) :: lbi(2), ubi(2)
4382  INTEGER, INTENT(IN) :: lbo(2), ubo(2)
4383  REAL(8), INTENT(IN) :: x(lbi(1):ubi(1),lbi(2):ubi(2))
4384  REAL(8), INTENT(IN) :: y(lbi(1):ubi(1),lbi(2):ubi(2))
4385  LOGICAL, INTENT(IN), OPTIONAL :: mask(lbi(1):ubi(1),lbi(2):ubi(2))
4386  INTEGER, INTENT(IN), OPTIONAL :: nfd
4387  LOGICAL, INTENT(IN), OPTIONAL :: sphere
4388  REAL(8), INTENT(IN), OPTIONAL :: radius
4389  REAL(8), INTENT(IN), OPTIONAL :: dx, dy
4390  REAL(8), INTENT(OUT), OPTIONAL :: gppc(lbo(1):ubo(1),lbo(2):ubo(2))
4391  REAL(8), INTENT(OUT), OPTIONAL :: gqqc(lbo(1):ubo(1),lbo(2):ubo(2))
4392  REAL(8), INTENT(OUT), OPTIONAL :: gpqc(lbo(1):ubo(1),lbo(2):ubo(2))
4393  REAL(8), INTENT(OUT), OPTIONAL :: gsqr(lbo(1):ubo(1),lbo(2):ubo(2))
4394  REAL(8), INTENT(OUT), OPTIONAL :: hpfc(lbo(1):ubo(1),lbo(2):ubo(2))
4395  REAL(8), INTENT(OUT), OPTIONAL :: hqfc(lbo(1):ubo(1),lbo(2):ubo(2))
4396  REAL(8), INTENT(OUT), OPTIONAL :: appc(lbo(1):ubo(1),lbo(2):ubo(2))
4397  REAL(8), INTENT(OUT), OPTIONAL :: aqqc(lbo(1):ubo(1),lbo(2):ubo(2))
4398  REAL(8), INTENT(OUT), OPTIONAL :: apqc(lbo(1):ubo(1),lbo(2):ubo(2))
4399  REAL(8), INTENT(OUT), OPTIONAL :: dxdp(lbo(1):ubo(1),lbo(2):ubo(2))
4400  REAL(8), INTENT(OUT), OPTIONAL :: dydp(lbo(1):ubo(1),lbo(2):ubo(2))
4401  REAL(8), INTENT(OUT), OPTIONAL :: dxdq(lbo(1):ubo(1),lbo(2):ubo(2))
4402  REAL(8), INTENT(OUT), OPTIONAL :: dydq(lbo(1):ubo(1),lbo(2):ubo(2))
4403  REAL(8), INTENT(OUT), OPTIONAL :: dpdx(lbo(1):ubo(1),lbo(2):ubo(2))
4404  REAL(8), INTENT(OUT), OPTIONAL :: dpdy(lbo(1):ubo(1),lbo(2):ubo(2))
4405  REAL(8), INTENT(OUT), OPTIONAL :: dqdx(lbo(1):ubo(1),lbo(2):ubo(2))
4406  REAL(8), INTENT(OUT), OPTIONAL :: dqdy(lbo(1):ubo(1),lbo(2):ubo(2))
4407  REAL(8), INTENT(OUT), OPTIONAL :: cosa(lbo(1):ubo(1),lbo(2):ubo(2))
4408  REAL(8), INTENT(OUT), OPTIONAL :: cosc(lbo(1):ubo(1),lbo(2):ubo(2))
4409  REAL(8), INTENT(OUT), OPTIONAL :: sinc(lbo(1):ubo(1),lbo(2):ubo(2))
4410  REAL(8), INTENT(OUT), OPTIONAL :: angl(lbo(1):ubo(1),lbo(2):ubo(2))
4411  INTEGER, INTENT(OUT), OPTIONAL :: rc
4412 
4413  ! Local parameters
4414  INTEGER, PARAMETER :: m = 1 ! order of derivative
4415  REAL(8), PARAMETER :: small = 1d-15
4416  INTEGER :: istat=0, n, np, nq, i1, i2, p, q
4417  LOGICAL :: sphr
4418  REAL(8) :: r, facx, facy
4419  INTEGER, ALLOCATABLE :: k(:,:,:), k2(:,:,:)
4420  REAL(8), ALLOCATABLE :: c(:,:,:), c2(:,:,:)
4421  REAL(8) :: gppcl, gqqcl, gpqcl
4422  REAL(8) :: gsqrl, hpfcl, hqfcl
4423  REAL(8) :: appcl, aqqcl, apqcl
4424  REAL(8) :: dxdpl, dydpl, dxdql, dydql
4425  REAL(8) :: dpdxl, dpdyl, dqdxl, dqdyl
4426  REAL(8) :: cosal, sinal, costp, sintp, coscl, sincl, angll
4427 #ifdef W3_S
4428  INTEGER, SAVE :: ient = 0
4429  CALL strace (ient, 'W3CGDM_R8')
4430 #endif
4431  ! -------------------------------------------------------------------- /
4432  ! 1. Check and setup inputs
4433  !
4434  IF ( PRESENT(rc) ) rc = 0
4435 
4436  IF ( PRESENT(nfd) ) THEN
4437  n = nfd
4438  ELSE
4439  n = nfd_default
4440  END IF
4441  IF ( n.LE.0 .OR. mod(n,2).NE.0 ) THEN
4442  WRITE(0,'(/1A,1A/)') 'W3CGDM ERROR -- ', &
4443  'NFD must be even and greater than zero'
4444  istat = 1
4445  IF ( PRESENT(rc) ) THEN
4446  rc = istat
4447  RETURN
4448  ELSE
4449  CALL extcde (istat)
4450  END IF
4451  END IF
4452 
4453  np = prange(2) - prange(1) + 1
4454  nq = qrange(2) - qrange(1) + 1
4455 
4456  SELECT CASE ( iclo )
4458  CONTINUE
4459  CASE DEFAULT
4460  WRITE(0,'(/1A,1A,1I2/)') 'W3CGDM ERROR -- ', &
4461  'unsupported ICLO: ',iclo
4462  istat = 1
4463  IF ( PRESENT(rc) ) THEN
4464  rc = istat
4465  RETURN
4466  ELSE
4467  CALL extcde (istat)
4468  END IF
4469  END SELECT
4470 
4471  IF ( iclo.EQ.iclo_trpl .AND. mod(np,2).NE.0 ) THEN
4472  WRITE(0,'(/1A,1A/)') 'W3CGDM ERROR -- ', &
4473  'tripole grid closure requires NP even'
4474  istat = 1
4475  IF ( PRESENT(rc) ) THEN
4476  rc = istat
4477  RETURN
4478  ELSE
4479  CALL extcde (istat)
4480  END IF
4481  END IF
4482 
4483  IF ( PRESENT(sphere) ) THEN
4484  sphr = sphere
4485  ELSE
4486  sphr = .true.
4487  END IF
4488 
4489  IF ( PRESENT(radius) ) THEN
4490  r = radius
4491  ELSE
4492  r = rearth
4493  END IF
4494  facy = r*d2r
4495 
4496  IF ( PRESENT(dx) ) THEN
4497  IF ( dx.LE.zero ) THEN
4498  WRITE(0,'(/1A,1A/)') 'W3CGDM ERROR -- ','DX must be > 0'
4499  istat = 1
4500  IF ( PRESENT(rc) ) THEN
4501  rc = istat
4502  RETURN
4503  ELSE
4504  CALL extcde (istat)
4505  END IF
4506  END IF
4507  END IF
4508 
4509  IF ( PRESENT(dy) ) THEN
4510  IF ( dy.LE.zero ) THEN
4511  WRITE(0,'(/1A,1A/)') 'W3CGDM ERROR -- ','DY must be > 0'
4512  istat = 1
4513  IF ( PRESENT(rc) ) THEN
4514  rc = istat
4515  RETURN
4516  ELSE
4517  CALL extcde (istat)
4518  END IF
4519  END IF
4520  END IF
4521  !
4522  ! -------------------------------------------------------------------- /
4523  ! 2. Setup finite difference coefficients
4524  !
4525  ALLOCATE ( k(0:n,0:n,1:n), c(0:n,0:n,1:n), stat=istat )
4526  IF ( istat .NE. 0 ) THEN
4527  WRITE(0,'(/1A,1A/)') 'W3CGDM ERROR -- ', &
4528  'finite difference coeff allocation failed'
4529  IF ( PRESENT(rc) ) THEN
4530  rc = istat
4531  RETURN
4532  ELSE
4533  CALL extcde (istat)
4534  END IF
4535  END IF
4536  CALL get_fdw3 ( n, m, k, c )
4537 
4538  ALLOCATE ( k2(0:2,0:2,1:2), c2(0:2,0:2,1:2), stat=istat )
4539  IF ( istat .NE. 0 ) THEN
4540  WRITE(0,'(/1A,1A/)') 'W3CGDM ERROR -- ', &
4541  'finite difference coeff allocation for N=2 failed'
4542  IF ( PRESENT(rc) ) THEN
4543  rc = istat
4544  RETURN
4545  ELSE
4546  CALL extcde (istat)
4547  END IF
4548  END IF
4549  CALL get_fdw3 ( 2, m, k2, c2 )
4550  !
4551  ! -------------------------------------------------------------------- /
4552  ! 3. Compute optional return quantities
4553  !
4554  DO i2 = lbo(2), ubo(2)
4555  DO i1 = lbo(1), ubo(1)
4556  IF ( ijg ) THEN
4557  p = i1
4558  q = i2
4559  ELSE
4560  p = i2
4561  q = i1
4562  END IF
4563  IF ( PRESENT(dx) ) THEN
4564  dxdpl = dx
4565  dydpl = zero
4566  ELSE
4567  CALL dxydp( n, k, c, ijg, llg, iclo, ptiled, qtiled, &
4568  prange, qrange, lbi, ubi, p, q, dxdpl, dydpl, &
4569  mask=mask, x8=x, y8=y, rc=istat )
4570  IF ( istat .NE. 0 ) THEN
4571  IF ( PRESENT(rc) ) THEN
4572  rc = istat
4573  RETURN
4574  ELSE
4575  CALL extcde (istat)
4576  END IF
4577  END IF
4578  END IF
4579  IF ( PRESENT(dy) ) THEN
4580  dxdql = zero
4581  dydql = dy
4582  ELSE
4583  CALL dxydq( n, k, c, ijg, llg, iclo, ptiled, qtiled, &
4584  prange, qrange, lbi, ubi, p, q, dxdql, dydql, &
4585  mask=mask, x8=x, y8=y, rc=istat )
4586  IF ( istat .NE. 0 ) THEN
4587  IF ( PRESENT(rc) ) THEN
4588  rc = istat
4589  RETURN
4590  ELSE
4591  CALL extcde (istat)
4592  END IF
4593  END IF
4594  END IF
4595  IF ( llg .AND. sphr ) THEN
4596  facx = facy*cos(real(y(i1,i2),8)*d2r)
4597  dxdpl = dxdpl*facx
4598  dydpl = dydpl*facy
4599  dxdql = dxdql*facx
4600  dydql = dydql*facy
4601  END IF
4602  gsqrl = dxdpl*dydql - dxdql*dydpl
4603  IF ( gsqrl .LT. zero .AND. n .GT. 2 ) THEN
4604  ! WRITE(0,'(1A,1I0,1A,1I0,1A,1I0,2A)') &
4605  ! 'W3CGDM WARNING -- NFD = ',N, &
4606  ! ' yields GSQRL < 0 at (',P,',',Q,'):', &
4607  ! ' computing metrics using NFD = 2'
4608  IF ( PRESENT(dx) ) THEN
4609  dxdpl = dx
4610  dydpl = zero
4611  ELSE
4612  CALL dxydp( 2, k2, c2, ijg, llg, iclo, ptiled, qtiled, &
4613  prange, qrange, lbi, ubi, p, q, dxdpl, dydpl, &
4614  mask=mask, x8=x, y8=y, rc=istat )
4615  IF ( istat .NE. 0 ) THEN
4616  IF ( PRESENT(rc) ) THEN
4617  rc = istat
4618  RETURN
4619  ELSE
4620  CALL extcde (istat)
4621  END IF
4622  END IF
4623  END IF
4624  IF ( PRESENT(dy) ) THEN
4625  dxdql = zero
4626  dydql = dy
4627  ELSE
4628  CALL dxydq( 2, k2, c2, ijg, llg, iclo, ptiled, qtiled, &
4629  prange, qrange, lbi, ubi, p, q, dxdql, dydql, &
4630  mask=mask, x8=x, y8=y, rc=istat )
4631  IF ( istat .NE. 0 ) THEN
4632  IF ( PRESENT(rc) ) THEN
4633  rc = istat
4634  RETURN
4635  ELSE
4636  CALL extcde (istat)
4637  END IF
4638  END IF
4639  END IF
4640  IF ( llg .AND. sphr ) THEN
4641  facx = facy*cos(real(y(i1,i2),8)*d2r)
4642  dxdpl = dxdpl*facx
4643  dydpl = dydpl*facy
4644  dxdql = dxdql*facx
4645  dydql = dydql*facy
4646  END IF
4647  gsqrl = dxdpl*dydql - dxdql*dydpl
4648  END IF
4649  IF ( gsqrl .LT. zero ) THEN
4650  istat = 1
4651  WRITE(0,'(/1A,1A)') 'W3CGDM ERROR -- ', &
4652  'input coordinates do not define a '// &
4653  'right-handed coordinate system'
4654  WRITE(0,'(1A,2A6,5A16)') 'W3CGDM ERROR --', &
4655  'P','Q','GSQRL','DXDPL','DYDQL','DXDQL','DYDPL'
4656  WRITE(0,'(1A,2I6,5E16.8/)') 'W3CGDM ERROR --', &
4657  p,q,gsqrl,dxdpl,dydql,dxdql,dydpl
4658  IF ( PRESENT(rc) ) THEN
4659  rc = istat
4660  RETURN
4661  ELSE
4662  CALL extcde (istat)
4663  END IF
4664  END IF
4665  gppcl = dxdpl*dxdpl + dydpl*dydpl
4666  gqqcl = dxdql*dxdql + dydql*dydql
4667  gpqcl = dxdpl*dxdql + dydpl*dydql
4668  gsqrl = max(gsqrl,small)
4669  gppcl = max(gppcl,small)
4670  gqqcl = max(gqqcl,small)
4671  dpdxl = dydql/gsqrl
4672  dpdyl =-dxdql/gsqrl
4673  dqdxl =-dydpl/gsqrl
4674  dqdyl = dxdpl/gsqrl
4675  appcl = dpdxl*dpdxl + dpdyl*dpdyl
4676  aqqcl = dqdxl*dqdxl + dqdyl*dqdyl
4677  apqcl = dpdxl*dqdxl + dpdyl*dqdyl
4678  hpfcl = sqrt(gppcl)
4679  hqfcl = sqrt(gqqcl)
4680  cosal = gpqcl/(hpfcl*hqfcl)
4681  sinal = gsqrl**2/(gppcl*gqqcl)
4682  costp = dxdpl/hpfcl
4683  sintp = dydpl/hqfcl
4684  coscl = sinal*costp + cosal*sintp
4685  sincl = sinal*sintp - cosal*costp
4686  angll = atan2(sincl,coscl)*r2d
4687  IF (PRESENT(gppc)) gppc(i1,i2) = gppcl
4688  IF (PRESENT(gqqc)) gqqc(i1,i2) = gqqcl
4689  IF (PRESENT(gpqc)) gpqc(i1,i2) = gpqcl
4690  IF (PRESENT(appc)) appc(i1,i2) = appcl
4691  IF (PRESENT(aqqc)) aqqc(i1,i2) = aqqcl
4692  IF (PRESENT(apqc)) apqc(i1,i2) = apqcl
4693  IF (PRESENT(gsqr)) gsqr(i1,i2) = gsqrl
4694  IF (PRESENT(hpfc)) hpfc(i1,i2) = hpfcl
4695  IF (PRESENT(hqfc)) hqfc(i1,i2) = hqfcl
4696  IF (PRESENT(dxdp)) dxdp(i1,i2) = dxdpl
4697  IF (PRESENT(dydp)) dydp(i1,i2) = dydpl
4698  IF (PRESENT(dxdq)) dxdq(i1,i2) = dxdql
4699  IF (PRESENT(dydq)) dydq(i1,i2) = dydql
4700  IF (PRESENT(dpdx)) dpdx(i1,i2) = dpdxl
4701  IF (PRESENT(dpdy)) dpdy(i1,i2) = dpdyl
4702  IF (PRESENT(dqdx)) dqdx(i1,i2) = dqdxl
4703  IF (PRESENT(dqdy)) dqdy(i1,i2) = dqdyl
4704  IF (PRESENT(cosa)) cosa(i1,i2) = cosal
4705  IF (PRESENT(cosc)) cosc(i1,i2) = coscl
4706  IF (PRESENT(sinc)) sinc(i1,i2) = sincl
4707  IF (PRESENT(angl)) angl(i1,i2) = atan2(sincl,coscl)*r2d
4708  IF (PRESENT(angl)) angl(i1,i2) = angll
4709  END DO !I1
4710  END DO !I2
4711  !
4712  ! -------------------------------------------------------------------- /
4713  ! 4. Clean up
4714  !
4715  DEALLOCATE ( k, c, k2, c2 )
4716 
4717  END SUBROUTINE w3cgdm_r8
4718  !/
4719  !/ End of W3CGDM ===================================================== /
4720  !/
4721 
4722 
4723 
4724 
4725 
4726 
4727 
4728 
4729  !/
4730  !/ =================================================================== /
4731  !/
4732  !/ SUBROUTINE W3GRD0( NFD, IJG, ICLO, PTILED, QTILED, &
4733  !/ PRANGE, QRANGE, LBI, UBI, LBO, UBO, &
4734  !/ DPDX, DPDY, DQDX, DQDY, &
4735  !/ F, DFDX, DFDY, MASK, RC )
4736  !/
4737  !/ =================================================================== /
4738  !/
4739  ! 1. Purpose :
4740  !
4741  ! Compute gradient of a scalar field F(x,y) defined on a
4742  ! curvilinear coordinate grid (x(p,q),y(p,q)).
4743  !
4744  ! 2. Method :
4745  !
4746  ! Compute derivatives using finite-difference method.
4747  ! Apply curvilinear grid metric.
4748  !
4749  ! 3. Parameters :
4750  !
4751  ! Parameter list
4752  ! ----------------------------------------------------------------
4753  ! NFD Int. I Finite-difference order (even)
4754  ! IJG Log. I Logical flag indicating ordering of input
4755  ! coord. arrays: T = (NP,NQ) and F = (NP,NQ)
4756  ! ICLO Int. I Parameter indicating type of index space closure.
4757  ! PTILED Log. I Logical flag indicating that input arrays are tiled
4758  ! in P-axis with halos of width >= NFD/2
4759  ! QTILED Log. I Logical flag indicating that input arrays are tiled
4760  ! in Q-axis with halos of width >= NFD/2
4761  ! PRANGE I.A. I Range of P index coordinate: P in [PRANGE(1),PRANGE(2)]
4762  ! QRANGE I.A. I Range of Q index coordinate: Q in [QRANGE(1),QRANGE(2)]
4763  ! LBI I.A. I Lower-bound of input arrays, DIMENSION(2)
4764  ! UBI I.A. I Upper-bound of input arrays, DIMENSION(2)
4765  ! LBO I.A. I Lower-bound of output arrays, DIMENSION(2)
4766  ! UBO I.A. I Upper-bound of output arrays, DIMENSION(2)
4767  ! DPDX R.A. I dp/dx, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
4768  ! DPDY R.A. I dp/dy, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
4769  ! DQDX R.A. I dq/dx, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
4770  ! DQDY R.A. I dq/dy, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
4771  ! F R.A. I Scalar input field, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
4772  ! DFDX R.A. O df/dx, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
4773  ! DFDY R.A. O df/dy, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
4774  ! MASK L.A. I OPTIONAL logical mask (T = invalid, F = valid)
4775  ! DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
4776  ! RC Int. O OPTIONAL return code (!= 0 if error occurs)
4777  ! ----------------------------------------------------------------
4778  !
4779  ! 4. Subroutines used :
4780  !
4781  ! See module documentation.
4782  !
4783  ! 5. Called by :
4784  !
4785  ! 6. Error messages :
4786  !
4787  ! 7. Remarks :
4788  !
4789  ! - If RC is not provided and an error occurs, then the routine will
4790  ! report error to stderr and attempt to abort the calling program.
4791  ! - When MASK is specified, points that are masked are excluded from
4792  ! the finite-difference stencil. In order to avoid reaching across
4793  ! masked regions, the stencil is modified to one-sided and/or the
4794  ! finite-difference order is reduced. If the masking results in a
4795  ! single point wide channel, then the derivative in the direction
4796  ! across the channel is set to zero.
4797  !
4798  ! 8. Structure :
4799  !
4800  ! 9. Switches :
4801  !
4802  ! !/S Enable subroutine tracing.
4803  !
4804  ! 10. Source code :
4805  !/
4806  !/ ------------------------------------------------------------------- /
4807  !/
4808  SUBROUTINE w3grd0_r4( NFD, IJG, ICLO, PTILED, QTILED, &
4809  PRANGE, QRANGE, LBI, UBI, LBO, UBO, &
4810  DPDX, DPDY, DQDX, DQDY, &
4811  F, DFDX, DFDY, MASK, RC )
4812  ! Single precision interface
4813  INTEGER, INTENT(IN) :: nfd
4814  LOGICAL, INTENT(IN) :: ijg
4815  INTEGER, INTENT(IN) :: iclo
4816  LOGICAL, INTENT(IN) :: ptiled, qtiled
4817  INTEGER, INTENT(IN) :: prange(2), qrange(2)
4818  INTEGER, INTENT(IN) :: lbi(2), ubi(2)
4819  INTEGER, INTENT(IN) :: lbo(2), ubo(2)
4820  REAL(4), INTENT(IN) :: dpdx(lbi(1):ubi(1),lbi(2):ubi(2))
4821  REAL(4), INTENT(IN) :: dpdy(lbi(1):ubi(1),lbi(2):ubi(2))
4822  REAL(4), INTENT(IN) :: dqdx(lbi(1):ubi(1),lbi(2):ubi(2))
4823  REAL(4), INTENT(IN) :: dqdy(lbi(1):ubi(1),lbi(2):ubi(2))
4824  REAL(4), INTENT(IN) :: f(lbi(1):ubi(1),lbi(2):ubi(2))
4825  REAL(4), INTENT(OUT) :: dfdx(lbo(1):ubo(1),lbo(2):ubo(2))
4826  REAL(4), INTENT(OUT) :: dfdy(lbo(1):ubo(1),lbo(2):ubo(2))
4827  LOGICAL, INTENT(IN), OPTIONAL :: mask(lbi(1):ubi(1),lbi(2):ubi(2))
4828  INTEGER, INTENT(OUT), OPTIONAL :: rc
4829 
4830  ! Local parameters
4831  INTEGER, PARAMETER :: m = 1 ! order of derivative
4832  INTEGER :: np, nq, i1, i2, p, q
4833  INTEGER :: istat=0
4834  INTEGER :: k(0:nfd,0:nfd,1:nfd)
4835  REAL(8) :: c(0:nfd,0:nfd,1:nfd)
4836  REAL(8) :: dfdp, dfdq
4837 #ifdef W3_S
4838  INTEGER, SAVE :: ient = 0
4839  CALL strace (ient, 'W3GRD0_R4')
4840 #endif
4841  ! -------------------------------------------------------------------- /
4842  ! 1. Check and setup inputs
4843  !
4844  IF ( PRESENT(rc) ) rc = 0
4845 
4846  IF ( nfd.LE.0 .OR. mod(nfd,2).NE.0 ) THEN
4847  WRITE(0,'(/1A,1A/)') 'W3GRD0 ERROR -- ', &
4848  'NFD must be even and greater than zero'
4849  istat = 1
4850  IF ( PRESENT(rc) ) THEN
4851  rc = istat
4852  RETURN
4853  ELSE
4854  CALL extcde (istat)
4855  END IF
4856  END IF
4857 
4858  np = prange(2) - prange(1) + 1
4859  nq = qrange(2) - qrange(1) + 1
4860 
4861  SELECT CASE ( iclo )
4863  CONTINUE
4864  CASE DEFAULT
4865  WRITE(0,'(/1A,1A,1I2/)') 'W3GRD0 ERROR -- ', &
4866  'unsupported ICLO: ',iclo
4867  istat = 1
4868  IF ( PRESENT(rc) ) THEN
4869  rc = istat
4870  RETURN
4871  ELSE
4872  CALL extcde (istat)
4873  END IF
4874  END SELECT
4875 
4876  IF ( iclo.EQ.iclo_trpl .AND. mod(np,2).NE.0 ) THEN
4877  WRITE(0,'(/1A,1A/)') 'W3GRD0 ERROR -- ', &
4878  'tripole grid closure requires NP even'
4879  istat = 1
4880  IF ( PRESENT(rc) ) THEN
4881  rc = istat
4882  RETURN
4883  ELSE
4884  CALL extcde (istat)
4885  END IF
4886  END IF
4887  !
4888  ! -------------------------------------------------------------------- /
4889  ! 2. Setup finite difference coefficients
4890  !
4891  CALL get_fdw3 ( nfd, m, k, c )
4892  !
4893  ! -------------------------------------------------------------------- /
4894  ! 3. Compute dF/dx & dF/dy
4895  !
4896  DO i2 = lbo(2), ubo(2)
4897  DO i1 = lbo(1), ubo(1)
4898  IF ( PRESENT(mask) ) THEN
4899  IF ( mask(i1,i2) ) cycle
4900  END IF
4901  IF ( ijg ) THEN
4902  p = i1
4903  q = i2
4904  ELSE
4905  p = i2
4906  q = i1
4907  END IF
4908  CALL dfdpq ( nfd, k, c, ijg, iclo, ptiled, qtiled, &
4909  prange, qrange, lbi, ubi, p, q, &
4910  f4=f, dfdp=dfdp, dfdq=dfdq, &
4911  mask=mask, rc=istat )
4912  IF ( istat .NE. 0 ) THEN
4913  IF ( PRESENT(rc) ) THEN
4914  rc = istat
4915  RETURN
4916  ELSE
4917  CALL extcde (istat)
4918  END IF
4919  END IF
4920  dfdx(i1,i2) = dfdp*dpdx(i1,i2) + dfdq*dqdx(i1,i2)
4921  dfdy(i1,i2) = dfdp*dpdy(i1,i2) + dfdq*dqdy(i1,i2)
4922  END DO !I1
4923  END DO !I2
4924 
4925  END SUBROUTINE w3grd0_r4
4926  !/
4927  !/ ------------------------------------------------------------------- /
4928  !/
4929  SUBROUTINE w3grd0_r8( NFD, IJG, ICLO, PTILED, QTILED, &
4930  PRANGE, QRANGE, LBI, UBI, LBO, UBO, &
4931  DPDX, DPDY, DQDX, DQDY, &
4932  F, DFDX, DFDY, MASK, RC )
4933  ! Double precision interface
4934  INTEGER, INTENT(IN) :: nfd
4935  LOGICAL, INTENT(IN) :: ijg
4936  INTEGER, INTENT(IN) :: iclo
4937  LOGICAL, INTENT(IN) :: ptiled, qtiled
4938  INTEGER, INTENT(IN) :: prange(2), qrange(2)
4939  INTEGER, INTENT(IN) :: lbi(2), ubi(2)
4940  INTEGER, INTENT(IN) :: lbo(2), ubo(2)
4941  REAL(8), INTENT(IN) :: dpdx(lbi(1):ubi(1),lbi(2):ubi(2))
4942  REAL(8), INTENT(IN) :: dpdy(lbi(1):ubi(1),lbi(2):ubi(2))
4943  REAL(8), INTENT(IN) :: dqdx(lbi(1):ubi(1),lbi(2):ubi(2))
4944  REAL(8), INTENT(IN) :: dqdy(lbi(1):ubi(1),lbi(2):ubi(2))
4945  REAL(8), INTENT(IN) :: f(lbi(1):ubi(1),lbi(2):ubi(2))
4946  REAL(8), INTENT(OUT) :: dfdx(lbo(1):ubo(1),lbo(2):ubo(2))
4947  REAL(8), INTENT(OUT) :: dfdy(lbo(1):ubo(1),lbo(2):ubo(2))
4948  LOGICAL, INTENT(IN), OPTIONAL :: mask(lbi(1):ubi(1),lbi(2):ubi(2))
4949  INTEGER, INTENT(OUT), OPTIONAL :: rc
4950 
4951  ! Local parameters
4952  INTEGER, PARAMETER :: m = 1 ! order of derivative
4953  INTEGER :: np, nq, i1, i2, p, q
4954  INTEGER :: istat=0
4955  INTEGER :: k(0:nfd,0:nfd,1:nfd)
4956  REAL(8) :: c(0:nfd,0:nfd,1:nfd)
4957  REAL(8) :: dfdp, dfdq
4958 #ifdef W3_S
4959  INTEGER, SAVE :: ient = 0
4960  CALL strace (ient, 'W3GRD0_R8')
4961 #endif
4962  ! -------------------------------------------------------------------- /
4963  ! 1. Check and setup inputs
4964  !
4965  IF ( PRESENT(rc) ) rc = 0
4966 
4967  IF ( nfd.LE.0 .OR. mod(nfd,2).NE.0 ) THEN
4968  WRITE(0,'(/1A,1A/)') 'W3GRD0 ERROR -- ', &
4969  'NFD must be even and greater than zero'
4970  istat = 1
4971  IF ( PRESENT(rc) ) THEN
4972  rc = istat
4973  RETURN
4974  ELSE
4975  CALL extcde (istat)
4976  END IF
4977  END IF
4978 
4979  np = prange(2) - prange(1) + 1
4980  nq = qrange(2) - qrange(1) + 1
4981 
4982  SELECT CASE ( iclo )
4984  CONTINUE
4985  CASE DEFAULT
4986  WRITE(0,'(/1A,1A,1I2/)') 'W3GRD0 ERROR -- ', &
4987  'unsupported ICLO: ',iclo
4988  istat = 1
4989  IF ( PRESENT(rc) ) THEN
4990  rc = istat
4991  RETURN
4992  ELSE
4993  CALL extcde (istat)
4994  END IF
4995  END SELECT
4996 
4997  IF ( iclo.EQ.iclo_trpl .AND. mod(np,2).NE.0 ) THEN
4998  WRITE(0,'(/1A,1A/)') 'W3GRD0 ERROR -- ', &
4999  'tripole grid closure requires NP even'
5000  istat = 1
5001  IF ( PRESENT(rc) ) THEN
5002  rc = istat
5003  RETURN
5004  ELSE
5005  CALL extcde (istat)
5006  END IF
5007  END IF
5008  !
5009  ! -------------------------------------------------------------------- /
5010  ! 2. Setup finite difference coefficients
5011  !
5012  CALL get_fdw3 ( nfd, m, k, c )
5013  !
5014  ! -------------------------------------------------------------------- /
5015  ! 3. Compute dF/dx & dF/dy
5016  !
5017  DO i2 = lbo(2), ubo(2)
5018  DO i1 = lbo(1), ubo(1)
5019  IF ( PRESENT(mask) ) THEN
5020  IF ( mask(i1,i2) ) cycle
5021  END IF
5022  IF ( ijg ) THEN
5023  p = i1
5024  q = i2
5025  ELSE
5026  p = i2
5027  q = i1
5028  END IF
5029  CALL dfdpq ( nfd, k, c, ijg, iclo, ptiled, qtiled, &
5030  prange, qrange, lbi, ubi, p, q, &
5031  f8=f, dfdp=dfdp, dfdq=dfdq, &
5032  mask=mask, rc=istat )
5033  IF ( istat .NE. 0 ) THEN
5034  IF ( PRESENT(rc) ) THEN
5035  rc = istat
5036  RETURN
5037  ELSE
5038  CALL extcde (istat)
5039  END IF
5040  END IF
5041  dfdx(i1,i2) = dfdp*dpdx(i1,i2) + dfdq*dqdx(i1,i2)
5042  dfdy(i1,i2) = dfdp*dpdy(i1,i2) + dfdq*dqdy(i1,i2)
5043  END DO !I1
5044  END DO !I2
5045 
5046  END SUBROUTINE w3grd0_r8
5047  !/
5048  !/ End of W3GRD0 ===================================================== /
5049  !/
5050 
5051 
5052 
5053 
5054 
5055 
5056 
5057 
5058  !/
5059  !/ =================================================================== /
5060  !/
5061  !/ SUBROUTINE W3DIV1( NFD, IJG, ICLO, PTILED, QTILED, &
5062  !/ PRANGE, QRANGE, LBI, UBI, LBO, UBO, &
5063  !/ DPDX, DPDY, DQDX, DQDY, &
5064  !/ VX, VY, DIVV, MASK, RC )
5065  !/
5066  !/ =================================================================== /
5067  !/
5068  ! 1. Purpose :
5069  !
5070  ! Compute divergence of a vector field (V_x,V_y) defined
5071  ! on a curvilinear coordinate grid (x(p,q),y(p,q)).
5072  !
5073  ! 2. Method :
5074  !
5075  ! Compute derivatives using finite-difference method.
5076  ! Apply curvilinear grid metric.
5077  !
5078  ! 3. Parameters :
5079  !
5080  ! Parameter list
5081  ! ----------------------------------------------------------------
5082  ! NFD Int. I Finite-difference order (even)
5083  ! IJG Log. I Logical flag indicating ordering of input
5084  ! coord. arrays: T = (NP,NQ) and F = (NP,NQ)
5085  ! ICLO Int. I Parameter indicating type of index space closure.
5086  ! PTILED Log. I Logical flag indicating that input arrays are tiled
5087  ! in P-axis with halos of width >= NFD/2
5088  ! QTILED Log. I Logical flag indicating that input arrays are tiled
5089  ! in Q-axis with halos of width >= NFD/2
5090  ! PRANGE I.A. I Range of P index coordinate: P in [PRANGE(1),PRANGE(2)]
5091  ! QRANGE I.A. I Range of Q index coordinate: Q in [QRANGE(1),QRANGE(2)]
5092  ! LBI I.A. I Lower-bound of input arrays, DIMENSION(2)
5093  ! UBI I.A. I Upper-bound of input arrays, DIMENSION(2)
5094  ! LBO I.A. I Lower-bound of output arrays, DIMENSION(2)
5095  ! UBO I.A. I Upper-bound of output arrays, DIMENSION(2)
5096  ! DPDX R.A. I dp/dx, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5097  ! DPDY R.A. I dp/dy, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5098  ! DQDX R.A. I dq/dx, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5099  ! DQDY R.A. I dq/dy, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5100  ! VX R.A. I x-component of input vector field,
5101  ! DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5102  ! VY R.A. I y-component of input vector field,
5103  ! DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5104  ! DIVV R.A. O div(V), DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
5105  ! MASK L.A. I OPTIONAL logical mask (T = invalid, F = valid)
5106  ! DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5107  ! RC Int. O OPTIONAL return code (!= 0 if error occurs)
5108  ! ----------------------------------------------------------------
5109  !
5110  ! 4. Subroutines used :
5111  !
5112  ! See module documentation.
5113  !
5114  ! 5. Called by :
5115  !
5116  ! 6. Error messages :
5117  !
5118  ! 7. Remarks :
5119  !
5120  ! - If RC is not provided and an error occurs, then the routine will
5121  ! report error to stderr and attempt to abort the calling program.
5122  ! - When MASK is specified, points that are masked are excluded from
5123  ! the finite-difference stencil. In order to avoid reaching across
5124  ! masked regions, the stencil is modified to one-sided and/or the
5125  ! finite-difference order is reduced. If the masking results in a
5126  ! single point wide channel, then the derivative in the direction
5127  ! across the channel is set to zero.
5128  !
5129  ! 8. Structure :
5130  !
5131  ! 9. Switches :
5132  !
5133  ! !/S Enable subroutine tracing.
5134  !
5135  ! 10. Source code :
5136  !/
5137  !/ ------------------------------------------------------------------- /
5138  !/
5139  SUBROUTINE w3div1_r4( NFD, IJG, ICLO, PTILED, QTILED, &
5140  PRANGE, QRANGE, LBI, UBI, LBO, UBO, &
5141  DPDX, DPDY, DQDX, DQDY, &
5142  VX, VY, DIVV, MASK, RC )
5143  ! Single precision interface
5144  INTEGER, INTENT(IN) :: nfd
5145  LOGICAL, INTENT(IN) :: ijg
5146  INTEGER, INTENT(IN) :: iclo
5147  LOGICAL, INTENT(IN) :: ptiled, qtiled
5148  INTEGER, INTENT(IN) :: prange(2), qrange(2)
5149  INTEGER, INTENT(IN) :: lbi(2), ubi(2)
5150  INTEGER, INTENT(IN) :: lbo(2), ubo(2)
5151  REAL(4), INTENT(IN) :: dpdx(lbi(1):ubi(1),lbi(2):ubi(2))
5152  REAL(4), INTENT(IN) :: dpdy(lbi(1):ubi(1),lbi(2):ubi(2))
5153  REAL(4), INTENT(IN) :: dqdx(lbi(1):ubi(1),lbi(2):ubi(2))
5154  REAL(4), INTENT(IN) :: dqdy(lbi(1):ubi(1),lbi(2):ubi(2))
5155  REAL(4), INTENT(IN) :: vx(lbi(1):ubi(1),lbi(2):ubi(2))
5156  REAL(4), INTENT(IN) :: vy(lbi(1):ubi(1),lbi(2):ubi(2))
5157  REAL(4), INTENT(OUT) :: divv(lbo(1):ubo(1),lbo(2):ubo(2))
5158  LOGICAL, INTENT(IN), OPTIONAL :: mask(lbi(1):ubi(1),lbi(2):ubi(2))
5159  INTEGER, INTENT(OUT), OPTIONAL :: rc
5160 
5161  ! Local parameters
5162  INTEGER, PARAMETER :: m = 1 ! order of derivative
5163  INTEGER :: np, nq, i1, i2, p, q
5164  INTEGER :: istat=0
5165  INTEGER :: k(0:nfd,0:nfd,1:nfd)
5166  REAL(8) :: c(0:nfd,0:nfd,1:nfd)
5167  REAL(8) :: dvxdp, dvxdq, dvydp, dvydq
5168  REAL(8) :: dvxdx, dvydy
5169 #ifdef W3_S
5170  INTEGER, SAVE :: ient = 0
5171  CALL strace (ient, 'W3DIV1_R4')
5172 #endif
5173  ! -------------------------------------------------------------------- /
5174  ! 1. Check and setup inputs
5175  !
5176  IF ( PRESENT(rc) ) rc = 0
5177 
5178  IF ( nfd.LE.0 .OR. mod(nfd,2).NE.0 ) THEN
5179  WRITE(0,'(/1A,1A/)') 'W3DIV1 ERROR -- ', &
5180  'NFD must be even and greater than zero'
5181  istat = 1
5182  IF ( PRESENT(rc) ) THEN
5183  rc = istat
5184  RETURN
5185  ELSE
5186  CALL extcde (istat)
5187  END IF
5188  END IF
5189 
5190  np = prange(2) - prange(1) + 1
5191  nq = qrange(2) - qrange(1) + 1
5192 
5193  SELECT CASE ( iclo )
5195  CONTINUE
5196  CASE DEFAULT
5197  WRITE(0,'(/1A,1A,1I2/)') 'W3DIV1 ERROR -- ', &
5198  'unsupported ICLO: ',iclo
5199  istat = 1
5200  IF ( PRESENT(rc) ) THEN
5201  rc = istat
5202  RETURN
5203  ELSE
5204  CALL extcde (istat)
5205  END IF
5206  END SELECT
5207 
5208  IF ( iclo.EQ.iclo_trpl .AND. mod(np,2).NE.0 ) THEN
5209  WRITE(0,'(/1A,1A/)') 'W3DIV1 ERROR -- ', &
5210  'tripole grid closure requires NP even'
5211  istat = 1
5212  IF ( PRESENT(rc) ) THEN
5213  rc = istat
5214  RETURN
5215  ELSE
5216  CALL extcde (istat)
5217  END IF
5218  END IF
5219  !
5220  ! -------------------------------------------------------------------- /
5221  ! 2. Setup finite difference coefficients
5222  !
5223  CALL get_fdw3 ( nfd, m, k, c )
5224  !
5225  ! -------------------------------------------------------------------- /
5226  ! 3. Compute div(V) = dV_x/dx + dV_y/dy
5227  !
5228  DO i2 = lbo(2), ubo(2)
5229  DO i1 = lbo(1), ubo(1)
5230  IF ( PRESENT(mask) ) THEN
5231  IF ( mask(i1,i2) ) cycle
5232  END IF
5233  IF ( ijg ) THEN
5234  p = i1
5235  q = i2
5236  ELSE
5237  p = i2
5238  q = i1
5239  END IF
5240  CALL dfdpq ( nfd, k, c, ijg, iclo, ptiled, qtiled, &
5241  prange, qrange, lbi, ubi, p, q, &
5242  f4=vx, dfdp=dvxdp, dfdq=dvxdq, &
5243  g4=vy, dgdp=dvydp, dgdq=dvydq, &
5244  mask=mask, rc=istat )
5245  IF ( istat .NE. 0 ) THEN
5246  IF ( PRESENT(rc) ) THEN
5247  rc = istat
5248  RETURN
5249  ELSE
5250  CALL extcde (istat)
5251  END IF
5252  END IF
5253  dvxdx = dvxdp*dpdx(i1,i2) + dvxdq*dqdx(i1,i2)
5254  dvydy = dvydp*dpdy(i1,i2) + dvydq*dqdy(i1,i2)
5255  divv(i1,i2) = dvxdx + dvydy
5256  END DO !I1
5257  END DO !I2
5258 
5259  END SUBROUTINE w3div1_r4
5260  !/
5261  !/ ------------------------------------------------------------------- /
5262  !/
5263  SUBROUTINE w3div1_r8( NFD, IJG, ICLO, PTILED, QTILED, &
5264  PRANGE, QRANGE, LBI, UBI, LBO, UBO, &
5265  DPDX, DPDY, DQDX, DQDY, &
5266  VX, VY, DIVV, MASK, RC )
5267  ! Double precision interface
5268  INTEGER, INTENT(IN) :: nfd
5269  LOGICAL, INTENT(IN) :: ijg
5270  INTEGER, INTENT(IN) :: iclo
5271  LOGICAL, INTENT(IN) :: ptiled, qtiled
5272  INTEGER, INTENT(IN) :: prange(2), qrange(2)
5273  INTEGER, INTENT(IN) :: lbi(2), ubi(2)
5274  INTEGER, INTENT(IN) :: lbo(2), ubo(2)
5275  REAL(8), INTENT(IN) :: dpdx(lbi(1):ubi(1),lbi(2):ubi(2))
5276  REAL(8), INTENT(IN) :: dpdy(lbi(1):ubi(1),lbi(2):ubi(2))
5277  REAL(8), INTENT(IN) :: dqdx(lbi(1):ubi(1),lbi(2):ubi(2))
5278  REAL(8), INTENT(IN) :: dqdy(lbi(1):ubi(1),lbi(2):ubi(2))
5279  REAL(8), INTENT(IN) :: vx(lbi(1):ubi(1),lbi(2):ubi(2))
5280  REAL(8), INTENT(IN) :: vy(lbi(1):ubi(1),lbi(2):ubi(2))
5281  REAL(8), INTENT(OUT) :: divv(lbo(1):ubo(1),lbo(2):ubo(2))
5282  LOGICAL, INTENT(IN), OPTIONAL :: mask(lbi(1):ubi(1),lbi(2):ubi(2))
5283  INTEGER, INTENT(OUT), OPTIONAL :: rc
5284 
5285  ! Local parameters
5286  INTEGER, PARAMETER :: m = 1 ! order of derivative
5287  INTEGER :: np, nq, i1, i2, p, q
5288  INTEGER :: istat=0
5289  INTEGER :: k(0:nfd,0:nfd,1:nfd)
5290  REAL(8) :: c(0:nfd,0:nfd,1:nfd)
5291  REAL(8) :: dvxdp, dvxdq, dvydp, dvydq
5292  REAL(8) :: dvxdx, dvydy
5293 #ifdef W3_S
5294  INTEGER, SAVE :: ient = 0
5295  CALL strace (ient, 'W3DIV1_R8')
5296 #endif
5297  ! -------------------------------------------------------------------- /
5298  ! 1. Check and setup inputs
5299  !
5300  IF ( PRESENT(rc) ) rc = 0
5301 
5302  IF ( nfd.LE.0 .OR. mod(nfd,2).NE.0 ) THEN
5303  WRITE(0,'(/1A,1A/)') 'W3GRD0 ERROR -- ', &
5304  'NFD must be even and greater than zero'
5305  istat = 1
5306  IF ( PRESENT(rc) ) THEN
5307  rc = istat
5308  RETURN
5309  ELSE
5310  CALL extcde (istat)
5311  END IF
5312  END IF
5313 
5314  np = prange(2) - prange(1) + 1
5315  nq = qrange(2) - qrange(1) + 1
5316 
5317  SELECT CASE ( iclo )
5319  CONTINUE
5320  CASE DEFAULT
5321  WRITE(0,'(/1A,1A,1I2/)') 'W3GRD0 ERROR -- ', &
5322  'unsupported ICLO: ',iclo
5323  istat = 1
5324  IF ( PRESENT(rc) ) THEN
5325  rc = istat
5326  RETURN
5327  ELSE
5328  CALL extcde (istat)
5329  END IF
5330  END SELECT
5331 
5332  IF ( iclo.EQ.iclo_trpl .AND. mod(np,2).NE.0 ) THEN
5333  WRITE(0,'(/1A,1A/)') 'W3GRD0 ERROR -- ', &
5334  'tripole grid closure requires NP even'
5335  istat = 1
5336  IF ( PRESENT(rc) ) THEN
5337  rc = istat
5338  RETURN
5339  ELSE
5340  CALL extcde (istat)
5341  END IF
5342  END IF
5343  !
5344  ! -------------------------------------------------------------------- /
5345  ! 2. Setup finite difference coefficients
5346  !
5347  CALL get_fdw3 ( nfd, m, k, c )
5348  !
5349  ! -------------------------------------------------------------------- /
5350  ! 3. Compute div(V) = dV_x/dx + dV_y/dy
5351  !
5352  DO i2 = lbo(2), ubo(2)
5353  DO i1 = lbo(1), ubo(1)
5354  IF ( PRESENT(mask) ) THEN
5355  IF ( mask(i1,i2) ) cycle
5356  END IF
5357  IF ( ijg ) THEN
5358  p = i1
5359  q = i2
5360  ELSE
5361  p = i2
5362  q = i1
5363  END IF
5364  CALL dfdpq ( nfd, k, c, ijg, iclo, ptiled, qtiled, &
5365  prange, qrange, lbi, ubi, p, q, &
5366  f8=vx, dfdp=dvxdp, dfdq=dvxdq, &
5367  g8=vy, dgdp=dvydp, dgdq=dvydq, &
5368  mask=mask, rc=istat )
5369  IF ( istat .NE. 0 ) THEN
5370  IF ( PRESENT(rc) ) THEN
5371  rc = istat
5372  RETURN
5373  ELSE
5374  CALL extcde (istat)
5375  END IF
5376  END IF
5377  dvxdx = dvxdp*dpdx(i1,i2) + dvxdq*dqdx(i1,i2)
5378  dvydy = dvydp*dpdy(i1,i2) + dvydq*dqdy(i1,i2)
5379  divv(i1,i2) = dvxdx + dvydy
5380  END DO !I1
5381  END DO !I2
5382 
5383  END SUBROUTINE w3div1_r8
5384  !/
5385  !/ End of W3DIV1 ===================================================== /
5386  !/
5387 
5388 
5389 
5390 
5391 
5392 
5393 
5394 
5395  !/
5396  !/ =================================================================== /
5397  !/
5398  !/ SUBROUTINE W3DIV2( NFD, IJG, ICLO, PTILED, QTILED, &
5399  !/ PRANGE, QRANGE, LBI, UBI, LBO, UBO, &
5400  !/ DPDX, DPDY, DQDX, DQDY, &
5401  !/ SXX, SYY, SXY, DSX, DSY, MASK, RC )
5402  !/
5403  !/ =================================================================== /
5404  !/
5405  ! 1. Purpose :
5406  !
5407  ! Compute divergence of a rank 2 symmetric tensor field (S_xx,S_yy,S_xy)
5408  ! defined on a curvilinear coordinate grid (x(p,q),y(p,q)).
5409  !
5410  ! 2. Method :
5411  !
5412  ! Compute derivatives using finite-difference method.
5413  ! Apply curvilinear grid metric.
5414  !
5415  ! 3. Parameters :
5416  !
5417  ! Parameter list
5418  ! ----------------------------------------------------------------
5419  ! NFD Int. I Finite-difference order (even)
5420  ! IJG Log. I Logical flag indicating ordering of input
5421  ! coord. arrays: T = (NP,NQ) and F = (NP,NQ)
5422  ! ICLO Int. I Parameter indicating type of index space closure.
5423  ! PTILED Log. I Logical flag indicating that input arrays are tiled
5424  ! in P-axis with halos of width >= NFD/2
5425  ! QTILED Log. I Logical flag indicating that input arrays are tiled
5426  ! in Q-axis with halos of width >= NFD/2
5427  ! PRANGE I.A. I Range of P index coordinate: P in [PRANGE(1),PRANGE(2)]
5428  ! QRANGE I.A. I Range of Q index coordinate: Q in [QRANGE(1),QRANGE(2)]
5429  ! LBI I.A. I Lower-bound of input arrays, DIMENSION(2)
5430  ! UBI I.A. I Upper-bound of input arrays, DIMENSION(2)
5431  ! LBO I.A. I Lower-bound of output arrays, DIMENSION(2)
5432  ! UBO I.A. I Upper-bound of output arrays, DIMENSION(2)
5433  ! DPDX R.A. I dp/dx, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5434  ! DPDY R.A. I dp/dy, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5435  ! DQDX R.A. I dq/dx, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5436  ! DQDY R.A. I dq/dy, DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5437  ! SXX R.A. I xx-component of input tensor field,
5438  ! DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5439  ! SYY R.A. I yy-component of input vector field,
5440  ! DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5441  ! SXY R.A. I xy-component of input vector field,
5442  ! DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5443  ! DSX R.A. O div(S)_x, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
5444  ! DSY R.A. O div(S)_y, DIMENSION(LBO(1):UBO(1),LBO(2):UBO(2))
5445  ! MASK L.A. I OPTIONAL logical mask (T = invalid, F = valid)
5446  ! DIMENSION(LBI(1):UBI(1),LBI(2):UBI(2))
5447  ! RC Int. O OPTIONAL return code (!= 0 if error occurs)
5448  ! ----------------------------------------------------------------
5449  !
5450  ! 4. Subroutines used :
5451  !
5452  ! See module documentation.
5453  !
5454  ! 5. Called by :
5455  !
5456  ! 6. Error messages :
5457  !
5458  ! 7. Remarks :
5459  !
5460  ! - If RC is not provided and an error occurs, then the routine will
5461  ! report error to stderr and attempt to abort the calling program.
5462  ! - When MASK is specified, points that are masked are excluded from
5463  ! the finite-difference stencil. In order to avoid reaching across
5464  ! masked regions, the stencil is modified to one-sided and/or the
5465  ! finite-difference order is reduced. If the masking results in a
5466  ! single point wide channel, then the derivative in the direction
5467  ! across the channel is set to zero.
5468  !
5469  ! 8. Structure :
5470  !
5471  ! 9. Switches :
5472  !
5473  ! !/S Enable subroutine tracing.
5474  !
5475  ! 10. Source code :
5476  !/
5477  !/ ------------------------------------------------------------------- /
5478  !/
5479  SUBROUTINE w3div2_r4( NFD, IJG, ICLO, PTILED, QTILED, &
5480  PRANGE, QRANGE, LBI, UBI, LBO, UBO, &
5481  DPDX, DPDY, DQDX, DQDY, &
5482  SXX, SYY, SXY, DSX, DSY, MASK, RC )
5483  ! Single precision interface
5484  INTEGER, INTENT(IN) :: nfd
5485  LOGICAL, INTENT(IN) :: ijg
5486  INTEGER, INTENT(IN) :: iclo
5487  LOGICAL, INTENT(IN) :: ptiled, qtiled
5488  INTEGER, INTENT(IN) :: prange(2), qrange(2)
5489  INTEGER, INTENT(IN) :: lbi(2), ubi(2)
5490  INTEGER, INTENT(IN) :: lbo(2), ubo(2)
5491  REAL(4), INTENT(IN) :: dpdx(lbi(1):ubi(1),lbi(2):ubi(2))
5492  REAL(4), INTENT(IN) :: dpdy(lbi(1):ubi(1),lbi(2):ubi(2))
5493  REAL(4), INTENT(IN) :: dqdx(lbi(1):ubi(1),lbi(2):ubi(2))
5494  REAL(4), INTENT(IN) :: dqdy(lbi(1):ubi(1),lbi(2):ubi(2))
5495  REAL(4), INTENT(IN) :: sxx(lbi(1):ubi(1),lbi(2):ubi(2))
5496  REAL(4), INTENT(IN) :: syy(lbi(1):ubi(1),lbi(2):ubi(2))
5497  REAL(4), INTENT(IN) :: sxy(lbi(1):ubi(1),lbi(2):ubi(2))
5498  REAL(4), INTENT(OUT) :: dsx(lbo(1):ubo(1),lbo(2):ubo(2))
5499  REAL(4), INTENT(OUT) :: dsy(lbo(1):ubo(1),lbo(2):ubo(2))
5500  LOGICAL, INTENT(IN), OPTIONAL :: mask(lbi(1):ubi(1),lbi(2):ubi(2))
5501  INTEGER, INTENT(OUT), OPTIONAL :: rc
5502 
5503  ! Local parameters
5504  INTEGER, PARAMETER :: m = 1 ! order of derivative
5505  INTEGER :: np, nq, i1, i2, p, q
5506  INTEGER :: istat=0
5507  INTEGER :: k(0:nfd,0:nfd,1:nfd)
5508  REAL(8) :: c(0:nfd,0:nfd,1:nfd)
5509  REAL(8) :: dxxdp, dxxdq, dyydp, dyydq, dxydp, dxydq
5510  REAL(8) :: dxxdx, dyydy, dxydx, dxydy
5511 #ifdef W3_S
5512  INTEGER, SAVE :: ient = 0
5513  CALL strace (ient, 'W3DIV2_R4')
5514 #endif
5515  ! -------------------------------------------------------------------- /
5516  ! 1. Check and setup inputs
5517  !
5518  IF ( PRESENT(rc) ) rc = 0
5519 
5520  IF ( nfd.LE.0 .OR. mod(nfd,2).NE.0 ) THEN
5521  WRITE(0,'(/1A,1A/)') 'W3DIV2 ERROR -- ', &
5522  'NFD must be even and greater than zero'
5523  istat = 1
5524  IF ( PRESENT(rc) ) THEN
5525  rc = istat
5526  RETURN
5527  ELSE
5528  CALL extcde (istat)
5529  END IF
5530  END IF
5531 
5532  np = prange(2) - prange(1) + 1
5533  nq = qrange(2) - qrange(1) + 1
5534 
5535  SELECT CASE ( iclo )
5537  CONTINUE
5538  CASE DEFAULT
5539  WRITE(0,'(/1A,1A,1I2/)') 'W3DIV2 ERROR -- ', &
5540  'unsupported ICLO: ',iclo
5541  istat = 1
5542  IF ( PRESENT(rc) ) THEN
5543  rc = istat
5544  RETURN
5545  ELSE
5546  CALL extcde (istat)
5547  END IF
5548  END SELECT
5549 
5550  IF ( iclo.EQ.iclo_trpl .AND. mod(np,2).NE.0 ) THEN
5551  WRITE(0,'(/1A,1A/)') 'W3DIV2 ERROR -- ', &
5552  'tripole grid closure requires NP even'
5553  istat = 1
5554  IF ( PRESENT(rc) ) THEN
5555  rc = istat
5556  RETURN
5557  ELSE
5558  CALL extcde (istat)
5559  END IF
5560  END IF
5561  !
5562  ! -------------------------------------------------------------------- /
5563  ! 2. Setup finite difference coefficients
5564  !
5565  CALL get_fdw3 ( nfd, m, k, c )
5566  !
5567  ! -------------------------------------------------------------------- /
5568  ! 3. Compute div(S) = (dS_xx/dx + dS_xy/dy, dS_xy/dx + dS_yy/dy)
5569  !
5570  DO i2 = lbo(2), ubo(2)
5571  DO i1 = lbo(1), ubo(1)
5572  IF ( PRESENT(mask) ) THEN
5573  IF ( mask(i1,i2) ) cycle
5574  END IF
5575  IF ( ijg ) THEN
5576  p = i1
5577  q = i2
5578  ELSE
5579  p = i2
5580  q = i1
5581  END IF
5582  CALL dfdpq ( nfd, k, c, ijg, iclo, ptiled, qtiled, &
5583  prange, qrange, lbi, ubi, p, q, &
5584  f4=sxx, dfdp=dxxdp, dfdq=dxxdq, &
5585  g4=syy, dgdp=dyydp, dgdq=dyydq, &
5586  h4=sxy, dhdp=dxydp, dhdq=dxydq, &
5587  mask=mask, rc=istat )
5588  IF ( istat .NE. 0 ) THEN
5589  IF ( PRESENT(rc) ) THEN
5590  rc = istat
5591  RETURN
5592  ELSE
5593  CALL extcde (istat)
5594  END IF
5595  END IF
5596  dxxdx = dxxdp*dpdx(i1,i2) + dxxdq*dqdx(i1,i2)
5597  dyydy = dyydp*dpdy(i1,i2) + dyydq*dqdy(i1,i2)
5598  dxydx = dxydp*dpdx(i1,i2) + dxydq*dqdx(i1,i2)
5599  dxydy = dxydp*dpdy(i1,i2) + dxydq*dqdy(i1,i2)
5600  dsx(i1,i2) = dxxdx + dxydy
5601  dsy(i1,i2) = dxydx + dyydy
5602  END DO !I1
5603  END DO !I2
5604 
5605  END SUBROUTINE w3div2_r4
5606  !/
5607  !/ ------------------------------------------------------------------- /
5608  !/
5609  SUBROUTINE w3div2_r8( NFD, IJG, ICLO, PTILED, QTILED, &
5610  PRANGE, QRANGE, LBI, UBI, LBO, UBO, &
5611  DPDX, DPDY, DQDX, DQDY, &
5612  SXX, SYY, SXY, DSX, DSY, MASK, RC )
5613  ! Double precision interface
5614  INTEGER, INTENT(IN) :: nfd
5615  LOGICAL, INTENT(IN) :: ijg
5616  INTEGER, INTENT(IN) :: iclo
5617  LOGICAL, INTENT(IN) :: ptiled, qtiled
5618  INTEGER, INTENT(IN) :: prange(2), qrange(2)
5619  INTEGER, INTENT(IN) :: lbi(2), ubi(2)
5620  INTEGER, INTENT(IN) :: lbo(2), ubo(2)
5621  REAL(8), INTENT(IN) :: dpdx(lbi(1):ubi(1),lbi(2):ubi(2))
5622  REAL(8), INTENT(IN) :: dpdy(lbi(1):ubi(1),lbi(2):ubi(2))
5623  REAL(8), INTENT(IN) :: dqdx(lbi(1):ubi(1),lbi(2):ubi(2))
5624  REAL(8), INTENT(IN) :: dqdy(lbi(1):ubi(1),lbi(2):ubi(2))
5625  REAL(8), INTENT(IN) :: sxx(lbi(1):ubi(1),lbi(2):ubi(2))
5626  REAL(8), INTENT(IN) :: syy(lbi(1):ubi(1),lbi(2):ubi(2))
5627  REAL(8), INTENT(IN) :: sxy(lbi(1):ubi(1),lbi(2):ubi(2))
5628  REAL(8), INTENT(OUT) :: dsx(lbo(1):ubo(1),lbo(2):ubo(2))
5629  REAL(8), INTENT(OUT) :: dsy(lbo(1):ubo(1),lbo(2):ubo(2))
5630  LOGICAL, INTENT(IN), OPTIONAL :: mask(lbi(1):ubi(1),lbi(2):ubi(2))
5631  INTEGER, INTENT(OUT), OPTIONAL :: rc
5632 
5633  ! Local parameters
5634  INTEGER, PARAMETER :: m = 1 ! order of derivative
5635  INTEGER :: np, nq, i1, i2, p, q
5636  INTEGER :: istat=0
5637  INTEGER :: k(0:nfd,0:nfd,1:nfd)
5638  REAL(8) :: c(0:nfd,0:nfd,1:nfd)
5639  REAL(8) :: dxxdp, dxxdq, dyydp, dyydq, dxydp, dxydq
5640  REAL(8) :: dxxdx, dyydy, dxydx, dxydy
5641 #ifdef W3_S
5642  INTEGER, SAVE :: ient = 0
5643  CALL strace (ient, 'W3DIV2_R8')
5644 #endif
5645  ! -------------------------------------------------------------------- /
5646  ! 1. Check and setup inputs
5647  !
5648  IF ( PRESENT(rc) ) rc = 0
5649 
5650  IF ( nfd.LE.0 .OR. mod(nfd,2).NE.0 ) THEN
5651  WRITE(0,'(/1A,1A/)') 'W3DIV2 ERROR -- ', &
5652  'NFD must be even and greater than zero'
5653  istat = 1
5654  IF ( PRESENT(rc) ) THEN
5655  rc = istat
5656  RETURN
5657  ELSE
5658  CALL extcde (istat)
5659  END IF
5660  END IF
5661 
5662  np = prange(2) - prange(1) + 1
5663  nq = qrange(2) - qrange(1) + 1
5664 
5665  SELECT CASE ( iclo )
5667  CONTINUE
5668  CASE DEFAULT
5669  WRITE(0,'(/1A,1A,1I2/)') 'W3DIV2 ERROR -- ', &
5670  'unsupported ICLO: ',iclo
5671  istat = 1
5672  IF ( PRESENT(rc) ) THEN
5673  rc = istat
5674  RETURN
5675  ELSE
5676  CALL extcde (istat)
5677  END IF
5678  END SELECT
5679 
5680  IF ( iclo.EQ.iclo_trpl .AND. mod(np,2).NE.0 ) THEN
5681  WRITE(0,'(/1A,1A/)') 'W3DIV2 ERROR -- ', &
5682  'tripole grid closure requires NP even'
5683  istat = 1
5684  IF ( PRESENT(rc) ) THEN
5685  rc = istat
5686  RETURN
5687  ELSE
5688  CALL extcde (istat)
5689  END IF
5690  END IF
5691  !
5692  ! -------------------------------------------------------------------- /
5693  ! 2. Setup finite difference coefficients
5694  !
5695  CALL get_fdw3 ( nfd, m, k, c )
5696  !
5697  ! -------------------------------------------------------------------- /
5698  ! 3. Compute div(S) = (dS_xx/dx + dS_xy/dy, dS_xy/dx + dS_yy/dy)
5699  !
5700  DO i2 = lbo(2), ubo(2)
5701  DO i1 = lbo(1), ubo(1)
5702  IF ( PRESENT(mask) ) THEN
5703  IF ( mask(i1,i2) ) cycle
5704  END IF
5705  IF ( ijg ) THEN
5706  p = i1
5707  q = i2
5708  ELSE
5709  p = i2
5710  q = i1
5711  END IF
5712  CALL dfdpq ( nfd, k, c, ijg, iclo, ptiled, qtiled, &
5713  prange, qrange, lbi, ubi, p, q, &
5714  f8=sxx, dfdp=dxxdp, dfdq=dxxdq, &
5715  g8=syy, dgdp=dyydp, dgdq=dyydq, &
5716  h8=sxy, dhdp=dxydp, dhdq=dxydq, &
5717  mask=mask, rc=istat )
5718  IF ( istat .NE. 0 ) THEN
5719  IF ( PRESENT(rc) ) THEN
5720  rc = istat
5721  RETURN
5722  ELSE
5723  CALL extcde (istat)
5724  END IF
5725  END IF
5726  dxxdx = dxxdp*dpdx(i1,i2) + dxxdq*dqdx(i1,i2)
5727  dyydy = dyydp*dpdy(i1,i2) + dyydq*dqdy(i1,i2)
5728  dxydx = dxydp*dpdx(i1,i2) + dxydq*dqdx(i1,i2)
5729  dxydy = dxydp*dpdy(i1,i2) + dxydq*dqdy(i1,i2)
5730  dsx(i1,i2) = dxxdx + dxydy
5731  dsy(i1,i2) = dxydx + dyydy
5732  END DO !I1
5733  END DO !I2
5734 
5735  END SUBROUTINE w3div2_r8
5736  !/
5737  !/ End of W3DIV2 ===================================================== /
5738  !/
5739 
5740 
5741 
5742 
5743 
5744 
5745 
5746 
5747  !/
5748  !/ =================================================================== /
5749  !/
5750  !/ FUNCTION W3DIST( LLG, XT, YT, XS, YS ) RESULT(DIST)
5751  !/
5752  !/ =================================================================== /
5753  !/
5754  ! 1. Purpose :
5755  !
5756  ! Compute distance between two points. If spherical grid, then
5757  ! distance is the angle (in degrees) between the two points.
5758  !
5759  ! 2. Method :
5760  !
5761  ! Map Projections -- A Working Manual, John P. Snyder
5762  ! U.S. Geological Survey professional paper; 1395
5763  ! Chapter 5. Transformation of Map Graticules
5764  !
5765  ! 3. Parameters :
5766  !
5767  ! Return parameter
5768  ! ----------------------------------------------------------------
5769  ! DIST Real O Distance
5770  ! ----------------------------------------------------------------
5771  !
5772  ! Parameter list
5773  ! ----------------------------------------------------------------
5774  ! LLG Log. I Logical flag indicating the coordinate system:
5775  ! T = spherical lat/lon (degrees) and F = Cartesian.
5776  ! XT Real I X-coordinate of target point.
5777  ! YT Real I Y-coordinate of target point.
5778  ! XS Real I X-coordinate of source point.
5779  ! YS Real I Y-coordinate of source point.
5780  ! ----------------------------------------------------------------
5781  !
5782  ! 4. Subroutines used :
5783  !
5784  ! See module documentation.
5785  !
5786  ! 5. Called by :
5787  !
5788  ! 6. Error messages :
5789  !
5790  ! 7. Remarks :
5791  !
5792  ! 8. Structure :
5793  !
5794  ! 9. Switches :
5795  !
5796  ! !/S Enable subroutine tracing.
5797  !
5798  ! 10. Source code :
5799  !/
5800  !/ ------------------------------------------------------------------- /
5801  !/
5802  FUNCTION w3dist_r4( LLG, XT, YT, XS, YS ) RESULT(DIST)
5803  ! Single precision interface
5804  REAL(4) :: dist
5805  LOGICAL, INTENT(IN) :: llg
5806  REAL(4), INTENT(IN) :: xt, yt
5807  REAL(4), INTENT(IN) :: xs, ys
5808 
5809  ! Local parameters
5810  REAL(8) :: xt8, yt8, xs8, ys8
5811 #ifdef W3_S
5812  INTEGER, SAVE :: ient = 0
5813  CALL strace (ient, 'W3DIST_R4')
5814 #endif
5815  !
5816  !-----set inputs
5817  xt8 = xt; yt8 = yt;
5818  xs8 = xs; ys8 = ys;
5819  !
5820  !-----call double precision method
5821  dist = w3dist( llg, xt8, yt8, xs8, ys8 )
5822 
5823  END FUNCTION w3dist_r4
5824  !/
5825  !/ ------------------------------------------------------------------- /
5826  !/
5827 #define DIST_WITH_SINE
5828 #define DIST_CHECK_NAN____disabled
5829  FUNCTION w3dist_r8( LLG, XT, YT, XS, YS ) RESULT(DIST)
5830  ! Double precision interface
5831  REAL(8) :: dist
5832  LOGICAL, INTENT(IN) :: llg
5833  REAL(8), INTENT(IN) :: xt, yt
5834  REAL(8), INTENT(IN) :: xs, ys
5835 
5836  ! Local parameters
5837  REAL(8) :: dx, dy, slam, sphi, argd
5838 #ifdef W3_S
5839  INTEGER, SAVE :: ient = 0
5840  CALL strace (ient, 'W3DIST_R8')
5841 #endif
5842  !
5843  !-----compute displacements
5844  dx = xt - xs
5845  dy = yt - ys
5846 
5847  IF ( llg ) THEN !spherical coordinates
5848  !---------check for longitudinal branch cut crossing
5849  IF ( abs(dx) .GT. d270 ) THEN
5850  dx = dx - sign(d360,dx)
5851  END IF
5852 #ifdef DIST_WITH_SINE
5853  !---------compute angular distance using sin(d/2)
5854  ! (this equation is more accurate than cos(d))
5855  slam = sin(half*dx*d2r)
5856  sphi = sin(half*dy*d2r)
5857  argd = sqrt( cos(yt*d2r)*cos(ys*d2r)*slam*slam + sphi*sphi )
5858  dist = r2d*two*asin( argd )
5859 #else
5860  !---------compute angular distance using cos(c) (min required
5861  ! for rare situation of acos(1+small) generating NaN)
5862  argd = min( one, cos(yt*d2r)*cos(ys*d2r)*cos(dx*d2r) &
5863  + sin(yt*d2r)*sin(ys*d2r) )
5864  dist = r2d*acos( argd )
5865 #endif
5866  ELSE !cartesian coordinates
5867  !---------compute cartesian distance
5868  dist = sqrt( dx**2 + dy**2 )
5869  END IF !cartesian coordinates
5870 #ifdef DIST_CHECK_NAN
5871  IF ( w3inan(dist) ) THEN
5872  WRITE(0,'(/1A/)') 'W3DIST_R8 ERROR -- result is NaN'
5873  CALL extcde (1)
5874  END IF
5875 #endif
5876 
5877  END FUNCTION w3dist_r8
5878  !/
5879  !/ End of W3DIST ===================================================== /
5880  !/
5881 
5882 
5883 
5884 
5885 
5886 
5887 
5888 
5889  !/
5890  !/ =================================================================== /
5891  !/
5892  !/ SUBROUTINE W3SPLX( LAM0, PHI0, C0, LAM, PHI, X, Y )
5893  !/
5894  !/ =================================================================== /
5895  !/
5896  ! 1. Purpose :
5897  !
5898  ! Compute Cartesian coordinates from input longitude and latitude
5899  ! using stereographic projection with center at (LAM0,PHI0) and
5900  ! "standard circle" of angular distance C0 (in degrees) from the
5901  ! center.
5902  !
5903  ! 2. Method :
5904  !
5905  ! Map Projections -- A Working Manual, John P. Snyder
5906  ! U.S. Geological Survey professional paper; 1395
5907  ! Chapter 21. Stereographic projection
5908  !
5909  ! 3. Parameters :
5910  !
5911  ! Parameter list
5912  ! ----------------------------------------------------------------
5913  ! LAM0 Real I Longitude of center of projection.
5914  ! PHI0 Real I Latitude of center of projection.
5915  ! C0 Real I Angular distance from center of projection
5916  ! where the scale factor is one.
5917  ! LAM Real I Longitude of input point.
5918  ! PHI Real I Latitude of input point.
5919  ! X Real O Cartesian x-coordinate of input point.
5920  ! Y Real O Cartesian y-coordinate of input point.
5921  ! ----------------------------------------------------------------
5922  !
5923  ! 4. Subroutines used :
5924  !
5925  ! See module documentation.
5926  !
5927  ! 5. Called by :
5928  !
5929  ! 6. Error messages :
5930  !
5931  ! 7. Remarks :
5932  !
5933  ! 8. Structure :
5934  !
5935  ! 9. Switches :
5936  !
5937  ! !/S Enable subroutine tracing.
5938  !
5939  ! 10. Source code :
5940  !/
5941  !/ ------------------------------------------------------------------- /
5942  !/
5943  SUBROUTINE w3splx_0d_r4( LAM0, PHI0, C0, LAM, PHI, X, Y )
5944  ! Single precision point interface
5945  REAL(4), INTENT(IN) :: lam0, phi0, c0
5946  REAL(4), INTENT(IN) :: lam, phi
5947  REAL(4), INTENT(OUT):: x, y
5948 
5949  ! Local parameters
5950  REAL(8) :: k, k0, clam, slam, cphi0, cphi, sphi0, sphi
5951 #ifdef W3_S
5952  INTEGER, SAVE :: ient = 0
5953  CALL strace (ient, 'W3SPLX_0D_R4')
5954 #endif
5955 
5956  clam = cos((lam-lam0)*d2r)
5957  slam = sin((lam-lam0)*d2r)
5958  cphi0 = cos(phi0*d2r)
5959  cphi = cos(phi*d2r)
5960  sphi0 = sin(phi0*d2r)
5961  sphi = sin(phi*d2r)
5962  k0 = cos(half*c0*d2r)**2
5963  k = two*k0*rearth/(one+sphi0*sphi+cphi0*cphi*clam)
5964  x = k*cphi*slam
5965  y = k*(cphi0*sphi-sphi0*cphi*clam)
5966 
5967  END SUBROUTINE w3splx_0d_r4
5968  !/
5969  !/ ------------------------------------------------------------------- /
5970  !/
5971  SUBROUTINE w3splx_0d_r8( LAM0, PHI0, C0, LAM, PHI, X, Y )
5972  ! Double precision point interface
5973  REAL(8), INTENT(IN) :: lam0, phi0, c0
5974  REAL(8), INTENT(IN) :: lam, phi
5975  REAL(8), INTENT(OUT):: x, y
5976 
5977  ! Local parameters
5978  REAL(8) :: k, k0, clam, slam, cphi0, cphi, sphi0, sphi
5979 #ifdef W3_S
5980  INTEGER, SAVE :: ient = 0
5981  CALL strace (ient, 'W3SPLX_0D_R8')
5982 #endif
5983 
5984  clam = cos((lam-lam0)*d2r)
5985  slam = sin((lam-lam0)*d2r)
5986  cphi0 = cos(phi0*d2r)
5987  cphi = cos(phi*d2r)
5988  sphi0 = sin(phi0*d2r)
5989  sphi = sin(phi*d2r)
5990  k0 = cos(half*c0*d2r)**2
5991  k = two*k0*rearth/(one+sphi0*sphi+cphi0*cphi*clam)
5992  x = k*cphi*slam
5993  y = k*(cphi0*sphi-sphi0*cphi*clam)
5994 
5995  END SUBROUTINE w3splx_0d_r8
5996  !/
5997  !/ ------------------------------------------------------------------- /
5998  !/
5999  SUBROUTINE w3splx_1d_r4( LAM0, PHI0, C0, LAM, PHI, X, Y )
6000  ! Single precision 1D array interface
6001  REAL(4), INTENT(IN) :: lam0, phi0, c0
6002  REAL(4), INTENT(IN) :: lam(:), phi(:)
6003  REAL(4), INTENT(OUT):: x(:), y(:)
6004 
6005  ! Local parameters
6006  INTEGER :: i
6007 #ifdef W3_S
6008  INTEGER, SAVE :: ient = 0
6009  CALL strace (ient, 'W3SPLX_1D_R4')
6010 #endif
6011 
6012  DO i = lbound(lam,1),ubound(lam,1)
6013  CALL w3splx( lam0, phi0, c0, lam(i), phi(i), x(i), y(i) )
6014  ENDDO
6015 
6016  END SUBROUTINE w3splx_1d_r4
6017  !/
6018  !/ ------------------------------------------------------------------- /
6019  !/
6020  SUBROUTINE w3splx_1d_r8( LAM0, PHI0, C0, LAM, PHI, X, Y )
6021  ! Double precision 1D array interface
6022  REAL(8), INTENT(IN) :: lam0, phi0, c0
6023  REAL(8), INTENT(IN) :: lam(:), phi(:)
6024  REAL(8), INTENT(OUT):: x(:), y(:)
6025 
6026  ! Local parameters
6027  INTEGER :: i
6028 #ifdef W3_S
6029  INTEGER, SAVE :: ient = 0
6030  CALL strace (ient, 'W3SPLX_1D_R8')
6031 #endif
6032 
6033  DO i = lbound(lam,1),ubound(lam,1)
6034  CALL w3splx( lam0, phi0, c0, lam(i), phi(i), x(i), y(i) )
6035  ENDDO
6036 
6037  END SUBROUTINE w3splx_1d_r8
6038  !/
6039  !/ ------------------------------------------------------------------- /
6040  !/
6041  SUBROUTINE w3splx_2d_r4( LAM0, PHI0, C0, LAM, PHI, X, Y )
6042  ! Single precision 2D array interface
6043  REAL(4), INTENT(IN) :: lam0, phi0, c0
6044  REAL(4), INTENT(IN) :: lam(:,:), phi(:,:)
6045  REAL(4), INTENT(OUT):: x(:,:), y(:,:)
6046 
6047  ! Local parameters
6048  INTEGER :: i, j
6049 #ifdef W3_S
6050  INTEGER, SAVE :: ient = 0
6051  CALL strace (ient, 'W3SPLX_2D_R4')
6052 #endif
6053 
6054  DO j = lbound(lam,2),ubound(lam,2)
6055  DO i = lbound(lam,1),ubound(lam,1)
6056  CALL w3splx( lam0, phi0, c0, lam(i,j), phi(i,j), x(i,j), y(i,j) )
6057  ENDDO
6058  ENDDO
6059 
6060  END SUBROUTINE w3splx_2d_r4
6061  !/
6062  !/ ------------------------------------------------------------------- /
6063  !/
6064  SUBROUTINE w3splx_2d_r8( LAM0, PHI0, C0, LAM, PHI, X, Y )
6065  ! Double precision 2D array interface
6066  REAL(8), INTENT(IN) :: lam0, phi0, c0
6067  REAL(8), INTENT(IN) :: lam(:,:), phi(:,:)
6068  REAL(8), INTENT(OUT):: x(:,:), y(:,:)
6069 
6070  ! Local parameters
6071  INTEGER :: i, j
6072 #ifdef W3_S
6073  INTEGER, SAVE :: ient = 0
6074  CALL strace (ient, 'W3SPLX_2D_R8')
6075 #endif
6076 
6077  DO j = lbound(lam,2),ubound(lam,2)
6078  DO i = lbound(lam,1),ubound(lam,1)
6079  CALL w3splx( lam0, phi0, c0, lam(i,j), phi(i,j), x(i,j), y(i,j) )
6080  ENDDO
6081  ENDDO
6082 
6083  END SUBROUTINE w3splx_2d_r8
6084  !/
6085  !/ End of W3SPLX ===================================================== /
6086  !/
6087 
6088 
6089 
6090 
6091 
6092 
6093 
6094 
6095  !/
6096  !/ =================================================================== /
6097  !/
6098  !/ SUBROUTINE W3SPXL( LAM0, PHI0, X, Y, LAM, PHI )
6099  !/
6100  !/ =================================================================== /
6101  !/
6102  ! 1. Purpose :
6103  !
6104  ! Compute longitude and latitude coordinates from input Cartesian
6105  ! coordinates using stereographic projection with center at (LAM0,PHI0)
6106  ! and "standard circle" of angular distance C0 (in degrees) from the
6107  ! center.
6108  !
6109  ! 2. Method :
6110  !
6111  ! Map Projections -- A Working Manual, John P. Snyder
6112  ! U.S. Geological Survey professional paper; 1395
6113  ! Chapter 21. Stereographic projection
6114  !
6115  ! 3. Parameters :
6116  !
6117  ! Parameter list
6118  ! ----------------------------------------------------------------
6119  ! LAM0 Real I Longitude of center of projection.
6120  ! PHI0 Real I Latitude of center of projection.
6121  ! C0 Real I Angular distance from center of projection
6122  ! where the scale factor is one.
6123  ! X Real I Cartesian x-coordinate of input point.
6124  ! Y Real I Cartesian y-coordinate of input point.
6125  ! LAM Real O Longitude of input point.
6126  ! PHI Real O Latitude of input point.
6127  ! ----------------------------------------------------------------
6128  !
6129  ! 4. Subroutines used :
6130  !
6131  ! See module documentation.
6132  !
6133  ! 5. Called by :
6134  !
6135  ! 6. Error messages :
6136  !
6137  ! 7. Remarks :
6138  !
6139  ! 8. Structure :
6140  !
6141  ! 9. Switches :
6142  !
6143  ! !/S Enable subroutine tracing.
6144  !
6145  ! 10. Source code :
6146  !/
6147  !/ ------------------------------------------------------------------- /
6148  !/
6149  SUBROUTINE w3spxl_0d_r4( LAM0, PHI0, C0, X, Y, LAM, PHI )
6150  ! Single precision point interface
6151  REAL(4), INTENT(IN) :: lam0, phi0, c0
6152  REAL(4), INTENT(IN) :: x, y
6153  REAL(4), INTENT(OUT):: lam, phi
6154 
6155  ! Local parameters
6156  REAL(8) :: k0, rho, c, cosc, sinc, cphi0, sphi0
6157 #ifdef W3_S
6158  INTEGER, SAVE :: ient = 0
6159  CALL strace (ient, 'W3SPXL_0D_R4')
6160 #endif
6161 
6162  k0 = cos(half*c0*d2r)**2
6163  rho = sqrt(x*x+y*y)
6164  c = two*atan2(rho,two*rearth*k0)
6165  cosc = cos(c)
6166  sinc = sin(c)
6167  cphi0 = cos(phi0*d2r)
6168  sphi0 = sin(phi0*d2r)
6169  phi = asin(cosc*sphi0+y*sinc*cphi0/rho)*r2d
6170  lam = lam0 + atan2(x*sinc,rho*cphi0*cosc-y*sphi0*sinc)*r2d
6171 
6172  END SUBROUTINE w3spxl_0d_r4
6173  !/
6174  !/ ------------------------------------------------------------------- /
6175  !/
6176  SUBROUTINE w3spxl_0d_r8( LAM0, PHI0, C0, X, Y, LAM, PHI )
6177  ! Double precision point interface
6178  REAL(8), INTENT(IN) :: lam0, phi0, c0
6179  REAL(8), INTENT(IN) :: x, y
6180  REAL(8), INTENT(OUT):: lam, phi
6181 
6182  ! Local parameters
6183  REAL(8) :: k0, rho, c, cosc, sinc, cphi0, sphi0
6184 #ifdef W3_S
6185  INTEGER, SAVE :: ient = 0
6186  CALL strace (ient, 'W3SPXL_0D_R8')
6187 #endif
6188 
6189  k0 = cos(half*c0*d2r)**2
6190  rho = sqrt(x*x+y*y)
6191  c = two*atan2(rho,two*rearth*k0)
6192  cosc = cos(c)
6193  sinc = sin(c)
6194  cphi0 = cos(phi0*d2r)
6195  sphi0 = sin(phi0*d2r)
6196  phi = asin(cosc*sphi0+y*sinc*cphi0/rho)*r2d
6197  lam = lam0 + atan2(x*sinc,rho*cphi0*cosc-y*sphi0*sinc)*r2d
6198 
6199  END SUBROUTINE w3spxl_0d_r8
6200  !/
6201  !/ ------------------------------------------------------------------- /
6202  !/
6203  SUBROUTINE w3spxl_1d_r4( LAM0, PHI0, C0, X, Y, LAM, PHI )
6204  ! Single precision 1D array interface
6205  REAL(4), INTENT(IN) :: lam0, phi0, c0
6206  REAL(4), INTENT(IN) :: x(:), y(:)
6207  REAL(4), INTENT(OUT):: lam(:), phi(:)
6208 
6209  ! Local parameters
6210  INTEGER :: i
6211 #ifdef W3_S
6212  INTEGER, SAVE :: ient = 0
6213  CALL strace (ient, 'W3SPXL_1D_R4')
6214 #endif
6215 
6216  DO i = lbound(x,1),ubound(x,1)
6217  CALL w3spxl( lam0, phi0, c0, x(i), y(i), lam(i), phi(i) )
6218  ENDDO
6219 
6220  END SUBROUTINE w3spxl_1d_r4
6221  !/
6222  !/ ------------------------------------------------------------------- /
6223  !/
6224  SUBROUTINE w3spxl_1d_r8( LAM0, PHI0, C0, X, Y, LAM, PHI )
6225  ! Double precision 1D array interface
6226  REAL(8), INTENT(IN) :: lam0, phi0, c0
6227  REAL(8), INTENT(IN) :: x(:), y(:)
6228  REAL(8), INTENT(OUT):: lam(:), phi(:)
6229 
6230  ! Local parameters
6231  INTEGER :: i
6232 #ifdef W3_S
6233  INTEGER, SAVE :: ient = 0
6234  CALL strace (ient, 'W3SPXL_1D_R8')
6235 #endif
6236 
6237  DO i = lbound(x,1),ubound(x,1)
6238  CALL w3spxl( lam0, phi0, c0, x(i), y(i), lam(i), phi(i) )
6239  ENDDO
6240 
6241  END SUBROUTINE w3spxl_1d_r8
6242  !/
6243  !/ ------------------------------------------------------------------- /
6244  !/
6245  SUBROUTINE w3spxl_2d_r4( LAM0, PHI0, C0, X, Y, LAM, PHI )
6246  ! Single precision 2D array interface
6247  REAL(4), INTENT(IN) :: lam0, phi0, c0
6248  REAL(4), INTENT(IN) :: x(:,:), y(:,:)
6249  REAL(4), INTENT(OUT):: lam(:,:), phi(:,:)
6250 
6251  ! Local parameters
6252  INTEGER :: i, j
6253 #ifdef W3_S
6254  INTEGER, SAVE :: ient = 0
6255  CALL strace (ient, 'W3SPXL_2D_R4')
6256 #endif
6257 
6258  DO j = lbound(x,2),ubound(x,2)
6259  DO i = lbound(x,1),ubound(x,1)
6260  CALL w3spxl( lam0, phi0, c0, x(i,j), y(i,j), lam(i,j), phi(i,j) )
6261  ENDDO
6262  ENDDO
6263 
6264  END SUBROUTINE w3spxl_2d_r4
6265  !/
6266  !/ ------------------------------------------------------------------- /
6267  !/
6268  SUBROUTINE w3spxl_2d_r8( LAM0, PHI0, C0, X, Y, LAM, PHI )
6269  ! Double precision 2D array interface
6270  REAL(8), INTENT(IN) :: lam0, phi0, c0
6271  REAL(8), INTENT(IN) :: x(:,:), y(:,:)
6272  REAL(8), INTENT(OUT):: lam(:,:), phi(:,:)
6273 
6274  ! Local parameters
6275  INTEGER :: i, j
6276 #ifdef W3_S
6277  INTEGER, SAVE :: ient = 0
6278  CALL strace (ient, 'W3SPXL_2D_R8')
6279 #endif
6280 
6281  DO j = lbound(x,2),ubound(x,2)
6282  DO i = lbound(x,1),ubound(x,1)
6283  CALL w3spxl( lam0, phi0, c0, x(i,j), y(i,j), lam(i,j), phi(i,j) )
6284  ENDDO
6285  ENDDO
6286 
6287  END SUBROUTINE w3spxl_2d_r8
6288  !/
6289  !/ End of W3SPXL ===================================================== /
6290  !/
6291 
6292 
6293 
6294 
6295 
6296 
6297 
6298 
6299  !/
6300  !/ =================================================================== /
6301  !/
6302  !/ SUBROUTINE W3TRLL( LAM0, PHI0, LAM1, PHI1, LAM, PHI )
6303  !/
6304  !/ =================================================================== /
6305  !/
6306  ! 1. Purpose :
6307  !
6308  ! Compute longitude and latitude for input coordinates in a
6309  ! coordinate system with the North Pole placed at a latitude
6310  ! PHI0 on a meridian LAM0 east of the central meridian.
6311  !
6312  ! 2. Method :
6313  !
6314  ! Map Projections -- A Working Manual, John P. Snyder
6315  ! U.S. Geological Survey professional paper; 1395
6316  ! Chapter 5. Transformation of Map Graticules
6317  !
6318  ! 3. Parameters :
6319  !
6320  ! Parameter list
6321  ! ----------------------------------------------------------------
6322  ! LAM0 Real I Longitude of North Pole
6323  ! PHI0 Real I Latitude of North Pole
6324  ! LAM1 Real I Input Longitude
6325  ! PHI1 Real I Input Latitude
6326  ! LAM Real O Transformed Longitude
6327  ! PHI Real O Transformed Latitude
6328  ! ----------------------------------------------------------------
6329  !
6330  ! 4. Subroutines used :
6331  !
6332  ! See module documentation.
6333  !
6334  ! 5. Called by :
6335  !
6336  ! 6. Error messages :
6337  !
6338  ! 7. Remarks :
6339  !
6340  ! 8. Structure :
6341  !
6342  ! 9. Switches :
6343  !
6344  ! !/S Enable subroutine tracing.
6345  !
6346  ! 10. Source code :
6347  !/
6348  !/ ------------------------------------------------------------------- /
6349  !/
6350  SUBROUTINE w3trll_0d_r4( LAM0, PHI0, LAM1, PHI1, LAM, PHI )
6351  ! Single precision point interface
6352  REAL(4), INTENT(IN) :: lam0, phi0
6353  REAL(4), INTENT(IN) :: lam1, phi1
6354  REAL(4), INTENT(OUT):: lam, phi
6355 
6356  ! Local parameters
6357  REAL(8) :: clam, slam, calp, salp, cphi, sphi
6358 #ifdef W3_S
6359  INTEGER, SAVE :: ient = 0
6360  CALL strace (ient, 'W3TRLL_0D_R4')
6361 #endif
6362 
6363  clam = cos((lam1-lam0)*d2r)
6364  slam = sin((lam1-lam0)*d2r)
6365  calp = cos(phi0*d2r)
6366  salp = sin(phi0*d2r)
6367  cphi = cos(phi1*d2r)
6368  sphi = sin(phi1*d2r)
6369  lam = lam0 + atan2(cphi*slam,salp*cphi*clam+calp*sphi)*r2d
6370  phi = asin(salp*sphi-calp*cphi*clam)*r2d
6371 
6372  END SUBROUTINE w3trll_0d_r4
6373  !/
6374  !/ ------------------------------------------------------------------- /
6375  !/
6376  SUBROUTINE w3trll_0d_r8( LAM0, PHI0, LAM1, PHI1, LAM, PHI )
6377  ! Double precision point interface
6378  REAL(8), INTENT(IN) :: lam0, phi0
6379  REAL(8), INTENT(IN) :: lam1, phi1
6380  REAL(8), INTENT(OUT):: lam, phi
6381 
6382  ! Local parameters
6383  REAL(8) :: clam, slam, calp, salp, cphi, sphi
6384 #ifdef W3_S
6385  INTEGER, SAVE :: ient = 0
6386  CALL strace (ient, 'W3TRLL_0D_R8')
6387 #endif
6388 
6389  clam = cos((lam1-lam0)*d2r)
6390  slam = sin((lam1-lam0)*d2r)
6391  calp = cos(phi0*d2r)
6392  salp = sin(phi0*d2r)
6393  cphi = cos(phi1*d2r)
6394  sphi = sin(phi1*d2r)
6395  lam = lam0 + atan2(cphi*slam,salp*cphi*clam+calp*sphi)*r2d
6396  phi = asin(salp*sphi-calp*cphi*clam)*r2d
6397 
6398  END SUBROUTINE w3trll_0d_r8
6399  !/
6400  !/ ------------------------------------------------------------------- /
6401  !/
6402  SUBROUTINE w3trll_1d_r4( LAM0, PHI0, LAM1, PHI1, LAM, PHI )
6403  ! Single precision 1D array interface
6404  REAL(4), INTENT(IN) :: lam0, phi0
6405  REAL(4), INTENT(IN) :: lam1(:), phi1(:)
6406  REAL(4), INTENT(OUT):: lam(:), phi(:)
6407 
6408  ! Local parameters
6409  INTEGER :: i
6410 #ifdef W3_S
6411  INTEGER, SAVE :: ient = 0
6412  CALL strace (ient, 'W3TRLL_1D_R4')
6413 #endif
6414 
6415  DO i = lbound(lam1,1),ubound(lam1,1)
6416  CALL w3trll( lam0, phi0, lam1(i), phi1(i), lam(i), phi(i) )
6417  ENDDO
6418 
6419  END SUBROUTINE w3trll_1d_r4
6420  !/
6421  !/ ------------------------------------------------------------------- /
6422  !/
6423  SUBROUTINE w3trll_1d_r8( LAM0, PHI0, LAM1, PHI1, LAM, PHI )
6424  ! Double precision 1D array interface
6425  REAL(8), INTENT(IN) :: lam0, phi0
6426  REAL(8), INTENT(IN) :: lam1(:), phi1(:)
6427  REAL(8), INTENT(OUT):: lam(:), phi(:)
6428 
6429  ! Local parameters
6430  INTEGER :: i
6431 #ifdef W3_S
6432  INTEGER, SAVE :: ient = 0
6433  CALL strace (ient, 'W3TRLL_1D_R8')
6434 #endif
6435 
6436  DO i = lbound(lam1,1),ubound(lam1,1)
6437  CALL w3trll( lam0, phi0, lam1(i), phi1(i), lam(i), phi(i) )
6438  ENDDO
6439 
6440  END SUBROUTINE w3trll_1d_r8
6441  !/
6442  !/ ------------------------------------------------------------------- /
6443  !/
6444  SUBROUTINE w3trll_2d_r4( LAM0, PHI0, LAM1, PHI1, LAM, PHI )
6445  ! Single precision 2D array interface
6446  REAL(4), INTENT(IN) :: lam0, phi0
6447  REAL(4), INTENT(IN) :: lam1(:,:), phi1(:,:)
6448  REAL(4), INTENT(OUT):: lam(:,:), phi(:,:)
6449 
6450  ! Local parameters
6451  INTEGER :: i, j
6452 #ifdef W3_S
6453  INTEGER, SAVE :: ient = 0
6454  CALL strace (ient, 'W3TRLL_2D_R4')
6455 #endif
6456 
6457  DO j = lbound(lam1,2),ubound(lam1,2)
6458  DO i = lbound(lam1,1),ubound(lam1,1)
6459  CALL w3trll( lam0, phi0, lam1(i,j), phi1(i,j), lam(i,j), phi(i,j) )
6460  ENDDO
6461  ENDDO
6462 
6463  END SUBROUTINE w3trll_2d_r4
6464  !/
6465  !/ ------------------------------------------------------------------- /
6466  !/
6467  SUBROUTINE w3trll_2d_r8( LAM0, PHI0, LAM1, PHI1, LAM, PHI )
6468  ! Double precision 2D array interface
6469  REAL(8), INTENT(IN) :: lam0, phi0
6470  REAL(8), INTENT(IN) :: lam1(:,:), phi1(:,:)
6471  REAL(8), INTENT(OUT):: lam(:,:), phi(:,:)
6472 
6473  ! Local parameters
6474  INTEGER :: i, j
6475 #ifdef W3_S
6476  INTEGER, SAVE :: ient = 0
6477  CALL strace (ient, 'W3TRLL_2D_R8')
6478 #endif
6479 
6480  DO j = lbound(lam1,2),ubound(lam1,2)
6481  DO i = lbound(lam1,1),ubound(lam1,1)
6482  CALL w3trll( lam0, phi0, lam1(i,j), phi1(i,j), lam(i,j), phi(i,j) )
6483  ENDDO
6484  ENDDO
6485 
6486  END SUBROUTINE w3trll_2d_r8
6487  !/
6488  !/ End of W3TRLL ===================================================== /
6489  !/
6490 
6491 
6492 
6493 
6494 
6495 
6496 
6497 
6498  !/
6499  !/ =================================================================== /
6500  !/
6501  !/ FUNCTION W3LLAZ( LAM1, PHI1, LAM2, PHI2 ) RESULT(AZ)
6502  !/
6503  !/ =================================================================== /
6504  !/
6505  ! 1. Purpose :
6506  !
6507  ! Compute azimuth (Az) east of north which point (LAM2,PHI2) bears
6508  ! to point (LAM1,PHI1).
6509  !
6510  ! 2. Method :
6511  !
6512  ! Map Projections -- A Working Manual, John P. Snyder
6513  ! U.S. Geological Survey professional paper; 1395
6514  ! Chapter 5. Transformation of Map Graticules
6515  !
6516  ! 3. Parameters :
6517  !
6518  ! Return parameter
6519  ! ----------------------------------------------------------------
6520  ! AZ Real O Azimuth in degrees east of north
6521  ! ----------------------------------------------------------------
6522  !
6523  ! Parameter list
6524  ! ----------------------------------------------------------------
6525  ! LAM1 Real I Longitude for point 1
6526  ! PHI1 Real I Latitude for point 1
6527  ! LAM2 Real I Longitude for point 2
6528  ! PHI2 Real I Latitude for point 2
6529  ! ----------------------------------------------------------------
6530  !
6531  ! 4. Subroutines used :
6532  !
6533  ! See module documentation.
6534  !
6535  ! 5. Called by :
6536  !
6537  ! 6. Error messages :
6538  !
6539  ! 7. Remarks :
6540  !
6541  ! 8. Structure :
6542  !
6543  ! 9. Switches :
6544  !
6545  ! !/S Enable subroutine tracing.
6546  !
6547  ! 10. Source code :
6548  !/
6549  !/ ------------------------------------------------------------------- /
6550  !/
6551  FUNCTION w3llaz_r4( LAM1, PHI1, LAM2, PHI2 ) RESULT(AZ)
6552  ! Single precision interface
6553  REAL(4) :: az
6554  REAL(4), INTENT(IN):: lam1, phi1
6555  REAL(4), INTENT(IN):: lam2, phi2
6556 
6557  ! Local parameters
6558  REAL(8) :: clam, slam, cph1, sph1, cph2, sph2
6559 #ifdef W3_S
6560  INTEGER, SAVE :: ient = 0
6561  CALL strace (ient, 'W3LLAZ_R4')
6562 #endif
6563 
6564  clam = cos((lam2-lam1)*d2r)
6565  slam = sin((lam2-lam1)*d2r)
6566  cph1 = cos(phi1*d2r)
6567  sph1 = sin(phi1*d2r)
6568  cph2 = cos(phi2*d2r)
6569  sph2 = sin(phi2*d2r)
6570  az = atan2(cph2*slam,cph1*sph2-sph1*cph2*clam)*r2d
6571 
6572  END FUNCTION w3llaz_r4
6573  !/
6574  !/ ------------------------------------------------------------------- /
6575  !/
6576  FUNCTION w3llaz_r8( LAM1, PHI1, LAM2, PHI2 ) RESULT(AZ)
6577  ! Double precision interface
6578  REAL(8) :: az
6579  REAL(8), INTENT(IN):: lam1, phi1
6580  REAL(8), INTENT(IN):: lam2, phi2
6581 
6582  ! Local parameters
6583  REAL(8) :: clam, slam, cph1, sph1, cph2, sph2
6584 #ifdef W3_S
6585  INTEGER, SAVE :: ient = 0
6586  CALL strace (ient, 'W3LLAZ_R8')
6587 #endif
6588 
6589  clam = cos((lam2-lam1)*d2r)
6590  slam = sin((lam2-lam1)*d2r)
6591  cph1 = cos(phi1*d2r)
6592  sph1 = sin(phi1*d2r)
6593  cph2 = cos(phi2*d2r)
6594  sph2 = sin(phi2*d2r)
6595  az = atan2(cph2*slam,cph1*sph2-sph1*cph2*clam)*r2d
6596 
6597  END FUNCTION w3llaz_r8
6598  !/
6599  !/ End of W3LLAZ ===================================================== /
6600  !/
6601 
6602 
6603 
6604 
6605 
6606 
6607 
6608 
6609  !/
6610  !/ =================================================================== /
6611  !/
6612  !/ SUBROUTINE W3FDWT( N, ND, M, Z, X, C )
6613  !/
6614  !/ =================================================================== /
6615  !/
6616  ! 1. Purpose :
6617  !
6618  ! Compute finite-difference weights on arbitrarily spaced
6619  ! 1-D node sets.
6620  !
6621  ! 2. Method :
6622  !
6623  ! Fornberg, B., Calculation of weights in finite difference formulas,
6624  ! SIAM Rev. 40:685-691, 1998.
6625  !
6626  ! 3. Parameters :
6627  !
6628  ! Parameter list
6629  ! ----------------------------------------------------------------
6630  ! N Int. I One less than total number of grid points;
6631  ! n must not exceed the parameter nd below.
6632  ! ND Int. I Dimension of X- and C-arrays in calling program
6633  ! X(0:ND) and C(0:ND,0:M), respectively.
6634  ! M Int. I Highest derivative for which weights are sought.
6635  ! Z Real I Location where approximations are to be accurate.
6636  ! X R.A. I Grid point locations, found in X(0:N)
6637  ! C R.A. O Weights at grid locations X(0:N) for derivatives
6638  ! of order 0:M, found in C(0:N,0:M)
6639  ! ----------------------------------------------------------------
6640  !
6641  ! 4. Subroutines used :
6642  !
6643  ! See module documentation.
6644  !
6645  ! 5. Called by :
6646  !
6647  ! 6. Error messages :
6648  !
6649  ! 7. Remarks :
6650  !
6651  ! 8. Structure :
6652  !
6653  ! 9. Switches :
6654  !
6655  ! !/S Enable subroutine tracing.
6656  !
6657  ! 10. Source code :
6658  !/
6659  !/ ------------------------------------------------------------------- /
6660  !/
6661  SUBROUTINE w3fdwt_r4 ( N, ND, M, Z, X, C )
6662  ! Single precision interface
6663  INTEGER, INTENT(IN) :: n, nd, m
6664  REAL(4), INTENT(IN) :: z
6665  REAL(4), INTENT(IN) :: x(0:nd)
6666  REAL(4), INTENT(OUT) :: c(0:nd,0:m)
6667 
6668  ! Local parameters
6669  INTEGER :: i, j, k, mn
6670  REAL(8) :: c1, c2, c3, c4, c5
6671 #ifdef W3_S
6672  INTEGER, SAVE :: ient = 0
6673  CALL strace (ient, 'W3FDWT_R4')
6674 #endif
6675 
6676  c1 = one
6677  c4 = x(0)-z
6678  c(:,:) = zero
6679  c(0,0) = one
6680  iloop: DO i = 1,n
6681  mn = min(i,m)
6682  c2 = one
6683  c5 = c4
6684  c4 = x(i)-z
6685  jloop: DO j = 0,i-1
6686  c3 = x(i)-x(j)
6687  c2 = c2*c3
6688  IF ( j.EQ.i-1 ) THEN
6689  DO k = mn,1,-1
6690  c(i,k) = c1*(k*c(i-1,k-1)-c5*c(i-1,k))/c2
6691  END DO
6692  c(i,0) = -c1*c5*c(i-1,0)/c2
6693  END IF
6694  DO k = mn,1,-1
6695  c(j,k) = (c4*c(j,k)-k*c(j,k-1))/c3
6696  END DO
6697  c(j,0) = c4*c(j,0)/c3
6698  END DO jloop
6699  c1 = c2
6700  END DO iloop
6701 
6702  END SUBROUTINE w3fdwt_r4
6703  !/
6704  !/ ------------------------------------------------------------------- /
6705  !/
6706  SUBROUTINE w3fdwt_r8 ( N, ND, M, Z, X, C )
6707  ! Double precision interface
6708  INTEGER, INTENT(IN) :: n, nd, m
6709  REAL(8), INTENT(IN) :: z
6710  REAL(8), INTENT(IN) :: x(0:nd)
6711  REAL(8), INTENT(OUT) :: c(0:nd,0:m)
6712 
6713  ! Local parameters
6714  INTEGER :: i, j, k, mn
6715  REAL(8) :: c1, c2, c3, c4, c5
6716 #ifdef W3_S
6717  INTEGER, SAVE :: ient = 0
6718  CALL strace (ient, 'W3FDWT_R4')
6719 #endif
6720 
6721  c1 = one
6722  c4 = x(0)-z
6723  c(:,:) = zero
6724  c(0,0) = one
6725  iloop: DO i = 1,n
6726  mn = min(i,m)
6727  c2 = one
6728  c5 = c4
6729  c4 = x(i)-z
6730  jloop: DO j = 0,i-1
6731  c3 = x(i)-x(j)
6732  c2 = c2*c3
6733  IF ( j.EQ.i-1 ) THEN
6734  DO k = mn,1,-1
6735  c(i,k) = c1*(k*c(i-1,k-1)-c5*c(i-1,k))/c2
6736  END DO
6737  c(i,0) = -c1*c5*c(i-1,0)/c2
6738  END IF
6739  DO k = mn,1,-1
6740  c(j,k) = (c4*c(j,k)-k*c(j,k-1))/c3
6741  END DO
6742  c(j,0) = c4*c(j,0)/c3
6743  END DO jloop
6744  c1 = c2
6745  END DO iloop
6746 
6747  END SUBROUTINE w3fdwt_r8
6748  !/
6749  !/ End of W3FDWT ===================================================== /
6750  !/
6751 
6752 
6753 
6754 
6755 
6756 
6757 
6758 
6759  !/
6760  !/ =================================================================== /
6761  !/
6762  !/ FUNCTION W3NNSC( NLVL ) RESULT(NNS)
6763  !/
6764  !/ =================================================================== /
6765  !/
6766  ! 1. Purpose :
6767  !
6768  ! Create nearest-neighbor (NNBR) search object.
6769  !
6770  ! 2. Method :
6771  !
6772  ! Notation
6773  ! ( L, N): L = NNBR level; N = NNBR sequential index
6774  ! {DI, DJ}: DI = I-index delta; DJ = J-index delta
6775  !
6776  ! ---------------------------------------------------
6777  ! | ( 2,21) | ( 2,20) | ( 2,19) | ( 2,18) | ( 2,17) |
6778  ! | {-2,+2} | {-1,+2} | { 0,+2} | {+1,+2} | {+2,+2} |
6779  ! ---------------------------------------------------
6780  ! | ( 2,22) | ( 1, 7) | ( 1, 6) | ( 1, 5) | ( 2,16) |
6781  ! | {-2,+1} | {-1,+1} | { 0,+1} | {+1,+1} | {+2,+1} |
6782  ! ---------------------------------------------------
6783  ! | ( 2,23) | ( 1, 8) | ( 0, 0) | ( 1, 4) | ( 2,15) |
6784  ! | {-2, 0} | {-1, 0} | { 0, 0} | {+1, 0} | {+2, 0} |
6785  ! ---------------------------------------------------
6786  ! | ( 2,24) | ( 1, 1) | ( 1, 2) | ( 1, 3) | ( 2,14) |
6787  ! | {-2,-1} | {-1,-1} | { 0,-1} | {+1,-1} | {+2,-1} |
6788  ! ---------------------------------------------------
6789  ! | ( 2, 9) | ( 2,10) | ( 2,11) | ( 2,12) | ( 2,13) |
6790  ! | {-2,-2} | {-1,-2} | { 0,-2} | {+1,-2} | {+2,-2} |
6791  ! ---------------------------------------------------
6792  !
6793  ! 3. Parameters :
6794  !
6795  ! Parameter list
6796  ! ----------------------------------------------------------------
6797  ! ----------------------------------------------------------------
6798  !
6799  ! 4. Subroutines used :
6800  !
6801  ! See module documentation.
6802  !
6803  ! 5. Called by :
6804  !
6805  ! 6. Error messages :
6806  !
6807  ! 7. Remarks :
6808  !
6809  ! 8. Structure :
6810  !
6811  ! 9. Switches :
6812  !
6813  ! !/S Enable subroutine tracing.
6814  !
6815  ! 10. Source code :
6816  !/
6817  !/ ------------------------------------------------------------------- /
6818  !/
6819  FUNCTION w3nnsc( NLVL ) RESULT(NNS)
6820  TYPE(t_nns), POINTER :: nns
6821  INTEGER, INTENT(IN) :: nlvl
6822 
6823  ! Local parameters
6824  INTEGER :: i, j, l, n
6825 #ifdef W3_S
6826  INTEGER, SAVE :: ient = 0
6827  CALL strace (ient, 'W3NNSC')
6828 #endif
6829  !
6830  !-----allocate object
6831  ALLOCATE(nns)
6832 
6833  !-----initialize sizes
6834  nns%NLVL = nlvl
6835  nns%NNBR = (2*nlvl+1)**2
6836 
6837  !-----allocate arrays
6838  ALLOCATE(nns%N1(0:nns%NLVL))
6839  ALLOCATE(nns%N2(0:nns%NLVL))
6840  ALLOCATE(nns%DI(0:nns%NNBR-1))
6841  ALLOCATE(nns%DJ(0:nns%NNBR-1))
6842 
6843  !-----compute index deltas for nearest-neighbor searches
6844  n = 0
6845  !-----central point
6846  l = 0
6847  nns%N1(l) = 0; nns%N2(l) = (2*l+1)**2-1;
6848  nns%DI(n) = 0; nns%DJ(n) = 0;
6849  !-----loop over levels
6850  DO l=1,nns%NLVL
6851  !---------nnbr loop bounds
6852  nns%N1(l) = (2*l-1)**2; nns%N2(l) = (2*l+1)**2-1;
6853  !---------bottom-layer
6854  j = -l
6855  DO i=-l,l-1
6856  n = n + 1
6857  nns%DI(n) = i; nns%DJ(n) = j;
6858  END DO
6859  !---------right-layer
6860  i = l
6861  DO j=-l,l-1
6862  n = n + 1
6863  nns%DI(n) = i; nns%DJ(n) = j;
6864  END DO
6865  !---------top-layer
6866  j = l
6867  DO i=l,-l+1,-1
6868  n = n + 1
6869  nns%DI(n) = i; nns%DJ(n) = j;
6870  END DO
6871  !---------left-layer
6872  i = -l
6873  DO j=l,-l+1,-1
6874  n = n + 1
6875  nns%DI(n) = i; nns%DJ(n) = j;
6876  END DO
6877  END DO !loop over levels
6878 
6879  END FUNCTION w3nnsc
6880  !/
6881  !/ End of W3NNSC ===================================================== /
6882  !/
6883 
6884 
6885 
6886 
6887 
6888 
6889 
6890 
6891  !/
6892  !/ =================================================================== /
6893  !/
6894  !/ SUBROUTINE W3NNSD( NNS )
6895  !/
6896  !/ =================================================================== /
6897  !/
6898  ! 1. Purpose :
6899  !
6900  ! Destroy nearest-neighbor (NNBR) search object.
6901  !
6902  ! 2. Method :
6903  !
6904  ! 3. Parameters :
6905  !
6906  ! Parameter list
6907  ! ----------------------------------------------------------------
6908  ! ----------------------------------------------------------------
6909  !
6910  ! 4. Subroutines used :
6911  !
6912  ! See module documentation.
6913  !
6914  ! 5. Called by :
6915  !
6916  ! 6. Error messages :
6917  !
6918  ! 7. Remarks :
6919  !
6920  ! 8. Structure :
6921  !
6922  ! 9. Switches :
6923  !
6924  ! !/S Enable subroutine tracing.
6925  !
6926  ! 10. Source code :
6927  !/
6928  !/ ------------------------------------------------------------------- /
6929  !/
6930  SUBROUTINE w3nnsd( NNS )
6931  TYPE(t_nns), POINTER :: nns
6932 
6933  ! Local parameters
6934 #ifdef W3_S
6935  INTEGER, SAVE :: ient = 0
6936  CALL strace (ient, 'W3NNSD')
6937 #endif
6938  !
6939  IF ( ASSOCIATED(nns) ) THEN
6940  nns%NLVL = 0
6941  nns%NNBR = 0
6942  IF ( ASSOCIATED(nns%N1) ) THEN
6943  DEALLOCATE(nns%N1); NULLIFY(nns%N1);
6944  END IF
6945  IF ( ASSOCIATED(nns%N2) ) THEN
6946  DEALLOCATE(nns%N2); NULLIFY(nns%N2);
6947  END IF
6948  IF ( ASSOCIATED(nns%DI) ) THEN
6949  DEALLOCATE(nns%DI); NULLIFY(nns%DI);
6950  END IF
6951  IF ( ASSOCIATED(nns%DJ) ) THEN
6952  DEALLOCATE(nns%DJ); NULLIFY(nns%DJ);
6953  END IF
6954  DEALLOCATE(nns)
6955  NULLIFY(nns)
6956  END IF
6957 
6958  END SUBROUTINE w3nnsd
6959  !/
6960  !/ End of W3NNSD ===================================================== /
6961  !/
6962 
6963 
6964 
6965 
6966 
6967 
6968 
6969 
6970  !/
6971  !/ =================================================================== /
6972  !/
6973  !/ SUBROUTINE W3NNSP( NNS, IUNIT )
6974  !/
6975  !/ =================================================================== /
6976  !/
6977  ! 1. Purpose :
6978  !
6979  ! Print nearest-neighbor (NNBR) search object to IUNIT.
6980  !
6981  ! 2. Method :
6982  !
6983  ! 3. Parameters :
6984  !
6985  ! Parameter list
6986  ! ----------------------------------------------------------------
6987  ! NNBR Type I Nearest-neighbor search object.
6988  ! IUNIT Int. I OPTIONAL unit for output. Default is stdout.
6989  ! ----------------------------------------------------------------
6990  !
6991  ! 4. Subroutines used :
6992  !
6993  ! See module documentation.
6994  !
6995  ! 5. Called by :
6996  !
6997  ! 6. Error messages :
6998  !
6999  ! 7. Remarks :
7000  !
7001  ! 8. Structure :
7002  !
7003  ! 9. Switches :
7004  !
7005  ! !/S Enable subroutine tracing.
7006  !
7007  ! 10. Source code :
7008  !/
7009  !/ ------------------------------------------------------------------- /
7010  !/
7011  SUBROUTINE w3nnsp(NNS, IUNIT)
7012  TYPE(t_nns), INTENT(IN) :: nns
7013  INTEGER, OPTIONAL, INTENT(IN) :: iunit
7014 
7015  ! Local parameters
7016  INTEGER :: ndst, l, n
7017 #ifdef W3_S
7018  INTEGER, SAVE :: ient = 0
7019  CALL strace (ient, 'W3NNSP')
7020 #endif
7021  !
7022  IF ( PRESENT(iunit) ) THEN
7023  ndst = iunit
7024  ELSE
7025  ndst = 6
7026  END IF
7027  !
7028  WRITE(ndst,'(A,2I6)') 'nlvl,nnbr:',nns%NLVL,nns%NNBR
7029  DO l=0,nns%NLVL
7030  DO n=nns%N1(l),nns%N2(l)
7031  WRITE(ndst,'(A,4I6)') 'l,n,di,dj:',l,n,nns%DI(n),nns%DJ(n)
7032  END DO
7033  END DO
7034 
7035  END SUBROUTINE w3nnsp
7036  !/
7037  !/ End of W3NNSP ===================================================== /
7038  !/
7039 
7040 
7041 
7042 
7043 
7044 
7045 
7046 
7047  !/
7048  !/ =================================================================== /
7049  !/
7050  !/ SUBROUTINE W3SORT( N, I, J, D )
7051  !/
7052  !/ =================================================================== /
7053  !/
7054  ! 1. Purpose :
7055  !
7056  ! Sort input arrays in increasing order according to input array D.
7057  !
7058  ! 2. Method :
7059  !
7060  ! 3. Parameters :
7061  !
7062  ! Parameter list
7063  ! ----------------------------------------------------------------
7064  ! ----------------------------------------------------------------
7065  !
7066  ! 4. Subroutines used :
7067  !
7068  ! See module documentation.
7069  !
7070  ! 5. Called by :
7071  !
7072  ! 6. Error messages :
7073  !
7074  ! 7. Remarks :
7075  !
7076  ! 8. Structure :
7077  !
7078  ! 9. Switches :
7079  !
7080  ! !/S Enable subroutine tracing.
7081  !
7082  ! 10. Source code :
7083  !/
7084  !/ ------------------------------------------------------------------- /
7085  !/
7086  SUBROUTINE w3sort_r4( N, I, J, D )
7087  ! Single precision interface.
7088  INTEGER, INTENT(IN) :: n
7089  INTEGER, INTENT(INOUT) :: i(n)
7090  INTEGER, INTENT(INOUT) :: j(n)
7091  REAL(4), INTENT(INOUT) :: d(n)
7092 
7093  ! Local parameters
7094  INTEGER :: k, l, im, jm
7095  REAL(4) :: dm
7096 #ifdef W3_S
7097  INTEGER, SAVE :: ient = 0
7098  CALL strace (ient, 'W3SORT_R4')
7099 #endif
7100 
7101  DO k=1, n-1
7102  DO l=k+1, n
7103  IF ( d(l) .LT. d(k) ) THEN
7104  im = i(k); jm = j(k); dm = d(k);
7105  i(k) = i(l); j(k) = j(l); d(k) = d(l);
7106  i(l) = im; j(l) = jm; d(l) = dm;
7107  END IF
7108  END DO !L
7109  END DO !K
7110 
7111  END SUBROUTINE w3sort_r4
7112  !/
7113  !/ ------------------------------------------------------------------- /
7114  !/
7115  SUBROUTINE w3sort_r8( N, I, J, D )
7116  ! Double precision interface.
7117  INTEGER, INTENT(IN) :: n
7118  INTEGER, INTENT(INOUT) :: i(n)
7119  INTEGER, INTENT(INOUT) :: j(n)
7120  REAL(8), INTENT(INOUT) :: d(n)
7121 
7122  ! Local parameters
7123  INTEGER :: k, l, im, jm
7124  REAL(8) :: dm
7125 #ifdef W3_S
7126  INTEGER, SAVE :: ient = 0
7127  CALL strace (ient, 'W3SORT_R8')
7128 #endif
7129 
7130  DO k=1, n-1
7131  DO l=k+1, n
7132  IF ( d(l) .LT. d(k) ) THEN
7133  im = i(k); jm = j(k); dm = d(k);
7134  i(k) = i(l); j(k) = j(l); d(k) = d(l);
7135  i(l) = im; j(l) = jm; d(l) = dm;
7136  END IF
7137  END DO !L
7138  END DO !K
7139 
7140  END SUBROUTINE w3sort_r8
7141  !/
7142  !/ End of W3SORT ===================================================== /
7143  !/
7144 
7145 
7146 
7147 
7148 
7149 
7150 
7151 
7152  !/
7153  !/ =================================================================== /
7154  !/
7155  !/ SUBROUTINE W3ISRT( II, JJ, DD, N, I, J, D )
7156  !/
7157  !/ =================================================================== /
7158  !/
7159  ! 1. Purpose :
7160  !
7161  ! Insert DD data into D at location where DD < D(K).
7162  !
7163  ! 2. Method :
7164  !
7165  ! 3. Parameters :
7166  !
7167  ! Parameter list
7168  ! ----------------------------------------------------------------
7169  ! ----------------------------------------------------------------
7170  !
7171  ! 4. Subroutines used :
7172  !
7173  ! See module documentation.
7174  !
7175  ! 5. Called by :
7176  !
7177  ! 6. Error messages :
7178  !
7179  ! 7. Remarks :
7180  !
7181  ! 8. Structure :
7182  !
7183  ! 9. Switches :
7184  !
7185  ! !/S Enable subroutine tracing.
7186  !
7187  ! 10. Source code :
7188  !/
7189  !/ ------------------------------------------------------------------- /
7190  !/
7191  SUBROUTINE w3isrt_r4( II, JJ, DD, N, I, J, D )
7192  ! Single precision interface
7193  INTEGER, INTENT(IN) :: ii
7194  INTEGER, INTENT(IN) :: jj
7195  REAL(4), INTENT(IN) :: dd
7196  INTEGER, INTENT(IN) :: n
7197  INTEGER, INTENT(INOUT) :: i(n)
7198  INTEGER, INTENT(INOUT) :: j(n)
7199  REAL(4), INTENT(INOUT) :: d(n)
7200 
7201  ! Local parameters
7202  INTEGER :: k, l
7203 #ifdef W3_S
7204  INTEGER, SAVE :: ient = 0
7205  CALL strace (ient, 'W3ISRT_R4')
7206 #endif
7207 
7208  k_loop: DO k=1,n
7209  IF ( dd .LT. d(k) ) THEN
7210  !-------------right-shift list (>= k)
7211  DO l=n,k+1,-1
7212  i(l) = i(l-1); j(l) = j(l-1); d(l) = d(l-1);
7213  END DO !L
7214  !-------------insert point into list at k
7215  i(k) = ii; j(k) = jj; d(k) = dd;
7216  EXIT k_loop
7217  END IF !dd.lt.d(k)
7218  END DO k_loop
7219 
7220  END SUBROUTINE w3isrt_r4
7221  !/
7222  !/ ------------------------------------------------------------------- /
7223  !/
7224  SUBROUTINE w3isrt_r8( II, JJ, DD, N, I, J, D )
7225  ! Double precision interface
7226  INTEGER, INTENT(IN) :: ii
7227  INTEGER, INTENT(IN) :: jj
7228  REAL(8), INTENT(IN) :: dd
7229  INTEGER, INTENT(IN) :: n
7230  INTEGER, INTENT(INOUT) :: i(n)
7231  INTEGER, INTENT(INOUT) :: j(n)
7232  REAL(8), INTENT(INOUT) :: d(n)
7233 
7234  ! Local parameters
7235  INTEGER :: k, l
7236 #ifdef W3_S
7237  INTEGER, SAVE :: ient = 0
7238  CALL strace (ient, 'W3ISRT_R8')
7239 #endif
7240 
7241  k_loop: DO k=1,n
7242  IF ( dd .LT. d(k) ) THEN
7243  !-------------right-shift list (>= k)
7244  DO l=n,k+1,-1
7245  i(l) = i(l-1); j(l) = j(l-1); d(l) = d(l-1);
7246  END DO !L
7247  !-------------insert point into list at k
7248  i(k) = ii; j(k) = jj; d(k) = dd;
7249  EXIT k_loop
7250  END IF !dd.lt.d(k)
7251  END DO k_loop
7252 
7253  END SUBROUTINE w3isrt_r8
7254  !/
7255  !/ End of W3ISRT ===================================================== /
7256  !/
7257 
7258 
7259 
7260 
7261 
7262 
7263 
7264 
7265  !/
7266  !/ =================================================================== /
7267  !/
7268  !/ FUNCTION W3INAN( X ) RESULT(INAN)
7269  !/
7270  !/ =================================================================== /
7271  !/
7272  ! 1. Purpose :
7273  !
7274  ! Return TRUE if input is infinite or NaN (not a number).
7275  !
7276  ! 2. Method :
7277  !
7278  ! 3. Parameters :
7279  !
7280  ! Parameter list
7281  ! ----------------------------------------------------------------
7282  ! ----------------------------------------------------------------
7283  !
7284  ! 4. Subroutines used :
7285  !
7286  ! See module documentation.
7287  !
7288  ! 5. Called by :
7289  !
7290  ! 6. Error messages :
7291  !
7292  ! 7. Remarks :
7293  !
7294  ! 8. Structure :
7295  !
7296  ! 9. Switches :
7297  !
7298  ! !/S Enable subroutine tracing.
7299  !
7300  ! 10. Source code :
7301  !/
7302  !/ ------------------------------------------------------------------- /
7303  !/
7304  FUNCTION w3inan_r4( X ) RESULT(INAN)
7305  ! Single precision interface
7306  LOGICAL :: inan
7307  REAL(4), INTENT(IN) :: x
7308 
7309  ! Local parameters
7310 #ifdef W3_S
7311  INTEGER, SAVE :: ient = 0
7312  CALL strace (ient, 'W3INAN_R4')
7313 #endif
7314 
7315  !-----return true if X is NaN or +Inf or -Inf
7316  inan = .NOT. ( x .GE. -huge(x) .AND. x .LE. huge(x) )
7317 
7318  END FUNCTION w3inan_r4
7319  !/
7320  !/ ------------------------------------------------------------------- /
7321  !/
7322  FUNCTION w3inan_r8( X ) RESULT(INAN)
7323  ! Double precision interface
7324  LOGICAL :: inan
7325  REAL(8), INTENT(IN) :: x
7326 
7327  ! Local parameters
7328 #ifdef W3_S
7329  INTEGER, SAVE :: ient = 0
7330  CALL strace (ient, 'W3INAN_R8')
7331 #endif
7332 
7333  !-----return true if X is NaN or +Inf or -Inf
7334  inan = .NOT. ( x .GE. -huge(x) .AND. x .LE. huge(x) )
7335 
7336  END FUNCTION w3inan_r8
7337  !/
7338  !/ End of W3INAN ===================================================== /
7339  !/
7340 
7341 
7342 
7343 
7344 
7345 
7346 
7347 
7348  !/
7349  !/ Internal Support Routines ========================================= /
7350  !/
7351  !/
7352  !/ ------------------------------------------------------------------- /
7353  !/
7354  FUNCTION gsu_create( IJG, LLG, ICLO, LB, UB, XG4, YG4, XG8, YG8, &
7355  BBOX_ONLY, NCB, NNP, DEBUG ) RESULT(GSU)
7356  ! *** INTERNAL SUBROUTINE ***
7357  TYPE(t_gsu) :: gsu
7358  LOGICAL, INTENT(IN) :: ijg
7359  LOGICAL, INTENT(IN) :: llg
7360  INTEGER, INTENT(IN) :: iclo
7361  INTEGER, INTENT(IN) :: lb(2)
7362  INTEGER, INTENT(IN) :: ub(2)
7363  REAL(4), TARGET, OPTIONAL :: xg4(lb(1):ub(1),lb(2):ub(2))
7364  REAL(4), TARGET, OPTIONAL :: yg4(lb(1):ub(1),lb(2):ub(2))
7365  REAL(8), TARGET, OPTIONAL :: xg8(lb(1):ub(1),lb(2):ub(2))
7366  REAL(8), TARGET, OPTIONAL :: yg8(lb(1):ub(1),lb(2):ub(2))
7367  LOGICAL, INTENT(IN), OPTIONAL :: bbox_only
7368  INTEGER, INTENT(IN), OPTIONAL :: ncb
7369  INTEGER, INTENT(IN), OPTIONAL :: nnp
7370  LOGICAL, INTENT(IN), OPTIONAL :: debug
7371 
7372  ! Local parameters
7373  TYPE(class_gsu), POINTER :: ptr
7374  LOGICAL :: type_r4, type_r8
7375  LOGICAL :: ldbg, lbbox, lbc, lpl, lnpl, lspl
7376  INTEGER :: lbx, lby, ubx, uby, nx, ny
7377  INTEGER :: lxc, lyc, uxc, uyc
7378  INTEGER :: i, j, k, l, n, ic(4), jc(4), ib, jb
7379  INTEGER :: ns, ib1(2), ib2(2), jb1(2), jb2(2), ibc(4), jbc(4)
7380  INTEGER :: istep, istat
7381  REAL(8) :: xc(4), yc(4)
7382 #ifdef W3_S
7383  INTEGER, SAVE :: ient = 0
7384  CALL strace (ient, 'W3GSUC')
7385 #endif
7386  ! -------------------------------------------------------------------- /
7387  ! 1. Test input
7388  !
7389  type_r4 = PRESENT(xg4).AND.PRESENT(yg4)
7390  type_r8 = PRESENT(xg8).AND.PRESENT(yg8)
7391  IF ( .NOT.type_r4.AND..NOT.type_r8 ) THEN
7392  WRITE(0,'(/1A,1A,1I2/)') 'W3GSUC ERROR -- ', &
7393  'no input grid coordinates specified'
7394  CALL extcde (1)
7395  END IF
7396 
7397  IF (ijg) THEN
7398  lbx = lb(1)
7399  lby = lb(2)
7400  ubx = ub(1)
7401  uby = ub(2)
7402  ELSE
7403  lbx = lb(2)
7404  lby = lb(1)
7405  ubx = ub(2)
7406  uby = ub(1)
7407  END IF
7408  nx = ubx - lbx + 1
7409  ny = uby - lby + 1
7410 
7411  SELECT CASE ( iclo )
7413  CONTINUE
7414  CASE DEFAULT
7415  WRITE(0,'(/1A,1A,1I2/)') 'W3GSUC ERROR -- ', &
7416  'unsupported ICLO: ',iclo
7417  CALL extcde (1)
7418  END SELECT
7419 
7420  IF ( iclo.EQ.iclo_trpl .AND. mod(nx,2).NE.0 ) THEN
7421  WRITE(0,'(/1A,1A/)') 'W3GSUC ERROR -- ', &
7422  'tripole grid closure requires NX=UBX-LBX+1 be even'
7423  CALL extcde (1)
7424  END IF
7425 
7426  IF ( PRESENT(bbox_only) ) THEN
7427  lbbox = bbox_only
7428  ELSE
7429  lbbox = .false.
7430  END IF
7431 
7432  IF ( PRESENT(ncb) ) THEN
7433  IF ( ncb .LE. 0 ) THEN
7434  WRITE(0,'(/1A,1A/)') 'W3GSUC ERROR -- ', &
7435  'NCB must be greater than zero'
7436  CALL extcde (1)
7437  END IF
7438  END IF
7439  !
7440  IF ( PRESENT(debug) ) THEN
7441  ldbg = debug
7442  ELSE
7443  ldbg = .false.
7444  END IF
7445  !
7446  ! -------------------------------------------------------------------- /
7447  ! 2. Allocate object and set grid related data and pointers
7448  !
7449  ALLOCATE(ptr, stat=istat)
7450  IF ( istat .NE. 0 ) THEN
7451  WRITE(0,'(/1A,1A/)') 'W3GSUC ERROR -- ', &
7452  'gsu object allocation failed'
7453  CALL extcde (istat)
7454  END IF
7455  ptr%IJG = ijg
7456  ptr%LLG = llg
7457  ptr%ICLO = iclo
7458  ptr%LBX = lbx
7459  ptr%LBY = lby
7460  ptr%UBX = ubx
7461  ptr%UBY = uby
7462  ptr%NX = nx
7463  ptr%NY = ny
7464  IF (type_r4) THEN
7465  ptr%XG4 => xg4
7466  ptr%YG4 => yg4
7467  ptr%GKIND = 4
7468  ELSE
7469  ptr%XG8 => xg8
7470  ptr%YG8 => yg8
7471  ptr%GKIND = 8
7472  END IF
7473  NULLIFY( ptr%NNP )
7474  NULLIFY( ptr%B )
7475  NULLIFY( ptr%NNB )
7476  !
7477  ! -------------------------------------------------------------------- /
7478  ! 3. Create nearest-neighbor point search object
7479  !
7480  IF ( .NOT.lbbox ) THEN
7481  IF ( PRESENT(nnp) ) THEN
7482  ptr%NNP => w3nnsc(nnp)
7483  ELSE
7484  ptr%NNP => w3nnsc(nnp_default)
7485  END IF
7486  END IF
7487  !
7488  ! -------------------------------------------------------------------- /
7489  ! 4. Construct bucket search "object"
7490  !
7491  !-----number of cells
7492  lxc = lbx; lyc = lby;
7493  SELECT CASE ( iclo )
7494  CASE ( iclo_none )
7495  uxc = ubx-1; uyc = uby-1;
7496  CASE ( iclo_grdi )
7497  uxc = ubx; uyc = uby-1;
7498  CASE ( iclo_grdj )
7499  uxc = ubx-1; uyc = uby;
7500  CASE ( iclo_trdl )
7501  uxc = ubx; uyc = uby;
7502  CASE ( iclo_trpl )
7503  uxc = ubx; uyc = uby;
7504  END SELECT
7505  !
7506  !-----initialize longitudinal periodicity flag (LCLO)
7507  IF ( llg .AND. iclo.NE.iclo_none ) THEN
7508  ptr%LCLO = .true.
7509  ELSE
7510  ptr%LCLO = .false.
7511  END IF
7512  !
7513  !-----check existence of longitudinal branch cut
7514  !-----check if source grid includes poles
7515  IF ( ldbg ) THEN
7516  WRITE(*,'(/A)') 'W3GSUC - check source grid'
7517  END IF
7518  lnpl = .false.
7519  lspl = .false.
7520  DO i=lxc,uxc
7521  DO j=lyc,uyc
7522  !-------------create list of cell vertices
7523  ic(1) = i ; jc(1) = j ;
7524  ic(2) = i+1; jc(2) = j ;
7525  ic(3) = i+1; jc(3) = j+1;
7526  ic(4) = i ; jc(4) = j+1;
7527  DO l=1,4
7528  !-----------------apply index closure
7529  IF ( mod(iclo,2).EQ.0 ) &
7530  ic(l) = lbx + mod(nx - 1 + mod(ic(l) - lbx + 1, nx), nx)
7531  IF ( mod(iclo,3).EQ.0 ) &
7532  jc(l) = lby + mod(ny - 1 + mod(jc(l) - lby + 1, ny), ny)
7533  IF ( iclo.EQ.iclo_trpl .AND. jc(l).GT.uby ) THEN
7534  ic(l) = ubx + lbx - ic(l)
7535  jc(l) = 2*uby - jc(l) + 1
7536  END IF
7537  !-----------------copy cell vertex coordinates into local variables
7538  IF ( ijg ) THEN
7539  IF (type_r4) THEN
7540  xc(l) = xg4(ic(l),jc(l))
7541  yc(l) = yg4(ic(l),jc(l))
7542  ELSE
7543  xc(l) = xg8(ic(l),jc(l))
7544  yc(l) = yg8(ic(l),jc(l))
7545  END IF
7546  ELSE
7547  IF (type_r4) THEN
7548  xc(l) = xg4(jc(l),ic(l))
7549  yc(l) = yg4(jc(l),ic(l))
7550  ELSE
7551  xc(l) = xg8(jc(l),ic(l))
7552  yc(l) = yg8(jc(l),ic(l))
7553  END IF
7554  END IF
7555  END DO !L
7556  !-------------check if cell includes a pole or branch cut
7557  lpl = .false.
7558  lbc = .false.
7559  IF ( llg ) THEN
7560  !-----------------count longitudinal branch cut crossings
7561  n = 0
7562  DO l=1,4
7563  k = mod(l,4)+1
7564  IF ( abs(xc(k)-xc(l)) .GT. d180 ) n = n + 1
7565  END DO
7566  !-----------------multiple longitudinal branch cut crossing => cell includes branch cut
7567  lbc = n.GT.1
7568  IF ( lbc .AND. ldbg ) &
7569  WRITE(*,'(A,8I6)') &
7570  'W3GSUC -- cell includes branch cut:',ic(:),jc(:)
7571  !-----------------single longitudinal branch cut crossing
7572  ! or single vertex at 90 degrees => cell includes pole
7573  lpl = n.EQ.1 .OR. count(abs(yc).EQ.d90).EQ.1
7574  IF ( lpl.AND.minval(yc).GT.zero ) THEN
7575  IF ( ldbg ) &
7576  WRITE(*,'(A,8I6)') &
7577  'W3GSUC -- cell includes N-pole:',ic(:),jc(:)
7578  lnpl = .true.
7579  END IF
7580  IF ( lpl.AND.maxval(yc).LT.zero ) THEN
7581  IF ( ldbg ) &
7582  WRITE(*,'(A,8I6)') &
7583  'W3GSUC -- cell includes S-pole:',ic(:),jc(:)
7584  lspl = .true.
7585  END IF
7586  !-----------------longitudinal branch cut crossing => longitudinal closure
7587  IF ( n.GT.0 ) ptr%LCLO = .true.
7588  END IF !LLG
7589  END DO !J
7590  END DO !I
7591  !
7592  !-----compute domain for search buckets
7593  ! if longitudinal periodicity, then force domain in x to [0:360]
7594  ! if grid includes north pole, then set ymax = 90 degrees
7595  ! if grid includes south pole, then set ymin = -90 degrees
7596  IF (type_r4) THEN
7597  ptr%XMIN = minval(xg4); ptr%XMAX = maxval(xg4);
7598  ptr%YMIN = minval(yg4); ptr%YMAX = maxval(yg4);
7599  ELSE
7600  ptr%XMIN = minval(xg8); ptr%XMAX = maxval(xg8);
7601  ptr%YMIN = minval(yg8); ptr%YMAX = maxval(yg8);
7602  END IF
7603  IF ( ptr%LCLO ) THEN
7604  ptr%XMIN = zero; ptr%XMAX = d360;
7605  END IF
7606  IF ( lspl ) ptr%YMIN = -d90
7607  IF ( lnpl ) ptr%YMAX = d90
7608  ptr%L360 = ptr%XMIN.GE.zero
7609  !
7610  !-----if bbox only, then set pointer and return
7611  IF ( lbbox ) THEN
7612  gsu%PTR => ptr
7613  RETURN
7614  END IF
7615  !
7616  !-----compute number of search buckets and bucket size
7617  IF ( PRESENT(ncb) ) THEN
7618  ptr%NBX = max(1,nx/ncb)
7619  ptr%NBY = max(1,ny/ncb)
7620  ELSE
7621  ptr%NBX = max(1,nx/ncb_default)
7622  ptr%NBY = max(1,ny/ncb_default)
7623  END IF
7624  ptr%DXB = (ptr%XMAX-ptr%XMIN)/real(ptr%NBX)
7625  ptr%DYB = (ptr%YMAX-ptr%YMIN)/real(ptr%NBY)
7626  !
7627  !-----print debug info
7628  IF ( ldbg ) THEN
7629  WRITE(*,'(/A,1I2,1L2,1I2)') 'W3GSUC - ICLO,LCLO,GKIND: ', &
7630  ptr%ICLO,ptr%LCLO,ptr%GKIND
7631  WRITE(*,'(A,4E24.16)') 'W3GSUC - grid search domain:', &
7632  ptr%XMIN,ptr%YMIN,ptr%XMAX,ptr%YMAX
7633  WRITE(*,'(A,2I6)') 'W3GSUC - number of search buckets:', &
7634  ptr%NBX,ptr%NBY
7635  WRITE(*,'(A,2E24.16)') 'W3GSUC - search bucket size:', &
7636  ptr%DXB,ptr%DYB
7637  END IF
7638  !
7639  !-----allocate array of search buckets
7640  ALLOCATE(ptr%B(ptr%NBY,ptr%NBX),stat=istat)
7641  IF ( istat .NE. 0 ) THEN
7642  WRITE(0,'(/1A,1A/)') 'W3GSUC ERROR -- ', &
7643  'search bucket array allocation failed'
7644  CALL extcde (istat)
7645  END IF
7646  !
7647  !-----BEGIN ISTEP_LOOP
7648  ! first step: compute number of cells in each bucket
7649  ! second step: allocate buckets and assign cells to buckets
7650  istep_loop: DO istep=1,2
7651  !
7652  !-----allocate search bucket cell lists
7653  IF ( istep .EQ. 2 ) THEN
7654  DO ib=1,ptr%NBX
7655  DO jb=1,ptr%NBY
7656  NULLIFY(ptr%B(jb,ib)%I)
7657  NULLIFY(ptr%B(jb,ib)%J)
7658  IF ( ptr%B(jb,ib)%N .GT. 0 ) THEN
7659  ALLOCATE(ptr%B(jb,ib)%I(ptr%B(jb,ib)%N),stat=istat)
7660  IF ( istat .NE. 0 ) THEN
7661  WRITE(0,'(/1A,2A,3I6/)') 'W3GSUC ERROR -- ', &
7662  'search bucket cell-i list allocation failed -- ', &
7663  'bucket: ',ib,jb,n
7664  CALL extcde (istat)
7665  END IF
7666  ALLOCATE(ptr%B(jb,ib)%J(ptr%B(jb,ib)%N),stat=istat)
7667  IF ( istat .NE. 0 ) THEN
7668  WRITE(0,'(/1A,2A,3I6/)') 'W3GSUC ERROR -- ', &
7669  'search bucket cell-j list allocation failed -- ', &
7670  'bucket: ',ib,jb,n
7671  CALL extcde (istat)
7672  END IF
7673  END IF
7674  END DO
7675  END DO
7676  END IF !ISTEP.EQ.2
7677  !
7678  !-----build search bucket cell lists
7679  ptr%B(:,:)%N = 0
7680  DO i=lxc,uxc
7681  DO j=lyc,uyc
7682  IF ( iclo.EQ.iclo_trpl ) THEN
7683  IF ( j.EQ.uyc .AND. i.GT.lbx+nx/2 ) cycle
7684  ENDIF
7685  !-------------create list of cell vertices
7686  ic(1) = i ; jc(1) = j ;
7687  ic(2) = i+1; jc(2) = j ;
7688  ic(3) = i+1; jc(3) = j+1;
7689  ic(4) = i ; jc(4) = j+1;
7690  DO l=1,4
7691  !-----------------apply index closure
7692  IF ( mod(iclo,2).EQ.0 ) &
7693  ic(l) = lbx + mod(nx - 1 + mod(ic(l) - lbx + 1, nx), nx)
7694  IF ( mod(iclo,3).EQ.0 ) &
7695  jc(l) = lby + mod(ny - 1 + mod(jc(l) - lby + 1, ny), ny)
7696  IF ( iclo.EQ.iclo_trpl .AND. jc(l).GT.uby ) THEN
7697  ic(l) = ubx + lbx - ic(l)
7698  jc(l) = 2*uby - jc(l) + 1
7699  END IF
7700  !-----------------copy cell vertex coordinates into local variables
7701  IF ( ijg ) THEN
7702  IF (type_r4) THEN
7703  xc(l) = xg4(ic(l),jc(l))
7704  yc(l) = yg4(ic(l),jc(l))
7705  ELSE
7706  xc(l) = xg8(ic(l),jc(l))
7707  yc(l) = yg8(ic(l),jc(l))
7708  END IF
7709  ELSE
7710  IF (type_r4) THEN
7711  xc(l) = xg4(jc(l),ic(l))
7712  yc(l) = yg4(jc(l),ic(l))
7713  ELSE
7714  xc(l) = xg8(jc(l),ic(l))
7715  yc(l) = yg8(jc(l),ic(l))
7716  END IF
7717  END IF
7718  END DO !L
7719  !-------------check if cell includes a pole or branch cut
7720  lpl = .false.
7721  lbc = .false.
7722  IF ( llg ) THEN
7723  !-----------------shift longitudes to appropriate range
7724  xc = mod(xc,d360)
7725  IF ( ptr%LCLO .OR. ptr%L360 ) THEN
7726  WHERE ( xc.LT.zero ) xc = xc + d360
7727  ELSE
7728  WHERE ( xc.GT.d180 ) xc = xc - d360
7729  END IF
7730  !-----------------count longitudinal branch cut crossings
7731  n = 0
7732  DO l=1,4
7733  k = mod(l,4)+1
7734  IF ( abs(xc(k)-xc(l)) .GT. d180 ) n = n + 1
7735  END DO
7736  !-----------------multiple longitudinal branch cut crossing => cell includes branch cut
7737  lbc = n.GT.1
7738  !-----------------single longitudinal branch cut crossing
7739  ! or single vertex at 90 degrees => cell includes pole
7740  lpl = n.EQ.1 .OR. count(abs(yc).EQ.d90).EQ.1
7741  END IF !LLG
7742  !-------------set bucket id for each cell vertex
7743  DO l=1,4
7744  ibc(l) = int((xc(l)-ptr%XMIN)/ptr%DXB)+1
7745  IF ( .NOT.ptr%LCLO ) ibc(l) = min(ibc(l),ptr%NBX)
7746  jbc(l) = min(int((yc(l)-ptr%YMIN)/ptr%DYB)+1,ptr%NBY)
7747  END DO !L
7748  !-------------set bucket overlap bounds
7749  IF ( lpl ) THEN
7750  !---------------cell includes pole: overlap includes full longitudinal range
7751  ns = 1
7752  ib1(1) = 1
7753  ib2(1) = ptr%NBX
7754  IF ( minval(yc).GT.zero ) THEN
7755  jb1(1) = max(1,minval(jbc))
7756  jb2(1) = ptr%NBY
7757  END IF
7758  IF ( maxval(yc).LT.zero ) THEN
7759  jb1(1) = 1
7760  jb2(1) = min(ptr%NBY,maxval(jbc))
7761  END IF
7762  ib1(2) = 0
7763  ib2(2) = 0
7764  jb1(2) = 0
7765  jb2(2) = 0
7766  ELSE IF ( lbc ) THEN
7767  !---------------cell includes branch cut: split overlap into two sets
7768  ns = 2
7769  ib1(1) = ptr%NBX
7770  ib2(1) = ptr%NBX
7771  ib1(2) = 1
7772  ib2(2) = 1
7773  DO l=1,4
7774  IF ( ibc(l) .GT. ptr%NBX/2 ) THEN
7775  ib1(1) = min(ib1(1),ibc(l))
7776  ELSE
7777  ib2(2) = max(ib2(2),ibc(l))
7778  END IF
7779  END DO !L
7780  jb1(:) = max(1,minval(jbc))
7781  jb2(:) = min(ptr%NBY,maxval(jbc))
7782  ELSE
7783  !---------------default: overlap computed from min/max
7784  ns = 1
7785  ib1(1) = max(1,minval(ibc))
7786  ib2(1) = min(ptr%NBX,maxval(ibc))
7787  jb1(1) = max(1,minval(jbc))
7788  jb2(1) = min(ptr%NBY,maxval(jbc))
7789  ib1(2) = 0
7790  ib2(2) = 0
7791  jb1(2) = 0
7792  jb2(2) = 0
7793  END IF
7794  !-------------debug output
7795  IF ( ldbg .AND. istep.EQ.1 ) THEN
7796  WRITE(*,'(/A,2I6)') 'W3GSUC -- BUCKET SORT:',i,j
7797  WRITE(*,'(A,2L6,1I6)') 'W3GSUC -- LBC,LPL:',lbc,lpl
7798  WRITE(*,'(A,4I6)') 'W3GSUC -- IC:',ic(:)
7799  WRITE(*,'(A,4I6)') 'W3GSUC -- JC:',jc(:)
7800  WRITE(*,'(A,4E24.16)') 'W3GSUC -- XC:',xc(:)
7801  WRITE(*,'(A,4E24.16)') 'W3GSUC -- YC:',yc(:)
7802  WRITE(*,'(A,4I6)') 'W3GSUC -- IBC:',ibc(:)
7803  WRITE(*,'(A,4I6)') 'W3GSUC -- JBC:',jbc(:)
7804  WRITE(*,'(A,1I6)') 'W3GSUC -- NS:',ns
7805  WRITE(*,'(A,4I6)') 'W3GSUC -- IB1:',ib1(:)
7806  WRITE(*,'(A,4I6)') 'W3GSUC -- JB1:',jb1(:)
7807  WRITE(*,'(A,4I6)') 'W3GSUC -- IB2:',ib2(:)
7808  WRITE(*,'(A,4I6)') 'W3GSUC -- JB2:',jb2(:)
7809  END IF
7810  !-------------assign cell to buckets based on overlap
7811  DO k=1,ns
7812  DO ib=ib1(k),ib2(k)
7813  DO jb=jb1(k),jb2(k)
7814  ptr%B(jb,ib)%N = ptr%B(jb,ib)%N + 1
7815  IF ( istep .EQ. 2 ) THEN
7816  ptr%B(jb,ib)%I(ptr%B(jb,ib)%N) = ic(1)
7817  ptr%B(jb,ib)%J(ptr%B(jb,ib)%N) = jc(1)
7818  END IF
7819  END DO !JB
7820  END DO !IB
7821  END DO !K
7822  END DO !J
7823  END DO !I
7824  !
7825  !-----END ISTEP_LOOP
7826  END DO istep_loop
7827  !
7828  !-----create nearest-neighbor bucket search object
7829  ptr%NNB => w3nnsc(nint(half*max(ptr%NBX,ptr%NBY)))
7830  !
7831  !-----print debug info
7832  IF ( ldbg ) THEN
7833  WRITE(*,'(/A,3I6,4E24.16)') 'W3GSUC - search bucket list:'
7834  WRITE(*,'(3A6,4A14)') 'I','J','N','X1','Y1','X2','Y2'
7835  DO ib=1,ptr%NBX
7836  DO jb=1,ptr%NBY
7837  WRITE(*,'(3I6,4E24.16)') ib,jb,ptr%B(jb,ib)%N, &
7838  ptr%XMIN+(ib-1)*ptr%DXB,ptr%YMIN+(jb-1)*ptr%DYB, &
7839  ptr%XMIN+(ib-0)*ptr%DXB,ptr%YMIN+(jb-0)*ptr%DYB
7840  END DO
7841  END DO
7842  END IF
7843  !
7844  ! -------------------------------------------------------------------- /
7845  ! 5. Set return parameter
7846  !
7847  gsu%PTR => ptr
7848 
7849  END FUNCTION gsu_create
7850  !/
7851  !/ ------------------------------------------------------------------- /
7852  !/
7853  SUBROUTINE getpqr( XT, YT, XS, YS, PR, QR, EPS, DEBUG )
7854  ! *** INTERNAL SUBROUTINE ***
7855  ! Compute source grid cell-relative coordinates (PR,QR) for target point (XT,YT)
7856  REAL(8), INTENT(IN) :: xt
7857  REAL(8), INTENT(IN) :: yt
7858  REAL(8), INTENT(IN) :: xs(4)
7859  REAL(8), INTENT(IN) :: ys(4)
7860  REAL(8), INTENT(OUT) :: pr
7861  REAL(8), INTENT(OUT) :: qr
7862  REAL(8), INTENT(IN), OPTIONAL :: eps
7863  LOGICAL, INTENT(IN) , OPTIONAL :: debug
7864 
7865  ! Local parameters
7866  INTEGER, PARAMETER :: max_iter = 10
7867  REAL(8), PARAMETER :: converge = 1d-6
7868  REAL(8) :: leps
7869  LOGICAL :: ldbg
7870  INTEGER :: k, iter
7871  REAL(8) :: dxt, dx1, dx2, dx3, dxp, dyt, dy1, dy2, dy3, dyp
7872  REAL(8) :: mat1, mat2, mat3, mat4, delp, delq, det
7873 #ifdef W3_S
7874  INTEGER, SAVE :: ient = 0
7875  CALL strace (ient, 'GETPQR')
7876 #endif
7877 
7878  IF ( PRESENT(eps) ) THEN
7879  IF ( eps .LT. zero ) THEN
7880  WRITE(0,'(/2A/)') 'GETPQR ERROR -- ', &
7881  'EPS parameter must be >= 0'
7882  CALL extcde (1)
7883  END IF
7884  leps = eps
7885  ELSE
7886  leps = eps_default
7887  END IF
7888  IF ( PRESENT(debug) ) THEN
7889  ldbg = debug
7890  ELSE
7891  ldbg = .false.
7892  END IF
7893  !
7894  !-----handle point coincident with a cell vertex
7895  DO k=1,4
7896  IF ( abs(xt-xs(k)).LE.leps .AND. abs(yt-ys(k)).LE.leps ) THEN
7897  SELECT CASE ( k )
7898  CASE ( 1 )
7899  pr = zero; qr = zero;
7900  CASE ( 2 )
7901  pr = one; qr = zero;
7902  CASE ( 3 )
7903  pr = one; qr = one;
7904  CASE ( 4 )
7905  pr = zero; qr = one;
7906  END SELECT
7907  IF ( ldbg ) &
7908  WRITE(*,'(A,I3,4E24.16)') 'GETPQR - COINCIDENT:', &
7909  k,abs(xt-xs(k)),abs(yt-ys(k)),pr,qr
7910  RETURN
7911  END IF
7912  END DO
7913  !
7914  !-----set iteration parameters and initial guess
7915  pr = half
7916  qr = half
7917  dyt = yt - ys(1)
7918  dy1 = ys(2) - ys(1)
7919  dy2 = ys(4) - ys(1)
7920  dy3 = ys(3) - ys(2) - dy2
7921  dxt = xt - xs(1)
7922  dx1 = xs(2) - xs(1)
7923  dx2 = xs(4) - xs(1)
7924  dx3 = xs(3) - xs(2) - dx2
7925 
7926  !-----iterate to find (PR,QR)
7927  iter_loop: DO iter=1,max_iter
7928  dyp = dyt - dy1*pr - dy2*qr - dy3*pr*qr
7929  dxp = dxt - dx1*pr - dx2*qr - dx3*pr*qr
7930  mat1 = dy1 + dy3*qr
7931  mat2 = dy2 + dy3*pr
7932  mat3 = dx1 + dx3*qr
7933  mat4 = dx2 + dx3*pr
7934  det = mat1*mat4 - mat2*mat3
7935  delp = (dyp*mat4 - mat2*dxp)/det
7936  delq = (mat1*dxp - dyp*mat3)/det
7937  IF ( ldbg ) &
7938  WRITE(*,'(A,I3,4E24.16)') 'GETPQR - ITER:', &
7939  iter,pr,qr,delp,delq
7940  pr = pr + delp
7941  qr = qr + delq
7942  IF ( abs(delp) < converge .AND. &
7943  abs(delq) < converge ) EXIT iter_loop
7944  END DO iter_loop
7945 
7946  !-----if max iteration count exceeded, then exit with error
7947  IF ( iter .GT. max_iter ) THEN
7948  WRITE(0,'(/A)') &
7949  'GETPQR -- ERROR: exceeded max iteration count'
7950  WRITE(0,'(A,2E24.16)') 'GETPQR - DEST POINT COORDS: ',xt,yt
7951  DO k=1,4
7952  WRITE(0,'(A,I1,A,2E24.16)') &
7953  'GETPQR - SRC POINT ',k,': ',xs(k),ys(k)
7954  END DO
7955  WRITE(0,'(A,4E24.16)') &
7956  'GETPQR - CURRENT PR,QR,DELP,DELQ: ',pr,qr,delp,delq
7957  CALL extcde (1)
7958  END IF !(ITER.LE.MAX_ITER)
7959 
7960  END SUBROUTINE getpqr
7961  !/
7962  !/ ------------------------------------------------------------------- /
7963  !/
7964  SUBROUTINE getblc( GSU, I, J, PR, QR, LCMP, NS, LS, IS, JS, CS )
7965  ! *** INTERNAL SUBROUTINE ***
7966  ! Compute bilinear remap factors for a given point (P,Q)
7967  ! (I,J) = lower-left corner point of grid cell containing target point
7968  ! (PR,QR) = cell-relative coordinate of target point
7969  ! Double precision interface
7970  TYPE(t_gsu), INTENT(IN) :: gsu
7971  INTEGER, INTENT(IN) :: i, j
7972  REAL(8), INTENT(IN) :: pr, qr
7973  LOGICAL, INTENT(IN) :: lcmp
7974  INTEGER, INTENT(OUT) :: ns
7975  LOGICAL, POINTER, INTENT(INOUT) :: ls(:)
7976  INTEGER, POINTER, INTENT(INOUT) :: is(:), js(:)
7977  REAL(8), POINTER, INTENT(INOUT) :: cs(:)
7978 
7979  ! Local parameters
7980  LOGICAL :: ijg, llg, lclo
7981  INTEGER :: iclo, gkind
7982  INTEGER :: lbx, lby, ubx, uby, nx, ny
7983  INTEGER :: istat, k
7984  !
7985  !---- initialize
7986  IF ( .NOT.ASSOCIATED(gsu%PTR) ) THEN
7987  WRITE(0,'(/2A/)') 'GETBLC ERROR -- ', &
7988  'grid search utility object not created'
7989  CALL extcde (1)
7990  END IF
7991  ijg = gsu%PTR%IJG
7992  llg = gsu%PTR%LLG
7993  iclo = gsu%PTR%ICLO
7994  lclo = gsu%PTR%LCLO
7995  gkind = gsu%PTR%GKIND
7996  lbx = gsu%PTR%LBX; lby = gsu%PTR%LBY;
7997  ubx = gsu%PTR%UBX; uby = gsu%PTR%UBY;
7998  nx = gsu%PTR%NX; ny = gsu%PTR%NY;
7999  !
8000  !---- check & deallocate
8001  IF ( ASSOCIATED(ls) ) THEN
8002  DEALLOCATE(ls); NULLIFY(ls);
8003  END IF
8004  IF ( ASSOCIATED(is) ) THEN
8005  DEALLOCATE(is); NULLIFY(is);
8006  END IF
8007  IF ( ASSOCIATED(js) ) THEN
8008  DEALLOCATE(js); NULLIFY(js);
8009  END IF
8010  IF ( ASSOCIATED(cs) ) THEN
8011  DEALLOCATE(cs); NULLIFY(cs);
8012  END IF
8013  !
8014  !---- set number of interpolation points and allocate arrays
8015  ns = 4
8016  ALLOCATE( ls(ns), is(ns), js(ns), cs(ns), stat=istat )
8017  IF ( istat .NE. 0 ) THEN
8018  WRITE(0,'(/1A,1A/)') 'GETBLC ERROR -- ', &
8019  'array allocation failed'
8020  CALL extcde (istat)
8021  END IF
8022  ls(:) = .true.
8023  cs(:) = zero
8024  !
8025  !---- 4 source points for the bilinear interpolation
8026  ! (4)------------------(3)
8027  ! | |
8028  ! | PR |
8029  ! |-----. |
8030  ! | | |
8031  ! | |QR |
8032  ! | | |
8033  ! (1)------------------(2)
8034  is(1) = i ; js(1) = j ;
8035  is(2) = i+1; js(2) = j ;
8036  is(3) = i+1; js(3) = j+1;
8037  is(4) = i ; js(4) = j+1;
8038  !
8039  !---- apply index closure
8040  DO k=1,ns
8041  IF ( mod(iclo,2).EQ.0 ) &
8042  is(k) = lbx + mod(nx - 1 + mod(is(k) - lbx + 1, nx), nx)
8043  IF ( mod(iclo,3).EQ.0 ) &
8044  js(k) = lby + mod(ny - 1 + mod(js(k) - lby + 1, ny), ny)
8045  IF ( iclo.EQ.iclo_trpl .AND. js(k).GT.uby ) THEN
8046  is(k) = ubx + lbx - is(k)
8047  js(k) = 2*uby - js(k) + 1
8048  END IF
8049  END DO
8050  !
8051  !---- calculate bilinear interpolation coefficients
8052  IF ( lcmp ) THEN
8053  cs(1) = (one-pr)*(one-qr)
8054  cs(2) = pr*(one-qr)
8055  cs(3) = pr*qr
8056  cs(4) = (one-pr)*qr
8057  END IF
8058 
8059  END SUBROUTINE getblc
8060  !/
8061  !/ ------------------------------------------------------------------- /
8062  !/
8063  SUBROUTINE getbcc( GSU, I, J, PR, QR, LCMP, NS, LS, IS, JS, CS )
8064  ! *** INTERNAL SUBROUTINE ***
8065  ! Compute bicubic remap factors for a given point (P,Q)
8066  ! (I,J) = lower-left corner point of grid cell containing target point
8067  ! (PR,QR) = cell-relative coordinate of target point
8068  TYPE(t_gsu), INTENT(IN) :: gsu
8069  INTEGER, INTENT(IN) :: i, j
8070  REAL(8), INTENT(IN) :: pr, qr
8071  LOGICAL, INTENT(IN) :: lcmp
8072  INTEGER, INTENT(OUT) :: ns
8073  LOGICAL, POINTER, INTENT(INOUT) :: ls(:)
8074  INTEGER, POINTER, INTENT(INOUT) :: is(:), js(:)
8075  REAL(8), POINTER, INTENT(INOUT) :: cs(:)
8076 
8077  ! Local parameters
8078  REAL(8), PARAMETER :: small = 1d-6
8079  LOGICAL :: ijg, llg, lclo
8080  INTEGER :: iclo, gkind
8081  INTEGER :: lbx, lby, ubx, uby, nx, ny
8082  INTEGER :: istat, p, q, ii, jj, k, l, n, m
8083  REAL(8) :: pv(0:3), qv(0:3), pw(0:3), qw(0:3)
8084  REAL(8) :: a(0:1,0:1,0:3)
8085  REAL(8) :: w(0:3,0:3) = reshape((/ 1, 0, -3, 2, &
8086  0, 0, 3, -2, &
8087  0, 1, -2, 1, &
8088  0, 0, -1, 1 /), &
8089  (/4,4/))
8090  INTEGER, PARAMETER :: nfd = 2 ! finite-difference order (even)
8091  INTEGER :: kfd(0:nfd,0:nfd) = reshape((/ 0, 1, 2, &
8092  -1, 0, 1, &
8093  -2, -1, 0 /), &
8094  (/nfd+1,nfd+1/))
8095  REAL(8) :: cfd(0:nfd,0:nfd) = half* reshape((/ -3, 4, -1, &
8096  -1, 0, 1, &
8097  1, -4, 3 /), &
8098  (/nfd+1,nfd+1/))
8099  REAL(8) :: cs2d(-nfd/2:nfd,-nfd/2:nfd)
8100  !
8101  !---- initialize
8102  IF ( .NOT.ASSOCIATED(gsu%PTR) ) THEN
8103  WRITE(0,'(/2A/)') 'GETBCC ERROR -- ', &
8104  'grid search utility object not created'
8105  CALL extcde (1)
8106  END IF
8107  ijg = gsu%PTR%IJG
8108  llg = gsu%PTR%LLG
8109  iclo = gsu%PTR%ICLO
8110  lclo = gsu%PTR%LCLO
8111  gkind = gsu%PTR%GKIND
8112  lbx = gsu%PTR%LBX; lby = gsu%PTR%LBY;
8113  ubx = gsu%PTR%UBX; uby = gsu%PTR%UBY;
8114  nx = gsu%PTR%NX; ny = gsu%PTR%NY;
8115  !
8116  !---- check & deallocate
8117  IF ( ASSOCIATED(ls) ) THEN
8118  DEALLOCATE(ls); NULLIFY(ls);
8119  END IF
8120  IF ( ASSOCIATED(is) ) THEN
8121  DEALLOCATE(is); NULLIFY(is);
8122  END IF
8123  IF ( ASSOCIATED(js) ) THEN
8124  DEALLOCATE(js); NULLIFY(js);
8125  END IF
8126  IF ( ASSOCIATED(cs) ) THEN
8127  DEALLOCATE(cs); NULLIFY(cs);
8128  END IF
8129  !
8130  !---- setup table of bicubic coefficients
8131  !
8132  ! (0,1)----------------(1,1)
8133  ! | |
8134  ! | |
8135  ! |-----x(Pr,Qr) |
8136  ! | | |
8137  ! | | |
8138  ! | | |
8139  ! (0,0)----------------(1,0)
8140  !
8141  ! Pv = [ Pr**0, Pr**1, Pr**2, Pr**3 ]^t
8142  ! Qv = [ Qr**0, Qr**1, Qr**2, Qr**3 ]^t
8143  !
8144  ! Pw = W*Pv
8145  ! Qw = W*Qv
8146  !
8147  ! A(i,j,0) = Pw(i )*Qw(j )
8148  ! A(i,j,1) = Pw(i+2)*Qw(j )
8149  ! A(i,j,2) = Pw(i )*Qw(j+2)
8150  ! A(i,j,3) = Pw(i+2)*Qw(j+2)
8151  !
8152  ! F(Pr,Qr) = SUM[i=0:1]{ SUM[j=0:1]{
8153  ! A(i,j,0) * F(i,j) +
8154  ! A(i,j,1) * Fp(i,j) +
8155  ! A(i,j,2) * Fq(i,j) +
8156  ! A(i,j,3) * Fpq(i,j) } }
8157  !
8158  DO k=0,3
8159  pv(k) = pr**k
8160  qv(k) = qr**k
8161  END DO
8162  pw = matmul(pv,w)
8163  qw = matmul(qv,w)
8164  DO jj=0,1
8165  DO ii=0,1
8166  a(ii,jj,0) = pw(ii) *qw(jj)
8167  a(ii,jj,1) = pw(ii+2)*qw(jj)
8168  a(ii,jj,2) = pw(ii) *qw(jj+2)
8169  a(ii,jj,3) = pw(ii+2)*qw(jj+2)
8170  END DO
8171  END DO
8172  !
8173  !---- source points for the bicubic interpolation
8174  ! The additional points are needed to construct derivatives (centered in space).
8175  ! If boundary points are not available one sided finite differences are used.
8176  !
8177  ! (-1, 2).... (0, 2).....(1, 2).....(2, 2)
8178  ! . . . .
8179  ! . . . .
8180  ! . . . .
8181  ! . . . .
8182  ! . . . .
8183  ! (-1, 1).....(0, 1)-----(1, 1).....(2, 1)
8184  ! . | | .
8185  ! . | Pr | .
8186  ! . |----x | .
8187  ! . | |Qr | .
8188  ! . | | | .
8189  ! (-1, 0).....(0, 0)-----(1, 0).....(2, 0)
8190  ! . . . .
8191  ! . . . .
8192  ! . . . .
8193  ! . . . .
8194  ! . . . .
8195  ! (-1,-1).....(0,-1).....(1,-1).....(2,-1)
8196  !
8197  ! Fp(i,j) = SUM[n=0:NFD]{ CFD(n,l)*F(i+KFD(n,l),j) }
8198  ! Fq(i,j) = SUM[n=0:NFD]{ CFD(n,k)*F(i,j+KFD(n,k)) }
8199  ! Fpq(i,j) = SUM[n=0:NFD]{ SUM[m=0:NFD]{
8200  ! CFD(n,l)*CFD(m,k)*F(i+KFD(n,l),j+KFD(m,k)) } }
8201  !
8202  ! (i,j) = (0,0),(1,0),(1,1),(0,1)
8203  ! l or k = 0 : one-sided finite-difference (left)
8204  ! l or k = 1 : centered finite-difference
8205  ! l or k = 2 : one-sided finite-difference (right)
8206  !
8207  cs2d = zero
8208  DO jj=0,1
8209  DO ii=0,1
8210  p = i + ii
8211  q = j + jj
8212  IF ( mod(iclo,2).EQ.0 ) THEN
8213  k = nfd/2
8214  ELSE
8215  IF (p-lbx.LT.nfd/2) THEN
8216  k = p - lbx
8217  ELSE IF (ubx-p.LT.nfd/2) THEN
8218  k = nfd + p - ubx
8219  ELSE
8220  k = nfd/2
8221  END IF
8222  END IF
8223  IF ( mod(iclo,3).EQ.0 ) THEN
8224  l = nfd/2
8225  ELSE IF ( iclo.EQ.iclo_trpl ) THEN
8226  IF (q-lby.LT.nfd/2) THEN
8227  l = q - lby
8228  ELSE
8229  l = nfd/2
8230  END IF
8231  ELSE
8232  IF (q-lby.LT.nfd/2) THEN
8233  l = q - lby
8234  ELSE IF (uby-q.LT.nfd/2) THEN
8235  l = nfd + q - uby
8236  ELSE
8237  l = nfd/2
8238  END IF
8239  END IF
8240  cs2d(ii,jj) = cs2d(ii,jj) + a(ii,jj,0)
8241  DO n=0,nfd
8242  cs2d(ii+kfd(n,k),jj) = cs2d(ii+kfd(n,k),jj) &
8243  + a(ii,jj,1)*cfd(n,k)
8244  cs2d(ii,jj+kfd(n,l)) = cs2d(ii,jj+kfd(n,l)) &
8245  + a(ii,jj,2)*cfd(n,l)
8246  DO m=0,nfd
8247  cs2d(ii+kfd(n,k),jj+kfd(m,l)) = &
8248  cs2d(ii+kfd(n,k),jj+kfd(m,l)) &
8249  + a(ii,jj,3)*cfd(n,k)*cfd(m,l)
8250  END DO
8251  END DO
8252  END DO
8253  END DO
8254  !
8255  !---- set number of interpolation points and allocate arrays
8256  ns = count( abs(cs2d) .GT. small )
8257  ALLOCATE( ls(ns), is(ns), js(ns), cs(ns), stat=istat )
8258  IF ( istat .NE. 0 ) THEN
8259  WRITE(0,'(/1A,1A/)') 'GETBCC ERROR -- ', &
8260  'array allocation failed'
8261  CALL extcde (istat)
8262  END IF
8263  ls(:) = .true.
8264  cs(:) = zero
8265  !
8266  !---- load arrays and apply index closure
8267  ns = 0
8268  DO jj=-nfd/2,nfd
8269  DO ii=-nfd/2,nfd
8270  IF ( abs(cs2d(ii,jj)) .GT. small ) THEN
8271  ns = ns + 1
8272  is(ns) = i + ii
8273  js(ns) = j + jj
8274  cs(ns) = cs2d(ii,jj)
8275  IF ( mod(iclo,2).EQ.0 ) &
8276  is(ns) = lbx + mod(nx - 1 + mod(is(ns) - lbx + 1, nx), nx)
8277  IF ( mod(iclo,3).EQ.0 ) &
8278  js(ns) = lby + mod(ny - 1 + mod(js(ns) - lby + 1, ny), ny)
8279  IF ( iclo.EQ.iclo_trpl .AND. js(ns).GT.uby ) THEN
8280  is(ns) = ubx + lbx - is(ns)
8281  js(ns) = 2*uby - js(ns) + 1
8282  END IF
8283  END IF
8284  END DO
8285  END DO
8286 
8287  END SUBROUTINE getbcc
8288  !/
8289  !/ ------------------------------------------------------------------- /
8290  !/
8291  SUBROUTINE getgfc( GSU, I, J, PR, QR, WIDTH, LCMP, NS, LS, IS, JS, CS )
8292  ! *** INTERNAL SUBROUTINE ***
8293  ! Compute gaussian filter remap factors for a given point (P,Q)
8294  ! (I,J) = lower-left corner point of grid cell containing target point
8295  ! (PR,QR) = cell-relative coordinate of target point
8296  ! Double precision interface
8297  TYPE(t_gsu), INTENT(IN) :: gsu
8298  INTEGER, INTENT(IN) :: i, j
8299  REAL(8), INTENT(IN) :: pr, qr
8300  REAL(8), INTENT(IN) :: width
8301  LOGICAL, INTENT(IN) :: lcmp
8302  INTEGER, INTENT(OUT) :: ns
8303  LOGICAL, POINTER, INTENT(INOUT) :: ls(:)
8304  INTEGER, POINTER, INTENT(INOUT) :: is(:), js(:)
8305  REAL(8), POINTER, INTENT(INOUT) :: cs(:)
8306 
8307  ! Local parameters
8308  ! Note, width (=nsig*sigma) is set to max(width,width_min)
8309  ! so that the filter includes at least one source point.
8310  REAL(8), PARAMETER :: nsig = 6.0d0
8311  REAL(8), PARAMETER :: width_min = 1.5d0
8312  LOGICAL :: ijg, llg, lclo
8313  INTEGER :: iclo, gkind
8314  INTEGER :: lbx, lby, ubx, uby, nx, ny
8315  INTEGER :: istat, k
8316  INTEGER :: ii, jj, imin, jmin, imax, jmax
8317  REAL(8) :: wdth, sig2, rmax, r2mx, sfac, r2, gij, gsum
8318  !
8319  !---- initialize
8320  IF ( .NOT.ASSOCIATED(gsu%PTR) ) THEN
8321  WRITE(0,'(/2A/)') 'GETBLC ERROR -- ', &
8322  'grid search utility object not created'
8323  CALL extcde (1)
8324  END IF
8325  ijg = gsu%PTR%IJG
8326  llg = gsu%PTR%LLG
8327  iclo = gsu%PTR%ICLO
8328  lclo = gsu%PTR%LCLO
8329  gkind = gsu%PTR%GKIND
8330  lbx = gsu%PTR%LBX; lby = gsu%PTR%LBY;
8331  ubx = gsu%PTR%UBX; uby = gsu%PTR%UBY;
8332  nx = gsu%PTR%NX; ny = gsu%PTR%NY;
8333  wdth = max(width,width_min)
8334  sig2 = (wdth/nsig)**2
8335  sfac = -0.5d0/sig2
8336  rmax = 0.5d0*wdth
8337  r2mx = rmax**2
8338  imin = int(min(zero,pr)-rmax)
8339  jmin = int(min(zero,qr)-rmax)
8340  imax = ceiling(max(zero,pr)+rmax)
8341  jmax = ceiling(max(zero,qr)+rmax)
8342  !
8343  !---- check & deallocate
8344  IF ( ASSOCIATED(ls) ) THEN
8345  DEALLOCATE(ls); NULLIFY(ls);
8346  END IF
8347  IF ( ASSOCIATED(is) ) THEN
8348  DEALLOCATE(is); NULLIFY(is);
8349  END IF
8350  IF ( ASSOCIATED(js) ) THEN
8351  DEALLOCATE(js); NULLIFY(js);
8352  END IF
8353  IF ( ASSOCIATED(cs) ) THEN
8354  DEALLOCATE(cs); NULLIFY(cs);
8355  END IF
8356  !
8357  !---- set number of interpolation points and allocate arrays
8358  ns = (imax-imin+1)*(jmax-jmin+1)
8359  ALLOCATE( ls(ns), is(ns), js(ns), cs(ns), stat=istat )
8360  IF ( istat .NE. 0 ) THEN
8361  WRITE(0,'(/1A,1A/)') 'GETGFC ERROR -- ', &
8362  'array allocation failed'
8363  CALL extcde (istat)
8364  END IF
8365  ls(:) = .false.
8366  cs(:) = zero
8367  !
8368  !---- calculate filter coefficients
8369  gsum = zero
8370  DO jj=jmin,jmax
8371  DO ii=imin,imax
8372  k = (imax-imin+1)*(jj-jmin) + ii - imin + 1
8373  !-------- source points for the filter
8374  is(k) = i + ii
8375  js(k) = j + jj
8376  !-------- apply index closure
8377  IF ( mod(iclo,2).EQ.0 ) &
8378  is(k) = lbx + mod(nx - 1 + mod(is(k) - lbx + 1, nx), nx)
8379  IF ( mod(iclo,3).EQ.0 ) &
8380  js(k) = lby + mod(ny - 1 + mod(js(k) - lby + 1, ny), ny)
8381  IF ( iclo.EQ.iclo_trpl .AND. js(k).GT.uby ) THEN
8382  is(k) = ubx + lbx - is(k)
8383  js(k) = 2*uby - js(k) + 1
8384  END IF
8385  !-------- skip if source point is outside domain
8386  IF ( is(k).LT.lbx .OR. is(k).GT.ubx ) cycle
8387  IF ( js(k).LT.lby .OR. js(k).GT.uby ) cycle
8388  !-------- compute distance
8389  r2 = (pr - ii)**2 + (qr - jj)**2
8390  ! IF ( R2.GT.R2MX ) CYCLE
8391  !-------- compute coefficient
8392  ls(k) = .true.
8393  IF ( lcmp ) THEN
8394  gij = exp( sfac*r2 )
8395  gsum = gsum + gij
8396  cs(k) = gij
8397  END IF
8398  END DO
8399  END DO
8400  IF ( lcmp ) THEN
8401  WHERE ( ls ) cs = cs/gsum
8402  END IF
8403 
8404  END SUBROUTINE getgfc
8405  !/
8406  !/ ------------------------------------------------------------------- /
8407  !/
8408 #define DXYDP_SINGLE_POINT_WIDE_CHANNEL_ERROR
8409 #undef DXYDP_SINGLE_POINT_WIDE_CHANNEL_WARNING
8410  SUBROUTINE dxydp( N, K, C, IJG, LLG, ICLO, &
8411  PTILED, QTILED, PRANGE, QRANGE, &
8412  LB, UB, P, Q, DXDP, DYDP, MASK, &
8413  X4, Y4, X8, Y8, RC )
8414  ! *** INTERNAL SUBROUTINE ***
8415  INTEGER, INTENT(IN) :: n
8416  INTEGER, INTENT(IN) :: k(0:n,0:n,1:n)
8417  REAL(8), INTENT(IN) :: c(0:n,0:n,1:n)
8418  LOGICAL, INTENT(IN) :: ijg
8419  LOGICAL, INTENT(IN) :: llg
8420  INTEGER, INTENT(IN) :: iclo
8421  LOGICAL, INTENT(IN) :: ptiled, qtiled
8422  INTEGER, INTENT(IN) :: prange(2), qrange(2)
8423  INTEGER, INTENT(IN) :: lb(2), ub(2)
8424  INTEGER, INTENT(IN) :: p, q
8425  REAL(8), INTENT(OUT) :: dxdp, dydp
8426  LOGICAL, INTENT(IN), OPTIONAL :: mask(lb(1):ub(1),lb(2):ub(2))
8427  REAL(4), INTENT(IN), OPTIONAL :: x4(lb(1):ub(1),lb(2):ub(2))
8428  REAL(4), INTENT(IN), OPTIONAL :: y4(lb(1):ub(1),lb(2):ub(2))
8429  REAL(8), INTENT(IN), OPTIONAL :: x8(lb(1):ub(1),lb(2):ub(2))
8430  REAL(8), INTENT(IN), OPTIONAL :: y8(lb(1):ub(1),lb(2):ub(2))
8431  INTEGER, INTENT(OUT), OPTIONAL :: rc
8432 
8433  ! Local parameters
8434  INTEGER, PARAMETER :: m = 1 ! order of derivative
8435  LOGICAL, PARAMETER :: debug = .false.
8436  CHARACTER(64) :: fstr
8437  LOGICAL :: comp_m, type_r4, type_r8
8438  INTEGER :: ihem
8439  INTEGER :: np, nq, lbp, lbq, ubp, ubq, p0, q0
8440  INTEGER :: istat=0, i, l, ii, ni, ii0, iin
8441  INTEGER :: kp(0:n), kq(0:n)
8442  LOGICAL :: mp(0:n)
8443  REAL(8) :: xp(0:n)
8444  REAL(8) :: yp(0:n)
8445  REAL(8) :: up(0:n)
8446  REAL(8) :: vp(0:n)
8447  REAL(8) :: x0, y0, lon0, lat0, c0
8448  REAL(8) :: d1dp, d2dp
8449  !
8450  ! -------------------------------------------------------------------- /
8451  ! 1. Check and setup inputs
8452  !
8453  IF ( PRESENT(rc) ) rc = 0
8454 
8455  type_r4 = PRESENT(x4).AND.PRESENT(y4)
8456  type_r8 = PRESENT(x8).AND.PRESENT(y8)
8457  IF ( .NOT.type_r4.AND..NOT.type_r8 ) THEN
8458  WRITE(0,'(/1A,1A/)') 'DXYDP ERROR -- ', &
8459  'no input grid coordinates specified'
8460  istat = 1
8461  IF ( PRESENT(rc) ) THEN
8462  rc = istat
8463  RETURN
8464  ELSE
8465  CALL extcde (istat)
8466  END IF
8467  END IF
8468 
8469  np = prange(2) - prange(1) + 1
8470  nq = qrange(2) - qrange(1) + 1
8471 
8472  IF ( ijg ) THEN
8473  lbp = lb(1); lbq = lb(2)
8474  ubp = ub(1); ubq = ub(2)
8475  ELSE
8476  lbp = lb(2); lbq = lb(1)
8477  ubp = ub(2); ubq = ub(1)
8478  END IF
8479 
8480  IF ( p.LT.lbp .OR. p.GT.ubp .OR. q.LT.lbq .OR. q.GT.ubq ) THEN
8481  WRITE(0,'(/1A,/1A,1L2,5I6,/1A,1L2,5I6/)') 'DXYDP ERROR -- '// &
8482  'input index coordinates outside input array bounds', &
8483  'DXYDP ERROR -- PTILED,PRANGE,P,LBP,UBP:',ptiled,prange,p,lbp,ubp, &
8484  'DXYDP ERROR -- QTILED,QRANGE,Q,LBQ,UBQ:',qtiled,qrange,q,lbq,ubq
8485  istat = 1
8486  IF ( PRESENT(rc) ) THEN
8487  rc = istat
8488  RETURN
8489  ELSE
8490  CALL extcde (istat)
8491  END IF
8492  END IF
8493 
8494  p0 = p
8495  q0 = q
8496  IF ( mod(iclo,2).EQ.0 ) &
8497  p0 = prange(1) + mod(np - 1 + mod(p0 - prange(1) + 1, np), np)
8498  IF ( mod(iclo,3).EQ.0 ) &
8499  q0 = qrange(1) + mod(nq - 1 + mod(q0 - qrange(1) + 1, nq), nq)
8500  IF ( iclo.EQ.iclo_trpl .AND. q0.GT.qrange(2) ) THEN
8501  p0 = prange(2) + prange(1) - p0
8502  q0 = 2*qrange(2) - q0 + 1
8503  END IF
8504  IF ( p0.LT.prange(1) .OR. p0.GT.prange(2) .OR. &
8505  q0.LT.qrange(1) .OR. q0.GT.qrange(2) ) THEN
8506  WRITE(0,'(/1A,/1A,4I6,/1A,4I6/)') 'DXYDP ERROR -- '// &
8507  'shifted input index coordinates outside allowed range', &
8508  'DXYDP ERROR -- PRANGE,P,P0:',prange,p,p0, &
8509  'DXYDP ERROR -- QRANGE,Q,Q0:',qrange,q,q0
8510  istat = 1
8511  IF ( PRESENT(rc) ) THEN
8512  rc = istat
8513  RETURN
8514  ELSE
8515  CALL extcde (istat)
8516  END IF
8517  END IF
8518 
8519  dxdp = zero
8520  dydp = zero
8521  comp_m = PRESENT(mask)
8522  IF ( comp_m ) THEN
8523  IF ( ijg ) THEN
8524  IF ( mask(p0,q0) ) RETURN
8525  ELSE
8526  IF ( mask(q0,p0) ) RETURN
8527  END IF
8528  END IF
8529  !
8530  ! -------------------------------------------------------------------- /
8531  ! 2. Compute DX/DP & DY/DP
8532  !
8533  IF ( mod(iclo,2).EQ.0 ) THEN
8534  i = n/2
8535  ELSE
8536  IF (p0-prange(1).LT.n/2) THEN
8537  i = p0 - prange(1)
8538  ELSE IF (prange(2)-p0.LT.n/2) THEN
8539  i = n + p0 - prange(2)
8540  ELSE
8541  i = n/2
8542  END IF
8543  END IF
8544 
8545  kp(:) = p + k(:,i,n)
8546  kq(:) = q
8547  IF ( .NOT.ptiled ) THEN
8548  IF ( mod(iclo,2).EQ.0 ) THEN
8549  kp = prange(1) + mod(np - 1 + mod(kp - prange(1) + 1, np), np)
8550  END IF
8551  END IF
8552 
8553  IF ( minval(kp).LT.lbp .OR. maxval(kp).GT.ubp .OR. &
8554  minval(kq).LT.lbq .OR. maxval(kq).GT.ubq ) THEN
8555  WRITE(0,'(/1A,/1A,1L2,8I6,/1A,1L2,8I6/)') 'DXYDP ERROR -- '// &
8556  'stencil index coordinates outside array bounds', &
8557  'DXYDP ERROR -- PTILED,PRANGE,P,P0,LBP,UBP,PMIN,PMAX:', &
8558  ptiled,prange,p,p0,lbp,ubp,minval(kp),maxval(kp), &
8559  'DXYDP ERROR -- QTILED,QRANGE,Q,Q0,LBQ,UBQ,QMIN,QMAX:', &
8560  qtiled,qrange,q,q0,lbq,ubq,minval(kq),maxval(kq)
8561  istat = 1
8562  IF ( PRESENT(rc) ) THEN
8563  rc = istat
8564  RETURN
8565  ELSE
8566  CALL extcde (istat)
8567  END IF
8568  END IF
8569 
8570  DO l = 0, n
8571  IF ( ijg ) THEN
8572  IF ( comp_m ) mp(l) = mask(kp(l),kq(l))
8573  IF ( type_r4 ) THEN
8574  xp(l) = x4(kp(l),kq(l))
8575  yp(l) = y4(kp(l),kq(l))
8576  ELSE
8577  xp(l) = x8(kp(l),kq(l))
8578  yp(l) = y8(kp(l),kq(l))
8579  END IF
8580  ELSE
8581  IF ( comp_m ) mp(l) = mask(kq(l),kp(l))
8582  IF ( type_r4 ) THEN
8583  xp(l) = x4(kq(l),kp(l))
8584  yp(l) = y4(kq(l),kp(l))
8585  ELSE
8586  xp(l) = x8(kq(l),kp(l))
8587  yp(l) = y8(kq(l),kp(l))
8588  END IF
8589  END IF
8590  END DO
8591 
8592  ii = i
8593  ni = n
8594  ii0 = 0
8595  iin = n
8596  IF ( comp_m ) THEN
8597  DO l = i-1, 0, -1
8598  IF ( mp(l) ) THEN
8599  mp(0:l) = .true.
8600  EXIT
8601  END IF
8602  END DO
8603  DO l = i+1, n
8604  IF ( mp(l) ) THEN
8605  mp(l:n) = .true.
8606  EXIT
8607  END IF
8608  END DO
8609  ii = count(.NOT.mp(0:i)) - 1
8610  ni = count(.NOT.mp(0:n)) - 1
8611  ii0 = i - ii
8612  iin = ii0 + ni
8613  END IF
8614 #ifdef DXYDP_SINGLE_POINT_WIDE_CHANNEL_ERROR
8615  IF ( ni.LE.0 ) THEN
8616  WRITE(0,'(/1A,1A,4I6/)') 'DXYDP ERROR -- ', &
8617  'single point wide channel not allowed',p,q,p0,q0
8618  istat = 1
8619  IF ( PRESENT(rc) ) THEN
8620  rc = istat
8621  RETURN
8622  ELSE
8623  CALL extcde (istat)
8624  END IF
8625  END IF
8626 #endif
8627 
8628  IF ( ni.GT.0 ) THEN
8629  IF ( llg ) THEN
8630 #define DXYDP_USE_SPLX
8631 #ifdef DXYDP_USE_SPLX
8632  IF ( ijg ) THEN
8633  IF ( type_r4 ) THEN
8634  x0 = x4(p,q); y0 = y4(p,q);
8635  ELSE
8636  x0 = x8(p,q); y0 = y8(p,q);
8637  END IF
8638  ELSE
8639  IF ( type_r4 ) THEN
8640  x0 = x4(q,p); y0 = y4(q,p);
8641  ELSE
8642  x0 = x8(q,p); y0 = y8(q,p);
8643  END IF
8644  END IF
8645  ihem = 1; IF (maxval(yp(ii0:iin)).LT.zero) ihem = -1;
8646  lon0 = zero; lat0 = sign(d90,real(ihem,8));
8647  c0 = d90 - abs(y0)
8648  CALL w3splx(lon0,lat0,c0,xp(ii0:iin),yp(ii0:iin), &
8649  up(ii0:iin),vp(ii0:iin))
8650  d1dp = dot_product(c(0:ni,ii,ni),up(ii0:iin))
8651  d2dp = dot_product(c(0:ni,ii,ni),vp(ii0:iin))
8652  CALL spddp(lon0,c0,ihem,x0,y0,d1dp,d2dp,dxdp,dydp)
8653 #else
8654  dxdp = dot_product(c(0:ni,ii,ni),xp(ii0:iin))
8655  dydp = dot_product(c(0:ni,ii,ni),yp(ii0:iin))
8656 #endif
8657  ELSE !.NOT.LLG
8658  dxdp = dot_product(c(0:ni,ii,ni),xp(ii0:iin))
8659  dydp = dot_product(c(0:ni,ii,ni),yp(ii0:iin))
8660  END IF !.NOT.LLG
8661  IF ( debug ) THEN
8662  WRITE(fstr,'(A,I0,A,I0,A)') &
8663  '(/1A,12I8,5(/1A,2E16.8),/1A,', &
8664  ni+1,'I16,3(/1A,',ni+1,'E16.8))'
8665  WRITE(*,trim(fstr)) &
8666  'DXYDP -- PRANGE,QRANGE,P,Q,P0,Q0,NI,II,II0,IIN:',&
8667  prange,qrange,p,q,p0,q0,ni,ii,ii0,iin, &
8668  'DXYDP -- X0, Y0:',x0,y0, &
8669  'DXYDP -- LON0,LAT0:',lon0,lat0, &
8670  'DXYDP -- C0,IHEM:',c0,real(ihem), &
8671  'DXYDP -- D1DP,D2DP:',d1dp,d2dp, &
8672  'DXYDP -- DXDP,DYDP:',dxdp,dydp, &
8673  'DXYDP -- K:', k(0:ni,ii,ni), &
8674  'DXYDP -- C:', c(0:ni,ii,ni), &
8675  'DXYDP -- XP:',xp(ii0:iin), &
8676  'DXYDP -- YP:',yp(ii0:iin)
8677  END IF
8678  ELSE
8679 #ifdef DXYDP_SINGLE_POINT_WIDE_CHANNEL_WARNING
8680  WRITE(0,'(/1A,1A,4I6/)') 'DXYDP WARNING -- ', &
8681  'single point wide channel, DXDP & DYDP set to zero:',p,q,p0,q0
8682 #endif
8683  dxdp = zero
8684  dydp = zero
8685  END IF
8686 
8687  END SUBROUTINE dxydp
8688  !/
8689  !/ ------------------------------------------------------------------- /
8690  !/
8691 #define DXYDQ_SINGLE_POINT_WIDE_CHANNEL_ERROR
8692 #undef DXYDQ_SINGLE_POINT_WIDE_CHANNEL_WARNING
8693  SUBROUTINE dxydq( N, K, C, IJG, LLG, ICLO, &
8694  PTILED, QTILED, PRANGE, QRANGE, &
8695  LB, UB, P, Q, DXDQ, DYDQ, MASK, &
8696  X4, Y4, X8, Y8, RC )
8697  ! *** INTERNAL SUBROUTINE ***
8698  INTEGER, INTENT(IN) :: n
8699  INTEGER, INTENT(IN) :: k(0:n,0:n,1:n)
8700  REAL(8), INTENT(IN) :: c(0:n,0:n,1:n)
8701  LOGICAL, INTENT(IN) :: ijg
8702  LOGICAL, INTENT(IN) :: llg
8703  INTEGER, INTENT(IN) :: iclo
8704  LOGICAL, INTENT(IN) :: ptiled, qtiled
8705  INTEGER, INTENT(IN) :: prange(2), qrange(2)
8706  INTEGER, INTENT(IN) :: lb(2), ub(2)
8707  INTEGER, INTENT(IN) :: p, q
8708  REAL(8), INTENT(OUT) :: dxdq, dydq
8709  LOGICAL, INTENT(IN), OPTIONAL :: mask(lb(1):ub(1),lb(2):ub(2))
8710  REAL(4), INTENT(IN), OPTIONAL :: x4(lb(1):ub(1),lb(2):ub(2))
8711  REAL(4), INTENT(IN), OPTIONAL :: y4(lb(1):ub(1),lb(2):ub(2))
8712  REAL(8), INTENT(IN), OPTIONAL :: x8(lb(1):ub(1),lb(2):ub(2))
8713  REAL(8), INTENT(IN), OPTIONAL :: y8(lb(1):ub(1),lb(2):ub(2))
8714  INTEGER, INTENT(OUT), OPTIONAL :: rc
8715 
8716  ! Local parameters
8717  INTEGER, PARAMETER :: m = 1 ! order of derivative
8718  LOGICAL, PARAMETER :: debug = .false.
8719  CHARACTER(64) :: fstr
8720  LOGICAL :: comp_m, type_r4, type_r8
8721  INTEGER :: ihem
8722  INTEGER :: np, nq, lbp, lbq, ubp, ubq, p0, q0
8723  INTEGER :: istat=0, j, l, jj, nj, jj0, jjn
8724  INTEGER :: kp(0:n), kq(0:n)
8725  LOGICAL :: mq(0:n)
8726  REAL(8) :: xq(0:n)
8727  REAL(8) :: yq(0:n)
8728  REAL(8) :: uq(0:n)
8729  REAL(8) :: vq(0:n)
8730  REAL(8) :: x0, y0, lon0, lat0, c0
8731  REAL(8) :: d1dq, d2dq
8732  !
8733  ! -------------------------------------------------------------------- /
8734  ! 1. Check and setup inputs
8735  !
8736  IF ( PRESENT(rc) ) rc = 0
8737 
8738  type_r4 = PRESENT(x4).AND.PRESENT(y4)
8739  type_r8 = PRESENT(x8).AND.PRESENT(y8)
8740  IF ( .NOT.type_r4.AND..NOT.type_r8 ) THEN
8741  WRITE(0,'(/1A,1A/)') 'DXYDQ ERROR -- ', &
8742  'no input grid coordinates specified'
8743  istat = 1
8744  IF ( PRESENT(rc) ) THEN
8745  rc = istat
8746  RETURN
8747  ELSE
8748  CALL extcde (istat)
8749  END IF
8750  END IF
8751 
8752  np = prange(2) - prange(1) + 1
8753  nq = qrange(2) - qrange(1) + 1
8754 
8755  IF ( ijg ) THEN
8756  lbp = lb(1); lbq = lb(2)
8757  ubp = ub(1); ubq = ub(2)
8758  ELSE
8759  lbp = lb(2); lbq = lb(1)
8760  ubp = ub(2); ubq = ub(1)
8761  END IF
8762 
8763  IF ( p.LT.lbp .OR. p.GT.ubp .OR. q.LT.lbq .OR. q.GT.ubq ) THEN
8764  WRITE(0,'(/1A,/1A,1L2,5I6,/1A,1L2,5I6/)') 'DXYDQ ERROR -- '// &
8765  'input index coordinates outside input array bounds', &
8766  'DXYDQ ERROR -- PTILED,PRANGE,P,LBP,UBP:',ptiled,prange,p,lbp,ubp, &
8767  'DXYDQ ERROR -- QTILED,QRANGE,Q,LBQ,UBQ:',qtiled,qrange,q,lbq,ubq
8768  istat = 1
8769  IF ( PRESENT(rc) ) THEN
8770  rc = istat
8771  RETURN
8772  ELSE
8773  CALL extcde (istat)
8774  END IF
8775  END IF
8776 
8777  p0 = p
8778  q0 = q
8779  IF ( mod(iclo,2).EQ.0 ) &
8780  p0 = prange(1) + mod(np - 1 + mod(p0 - prange(1) + 1, np), np)
8781  IF ( mod(iclo,3).EQ.0 ) &
8782  q0 = qrange(1) + mod(nq - 1 + mod(q0 - qrange(1) + 1, nq), nq)
8783  IF ( iclo.EQ.iclo_trpl .AND. q0.GT.qrange(2) ) THEN
8784  p0 = prange(2) + prange(1) - p0
8785  q0 = 2*qrange(2) - q0 + 1
8786  END IF
8787  IF ( p0.LT.prange(1) .OR. p0.GT.prange(2) .OR. &
8788  q0.LT.qrange(1) .OR. q0.GT.qrange(2) ) THEN
8789  WRITE(0,'(/1A,/1A,4I6,/1A,4I6/)') 'DXYDQ ERROR -- '// &
8790  'shifted input index coordinates outside allowed range', &
8791  'DXYDQ ERROR -- PRANGE,P,P0:',prange,p,p0, &
8792  'DXYDQ ERROR -- QRANGE,Q,Q0:',qrange,q,q0
8793  istat = 1
8794  IF ( PRESENT(rc) ) THEN
8795  rc = istat
8796  RETURN
8797  ELSE
8798  CALL extcde (istat)
8799  END IF
8800  END IF
8801 
8802  dxdq = zero
8803  dydq = zero
8804  comp_m = PRESENT(mask)
8805  IF ( comp_m ) THEN
8806  IF ( ijg ) THEN
8807  IF ( mask(p0,q0) ) RETURN
8808  ELSE
8809  IF ( mask(q0,p0) ) RETURN
8810  END IF
8811  END IF
8812  !
8813  ! -------------------------------------------------------------------- /
8814  ! 2. Compute DX/DQ & DY/DQ
8815  !
8816  IF ( mod(iclo,3).EQ.0 ) THEN
8817  j = n/2
8818  ELSE IF ( iclo.EQ.iclo_trpl ) THEN
8819  IF (q0-qrange(1).LT.n/2) THEN
8820  j = q0 - qrange(1)
8821  ELSE
8822  j = n/2
8823  END IF
8824  ELSE
8825  IF (q0-qrange(1).LT.n/2) THEN
8826  j = q0 - qrange(1)
8827  ELSE IF (qrange(2)-q0.LT.n/2) THEN
8828  j = n + q0 - qrange(2)
8829  ELSE
8830  j = n/2
8831  END IF
8832  END IF
8833 
8834  kp(:) = p
8835  kq(:) = q + k(:,j,n)
8836  IF ( .NOT.qtiled ) THEN
8837  IF ( mod(iclo,3).EQ.0 ) THEN
8838  kq = qrange(1) + mod(nq - 1 + mod(kq - qrange(1) + 1, nq), nq)
8839  END IF
8840  IF ( iclo.EQ.iclo_trpl .AND. .NOT.ptiled ) THEN
8841  WHERE ( kq.GT.qrange(2) )
8842  kp = prange(2) + prange(1) - kp
8843  kq = 2*qrange(2) - kq + 1
8844  END WHERE
8845  END IF
8846  END IF
8847 
8848  IF ( minval(kp).LT.lbp .OR. maxval(kp).GT.ubp .OR. &
8849  minval(kq).LT.lbq .OR. maxval(kq).GT.ubq ) THEN
8850  WRITE(0,'(/1A,/1A,1L2,8I6,/1A,1L2,8I6/)') 'DXYDQ ERROR -- '// &
8851  'stencil index coordinates outside array bounds', &
8852  'DXYDQ ERROR -- PTILED,PRANGE,P,P0,LBP,UBP,PMIN,PMAX:', &
8853  ptiled,prange,p,p0,lbp,ubp,minval(kp),maxval(kp), &
8854  'DXYDQ ERROR -- QTILED,QRANGE,Q,Q0,LBQ,UBQ,QMIN,QMAX:', &
8855  qtiled,qrange,q,q0,lbq,ubq,minval(kq),maxval(kq)
8856  istat = 1
8857  IF ( PRESENT(rc) ) THEN
8858  rc = istat
8859  RETURN
8860  ELSE
8861  CALL extcde (istat)
8862  END IF
8863  END IF
8864 
8865  DO l = 0, n
8866  IF ( ijg ) THEN
8867  IF ( comp_m ) mq(l) = mask(kp(l),kq(l))
8868  IF ( type_r4 ) THEN
8869  xq(l) = x4(kp(l),kq(l))
8870  yq(l) = y4(kp(l),kq(l))
8871  ELSE
8872  xq(l) = x8(kp(l),kq(l))
8873  yq(l) = y8(kp(l),kq(l))
8874  END IF
8875  ELSE
8876  IF ( comp_m ) mq(l) = mask(kq(l),kp(l))
8877  IF ( type_r4 ) THEN
8878  xq(l) = x4(kq(l),kp(l))
8879  yq(l) = y4(kq(l),kp(l))
8880  ELSE
8881  xq(l) = x8(kq(l),kp(l))
8882  yq(l) = y8(kq(l),kp(l))
8883  END IF
8884  END IF
8885  END DO
8886 
8887  jj = j
8888  nj = n
8889  jj0 = 0
8890  jjn = n
8891  IF ( comp_m ) THEN
8892  DO l = j-1, 0, -1
8893  IF ( mq(l) ) THEN
8894  mq(0:l) = .true.
8895  EXIT
8896  END IF
8897  END DO
8898  DO l = j+1, n
8899  IF ( mq(l) ) THEN
8900  mq(l:n) = .true.
8901  EXIT
8902  END IF
8903  END DO
8904  jj = count(.NOT.mq(0:j)) - 1
8905  nj = count(.NOT.mq(0:n)) - 1
8906  jj0 = j - jj
8907  jjn = jj0 + nj
8908  END IF
8909 #ifdef DXYDQ_SINGLE_POINT_WIDE_CHANNEL_ERROR
8910  IF ( nj.LE.0 ) THEN
8911  WRITE(0,'(/1A,1A,4I6/)') 'DXYDQ ERROR -- ', &
8912  'single point wide channel not allowed',p,q,p0,q0
8913  istat = 1
8914  IF ( PRESENT(rc) ) THEN
8915  rc = istat
8916  RETURN
8917  ELSE
8918  CALL extcde (istat)
8919  END IF
8920  END IF
8921 #endif
8922 
8923  IF ( nj.GT.0 ) THEN
8924  IF ( llg ) THEN
8925 #define DXYDQ_USE_SPLX
8926 #ifdef DXYDQ_USE_SPLX
8927  IF ( ijg ) THEN
8928  IF ( type_r4 ) THEN
8929  x0 = x4(p,q); y0 = y4(p,q);
8930  ELSE
8931  x0 = x8(p,q); y0 = y8(p,q);
8932  END IF
8933  ELSE
8934  IF ( type_r4 ) THEN
8935  x0 = x4(q,p); y0 = y4(q,p);
8936  ELSE
8937  x0 = x8(q,p); y0 = y8(q,p);
8938  END IF
8939  END IF
8940  ihem = 1; IF (maxval(yq(jj0:jjn)).LT.zero) ihem = -1;
8941  lon0 = zero; lat0 = sign(d90,real(ihem,8));
8942  c0 = d90 - abs(y0)
8943  CALL w3splx(lon0,lat0,c0,xq(jj0:jjn),yq(jj0:jjn), &
8944  uq(jj0:jjn),vq(jj0:jjn))
8945  d1dq = dot_product(c(0:nj,jj,nj),uq(jj0:jjn))
8946  d2dq = dot_product(c(0:nj,jj,nj),vq(jj0:jjn))
8947  CALL spddq(lon0,c0,ihem,x0,y0,d1dq,d2dq,dxdq,dydq)
8948 #else
8949  dxdq = dot_product(c(0:nj,jj,nj),xq(jj0:jjn))
8950  dydq = dot_product(c(0:nj,jj,nj),yq(jj0:jjn))
8951 #endif
8952  ELSE !.NOT.LLG
8953  dxdq = dot_product(c(0:nj,jj,nj),xq(jj0:jjn))
8954  dydq = dot_product(c(0:nj,jj,nj),yq(jj0:jjn))
8955  END IF !.NOT.LLG
8956  IF ( debug ) THEN
8957  WRITE(fstr,'(A,I0,A,I0,A)') &
8958  '(/1A,12I8,5(/1A,2E16.8),/1A,', &
8959  nj+1,'I16,3(/1A,',nj+1,'E16.8))'
8960  WRITE(*,trim(fstr)) &
8961  'DXYDQ -- PRANGE,QRANGE,P,Q,P0,Q0,NJ,JJ,JJ0,JJN:',&
8962  prange,qrange,p,q,p0,q0,nj,jj,jj0,jjn, &
8963  'DXYDQ -- X0, Y0:',x0,y0, &
8964  'DXYDQ -- LON0,LAT0:',lon0,lat0, &
8965  'DXYDQ -- C0,IHEM:',c0,real(ihem), &
8966  'DXYDQ -- D1DQ,D1DQ:',d1dq,d1dq, &
8967  'DXYDQ -- DXDQ,DYDQ:',dxdq,dydq, &
8968  'DXYDQ -- K:', k(0:nj,jj,nj), &
8969  'DXYDQ -- C:', c(0:nj,jj,nj), &
8970  'DXYDQ -- XQ:',xq(jj0:jjn), &
8971  'DXYDQ -- YQ:',yq(jj0:jjn)
8972  END IF
8973  ELSE
8974 #ifdef DXYDQ_SINGLE_POINT_WIDE_CHANNEL_WARNING
8975  WRITE(0,'(/1A,1A,4I6/)') 'DXYDQ WARNING -- ', &
8976  'single point wide channel, DXDQ & DYDQ set to zero:',p,q,p0,q0
8977 #endif
8978  dxdq = zero
8979  dydq = zero
8980  END IF
8981 
8982  END SUBROUTINE dxydq
8983  !/
8984  !/ ------------------------------------------------------------------- /
8985  !/
8986  SUBROUTINE spddp( LAM0, C0, IHEM, LAM, PHI, DXDP, DYDP, &
8987  DLAMDP, DPHIDP )
8988  ! *** INTERNAL SUBROUTINE ***
8989  ! Routine to compute polar stereographic transformation of
8990  ! grid derivatives dx/dp & dy/dp to dlam/dp & dphi/dp.
8991  !
8992  ! mu = lam - lam0
8993  ! nu = pi/4 - alpha*phi/2
8994  ! k0 = cos(c0/2)**2
8995  !
8996  ! dlam/dx = ( 1/(2*R*k0)) * cot(nu) * cos(mu)
8997  ! dlam/dy = ( alpha/(2*R*k0)) * cot(nu) * sin(mu)
8998  ! dphi/dx = (-alpha/( R*k0)) * cos(nu)^2 * sin(mu)
8999  ! dphi/dy = ( 1/( R*k0)) * cos(nu)^2 * cos(mu)
9000  !
9001  ! dlam/dp = dx/dp*dlam/dx + dy/dp*dlam/dy
9002  ! dphi/dp = dx/dp*dphi/dx + dy/dp*dphi/dy
9003  ! dlam/dq = dx/dq*dlam/dx + dy/dq*dlam/dy
9004  ! dphi/dq = dx/dq*dphi/dx + dy/dq*dphi/dy
9005  !
9006  REAL(8),INTENT(IN) :: lam0, c0
9007  INTEGER,INTENT(IN) :: ihem
9008  REAL(8),INTENT(IN) :: lam, phi
9009  REAL(8),INTENT(IN) :: dxdp, dydp
9010  REAL(8),INTENT(OUT):: dlamdp, dphidp
9011 
9012  ! Local parameters
9013  REAL(8), PARAMETER :: small = 1d-6
9014  REAL(8) :: k0, a, mu, nu, fac
9015  REAL(8) :: cosmu, sinmu, cosnu2, cotnu
9016  REAL(8) :: dlamdx, dlamdy, dphidx, dphidy
9017 
9018  k0 = cos(half*c0*d2r)**2
9019  mu = (lam-lam0)*d2r
9020  a = sign(one,real(ihem,8))
9021  nu = pio4 - a*half*phi*d2r
9022  nu = sign(max(small,abs(nu)),nu)
9023  fac = r2d*half/rearth/k0
9024 
9025  cosmu = cos(mu)
9026  sinmu = sin(mu)
9027  cosnu2 = cos(nu)**2
9028  cotnu = one/tan(nu)
9029 
9030  dlamdx = fac*cotnu*cosmu
9031  dlamdy = a*fac*cotnu*sinmu
9032  dphidx = -a*two*fac*cosnu2*sinmu
9033  dphidy = two*fac*cosnu2*cosmu
9034 
9035  dlamdp = dxdp*dlamdx + dydp*dlamdy
9036  dphidp = dxdp*dphidx + dydp*dphidy
9037 
9038  END SUBROUTINE spddp
9039  !/
9040  !/ ------------------------------------------------------------------- /
9041  !/
9042  SUBROUTINE spddq( LAM0, C0, IHEM, LAM, PHI, DXDQ, DYDQ, &
9043  DLAMDQ, DPHIDQ )
9044  ! *** INTERNAL SUBROUTINE ***
9045  ! Routine to compute polar stereographic transformation of
9046  ! grid derivatives dx/dq & dy/dq to dlam/dq & dphi/dq.
9047  !
9048  ! mu = lam - lam0
9049  ! nu = pi/4 - alpha*phi/2
9050  ! k0 = cos(c0/2)**2
9051  !
9052  ! dlam/dx = ( 1/(2*R*k0)) * cot(nu) * cos(mu)
9053  ! dlam/dy = ( alpha/(2*R*k0)) * cot(nu) * sin(mu)
9054  ! dphi/dx = (-alpha/( R*k0)) * cos(nu)^2 * sin(mu)
9055  ! dphi/dy = ( 1/( R*k0)) * cos(nu)^2 * cos(mu)
9056  !
9057  ! dlam/dp = dx/dp*dlam/dx + dy/dp*dlam/dy
9058  ! dphi/dp = dx/dp*dphi/dx + dy/dp*dphi/dy
9059  ! dlam/dq = dx/dq*dlam/dx + dy/dq*dlam/dy
9060  ! dphi/dq = dx/dq*dphi/dx + dy/dq*dphi/dy
9061  !
9062  REAL(8),INTENT(IN) :: lam0, c0
9063  INTEGER,INTENT(IN) :: ihem
9064  REAL(8),INTENT(IN) :: lam, phi
9065  REAL(8),INTENT(IN) :: dxdq, dydq
9066  REAL(8),INTENT(OUT):: dlamdq, dphidq
9067 
9068  ! Local parameters
9069  REAL(8), PARAMETER :: small = 1d-6
9070  REAL(8) :: k0, a, mu, nu, fac
9071  REAL(8) :: cosmu, sinmu, cosnu2, cotnu
9072  REAL(8) :: dlamdx, dlamdy, dphidx, dphidy
9073 
9074  k0 = cos(half*c0*d2r)**2
9075  mu = (lam-lam0)*d2r
9076  a = sign(one,real(ihem,8))
9077  nu = pio4 - a*half*phi*d2r
9078  nu = sign(max(small,abs(nu)),nu)
9079  fac = r2d*half/rearth/k0
9080 
9081  cosmu = cos(mu)
9082  sinmu = sin(mu)
9083  cosnu2 = cos(nu)**2
9084  cotnu = one/tan(nu)
9085 
9086  dlamdx = fac*cotnu*cosmu
9087  dlamdy = a*fac*cotnu*sinmu
9088  dphidx = -a*two*fac*cosnu2*sinmu
9089  dphidy = two*fac*cosnu2*cosmu
9090 
9091  dlamdq = dxdq*dlamdx + dydq*dlamdy
9092  dphidq = dxdq*dphidx + dydq*dphidy
9093 
9094  END SUBROUTINE spddq
9095  !/
9096  !/ ------------------------------------------------------------------- /
9097  !/
9098 #undef DFDPQ_SINGLE_POINT_WIDE_CHANNEL_ERROR
9099 #undef DFDPQ_SINGLE_POINT_WIDE_CHANNEL_WARNING
9100  SUBROUTINE dfdpq( N, K, C, IJG, ICLO, &
9101  PTILED, QTILED, &
9102  PRANGE, QRANGE, &
9103  LB, UB, P, Q, &
9104  F4, F8, DFDP, DFDQ, &
9105  G4, G8, DGDP, DGDQ, &
9106  H4, H8, DHDP, DHDQ, &
9107  NSDP, ISDP, JSDP, CSDP, &
9108  NSDQ, ISDQ, JSDQ, CSDQ, &
9109  MASK, RC )
9110  ! *** INTERNAL SUBROUTINE ***
9111  INTEGER, INTENT(IN) :: n
9112  INTEGER, INTENT(IN) :: k(0:n,0:n,1:n)
9113  REAL(8), INTENT(IN) :: c(0:n,0:n,1:n)
9114  LOGICAL, INTENT(IN) :: ijg
9115  INTEGER, INTENT(IN) :: iclo
9116  LOGICAL, INTENT(IN) :: ptiled, qtiled
9117  INTEGER, INTENT(IN) :: prange(2), qrange(2)
9118  INTEGER, INTENT(IN) :: lb(2), ub(2)
9119  INTEGER, INTENT(IN) :: p, q
9120  REAL(4), INTENT(IN), OPTIONAL :: f4(lb(1):ub(1),lb(2):ub(2))
9121  REAL(8), INTENT(IN), OPTIONAL :: f8(lb(1):ub(1),lb(2):ub(2))
9122  REAL(8), INTENT(OUT), OPTIONAL :: dfdp, dfdq
9123  REAL(4), INTENT(IN), OPTIONAL :: g4(lb(1):ub(1),lb(2):ub(2))
9124  REAL(8), INTENT(IN), OPTIONAL :: g8(lb(1):ub(1),lb(2):ub(2))
9125  REAL(8), INTENT(OUT), OPTIONAL :: dgdp, dgdq
9126  REAL(4), INTENT(IN), OPTIONAL :: h4(lb(1):ub(1),lb(2):ub(2))
9127  REAL(8), INTENT(IN), OPTIONAL :: h8(lb(1):ub(1),lb(2):ub(2))
9128  REAL(8), INTENT(OUT), OPTIONAL :: dhdp, dhdq
9129  INTEGER, INTENT(OUT), OPTIONAL :: nsdp
9130  INTEGER, POINTER, OPTIONAL :: isdp(:), jsdp(:)
9131  REAL(8), POINTER, OPTIONAL :: csdp(:)
9132  INTEGER, INTENT(OUT), OPTIONAL :: nsdq
9133  INTEGER, POINTER, OPTIONAL :: isdq(:), jsdq(:)
9134  REAL(8), POINTER, OPTIONAL :: csdq(:)
9135  LOGICAL, INTENT(IN), OPTIONAL :: mask(lb(1):ub(1),lb(2):ub(2))
9136  INTEGER, INTENT(OUT), OPTIONAL :: rc
9137 
9138  ! Local parameters
9139  INTEGER, PARAMETER :: m = 1 ! order of derivative
9140  LOGICAL, PARAMETER :: debug = .false.
9141  CHARACTER(64) :: fstr
9142  LOGICAL :: comp_m, comp_f, comp_g, comp_h, type_r4
9143  LOGICAL :: comp_cp, comp_cq
9144  INTEGER :: np, nq, lbp, lbq, ubp, ubq, p0, q0
9145  INTEGER :: istat=0, i, j, l, ii, jj, ni, nj, ii0, iin, jj0, jjn
9146  INTEGER :: kp(0:n), kq(0:n)
9147  LOGICAL :: mp(0:n), mq(0:n)
9148  REAL(8) :: fp(0:n), fq(0:n)
9149  REAL(8) :: gp(0:n), gq(0:n)
9150  REAL(8) :: hp(0:n), hq(0:n)
9151  INTEGER :: ip(0:n), iq(0:n)
9152  INTEGER :: jp(0:n), jq(0:n)
9153  !
9154  ! -------------------------------------------------------------------- /
9155  ! 1. Check and setup inputs
9156  !
9157  IF ( PRESENT(rc) ) rc = 0
9158 
9159  comp_f = ( PRESENT(f4) .OR. PRESENT(f8) ) .AND. &
9160  PRESENT(dfdp) .AND. PRESENT(dfdq)
9161  comp_g = ( PRESENT(g4) .OR. PRESENT(g8) ) .AND. &
9162  PRESENT(dgdp) .AND. PRESENT(dgdq)
9163  comp_h = ( PRESENT(h4) .OR. PRESENT(h8) ) .AND. &
9164  PRESENT(dhdp) .AND. PRESENT(dhdq)
9165  comp_cp = PRESENT(nsdp) .AND. PRESENT(isdp) .AND. &
9166  PRESENT(jsdp) .AND. PRESENT(csdp)
9167  comp_cq = PRESENT(nsdq) .AND. PRESENT(isdq) .AND. &
9168  PRESENT(jsdq) .AND. PRESENT(csdq)
9169  IF ( .NOT.comp_f.AND..NOT.comp_g.AND..NOT.comp_h.AND. &
9170  .NOT.comp_cp.AND..NOT.comp_cq ) RETURN
9171 
9172  IF ( comp_f ) THEN
9173  type_r4 = PRESENT(f4)
9174  ELSE IF ( comp_g ) THEN
9175  type_r4 = PRESENT(g4)
9176  ELSE IF ( comp_h ) THEN
9177  type_r4 = PRESENT(h4)
9178  END IF
9179 
9180  np = prange(2) - prange(1) + 1
9181  nq = qrange(2) - qrange(1) + 1
9182 
9183  IF ( ijg ) THEN
9184  lbp = lb(1); lbq = lb(2)
9185  ubp = ub(1); ubq = ub(2)
9186  ELSE
9187  lbp = lb(2); lbq = lb(1)
9188  ubp = ub(2); ubq = ub(1)
9189  END IF
9190 
9191  IF ( p.LT.lbp .OR. p.GT.ubp .OR. q.LT.lbq .OR. q.GT.ubq ) THEN
9192  WRITE(0,'(/1A,/1A,1L2,5I6,/1A,1L2,5I6/)') 'DFDPQ ERROR -- '// &
9193  'input index coordinates outside input array bounds', &
9194  'DFDPQ ERROR -- PTILED,PRANGE,P,LBP,UBP:',ptiled,prange,p,lbp,ubp, &
9195  'DFDPQ ERROR -- QTILED,QRANGE,Q,LBQ,UBQ:',qtiled,qrange,q,lbq,ubq
9196  istat = 1
9197  IF ( PRESENT(rc) ) THEN
9198  rc = istat
9199  RETURN
9200  ELSE
9201  CALL extcde (istat)
9202  END IF
9203  END IF
9204 
9205  p0 = p
9206  q0 = q
9207  IF ( mod(iclo,2).EQ.0 ) &
9208  p0 = prange(1) + mod(np - 1 + mod(p0 - prange(1) + 1, np), np)
9209  IF ( mod(iclo,3).EQ.0 ) &
9210  q0 = qrange(1) + mod(nq - 1 + mod(q0 - qrange(1) + 1, nq), nq)
9211  IF ( iclo.EQ.iclo_trpl .AND. q0.GT.qrange(2) ) THEN
9212  p0 = prange(2) + prange(1) - p0
9213  q0 = 2*qrange(2) - q0 + 1
9214  END IF
9215  IF ( p0.LT.prange(1) .OR. p0.GT.prange(2) .OR. &
9216  q0.LT.qrange(1) .OR. q0.GT.qrange(2) ) THEN
9217  WRITE(0,'(/1A,/1A,4I6,/1A,4I6/)') 'DFDPQ ERROR -- '// &
9218  'shifted input index coordinates outside allowed range', &
9219  'DFDPQ ERROR -- PRANGE,P,P0:',prange,p,p0, &
9220  'DFDPQ ERROR -- QRANGE,Q,Q0:',qrange,q,q0
9221  istat = 1
9222  IF ( PRESENT(rc) ) THEN
9223  rc = istat
9224  RETURN
9225  ELSE
9226  CALL extcde (istat)
9227  END IF
9228  END IF
9229 
9230  comp_m = PRESENT(mask)
9231  IF ( comp_m ) THEN
9232  IF ( ijg ) THEN
9233  IF ( mask(p0,q0) ) RETURN
9234  ELSE
9235  IF ( mask(q0,p0) ) RETURN
9236  END IF
9237  END IF
9238  !
9239  ! -------------------------------------------------------------------- /
9240  ! 2. Compute DF/DP
9241  !
9242  IF ( comp_f.OR.comp_g.OR.comp_h.OR.comp_cp ) THEN
9243 
9244  IF ( mod(iclo,2).EQ.0 ) THEN
9245  i = n/2
9246  ELSE
9247  IF (p0-prange(1).LT.n/2) THEN
9248  i = p0 - prange(1)
9249  ELSE IF (prange(2)-p0.LT.n/2) THEN
9250  i = n + p0 - prange(2)
9251  ELSE
9252  i = n/2
9253  END IF
9254  END IF
9255 
9256  kp(:) = p + k(:,i,n)
9257  kq(:) = q
9258  IF ( .NOT.ptiled ) THEN
9259  IF ( mod(iclo,2).EQ.0 ) THEN
9260  kp = prange(1) + mod(np - 1 + mod(kp - prange(1) + 1, np), np)
9261  END IF
9262  END IF
9263 
9264  IF ( minval(kp).LT.lbp .OR. maxval(kp).GT.ubp .OR. &
9265  minval(kq).LT.lbq .OR. maxval(kq).GT.ubq ) THEN
9266  WRITE(0,'(/1A,/1A,1L2,8I6,/1A,1L2,8I6/)') 'DFDPQ ERROR -- '// &
9267  'stencil index coordinates outside array bounds', &
9268  'DFDPQ ERROR -- PTILED,PRANGE,P,P0,LBP,UBP,PMIN,PMAX:', &
9269  ptiled,prange,p,p0,lbp,ubp,minval(kp),maxval(kp), &
9270  'DFDPQ ERROR -- QTILED,QRANGE,Q,Q0,LBQ,UBQ,QMIN,QMAX:', &
9271  qtiled,qrange,q,q0,lbq,ubq,minval(kq),maxval(kq)
9272  istat = 1
9273  IF ( PRESENT(rc) ) THEN
9274  rc = istat
9275  RETURN
9276  ELSE
9277  CALL extcde (istat)
9278  END IF
9279  END IF
9280 
9281  IF ( comp_cp ) THEN
9282  ip(:) = p0 + k(:,i,n)
9283  jp(:) = q0
9284  IF ( mod(iclo,2).EQ.0 ) THEN
9285  ip = prange(1) + mod(np - 1 + mod(ip - prange(1) + 1, np), np)
9286  END IF
9287  END IF
9288 
9289  DO l = 0, n
9290  IF ( ijg ) THEN
9291  IF ( comp_m ) mp(l) = mask(kp(l),kq(l))
9292  IF ( type_r4 ) THEN
9293  IF ( comp_f ) fp(l) = f4(kp(l),kq(l))
9294  IF ( comp_g ) gp(l) = g4(kp(l),kq(l))
9295  IF ( comp_h ) hp(l) = h4(kp(l),kq(l))
9296  ELSE
9297  IF ( comp_f ) fp(l) = f8(kp(l),kq(l))
9298  IF ( comp_g ) gp(l) = g8(kp(l),kq(l))
9299  IF ( comp_h ) hp(l) = h8(kp(l),kq(l))
9300  END IF
9301  ELSE
9302  IF ( comp_m ) mp(l) = mask(kq(l),kp(l))
9303  IF ( type_r4 ) THEN
9304  IF ( comp_f ) fp(l) = f4(kq(l),kp(l))
9305  IF ( comp_g ) gp(l) = g4(kq(l),kp(l))
9306  IF ( comp_h ) hp(l) = h4(kq(l),kp(l))
9307  ELSE
9308  IF ( comp_f ) fp(l) = f8(kq(l),kp(l))
9309  IF ( comp_g ) gp(l) = g8(kq(l),kp(l))
9310  IF ( comp_h ) hp(l) = h8(kq(l),kp(l))
9311  END IF
9312  END IF
9313  END DO
9314 
9315  ii = i
9316  ni = n
9317  ii0 = 0
9318  iin = n
9319  IF ( comp_m ) THEN
9320  DO l = i-1, 0, -1
9321  IF ( mp(l) ) THEN
9322  mp(0:l) = .true.
9323  EXIT
9324  END IF
9325  END DO
9326  DO l = i+1, n
9327  IF ( mp(l) ) THEN
9328  mp(l:n) = .true.
9329  EXIT
9330  END IF
9331  END DO
9332  ii = count(.NOT.mp(0:i)) - 1
9333  ni = count(.NOT.mp(0:n)) - 1
9334  ii0 = i - ii
9335  iin = ii0 + ni
9336  END IF
9337 #ifdef DFDPQ_SINGLE_POINT_WIDE_CHANNEL_ERROR
9338  IF ( ni.LE.0 ) THEN
9339  WRITE(0,'(/1A,1A,4I6/)') 'DFDPQ ERROR -- ', &
9340  'DFDP -- single point wide channel not allowed',p,q,p0,q0
9341  istat = 1
9342  IF ( PRESENT(rc) ) THEN
9343  rc = istat
9344  RETURN
9345  ELSE
9346  CALL extcde (istat)
9347  END IF
9348  END IF
9349 #endif
9350 
9351  IF ( ni.GT.0 ) THEN
9352  IF ( comp_f ) dfdp = dot_product(c(0:ni,ii,ni),fp(ii0:iin))
9353  IF ( comp_g ) dgdp = dot_product(c(0:ni,ii,ni),gp(ii0:iin))
9354  IF ( comp_h ) dhdp = dot_product(c(0:ni,ii,ni),hp(ii0:iin))
9355  IF ( comp_cp ) THEN
9356  IF ( ASSOCIATED(isdp) ) DEALLOCATE(isdp)
9357  IF ( ASSOCIATED(jsdp) ) DEALLOCATE(jsdp)
9358  IF ( ASSOCIATED(csdp) ) DEALLOCATE(csdp)
9359  nsdp = ni+1
9360  ALLOCATE(isdp(nsdp),jsdp(nsdp),csdp(nsdp))
9361  isdp(1:nsdp) = ip(ii0:iin)
9362  jsdp(1:nsdp) = jp(ii0:iin)
9363  csdp(1:nsdp) = c(0:ni,ii,ni)
9364  END IF
9365  IF ( debug .AND. comp_f ) THEN
9366  WRITE(fstr,'(A,I0,A,I0,A,I0,A)') '(/1A,8I6,E16.8,/1A,',&
9367  ni+1,'I16,/1A,',ni+1,'E16.8,/1A,',ni+1,'E16.8)'
9368  WRITE(*,trim(fstr)) &
9369  'DFDPQ -- DFDP -- P,Q,P0,Q0,NI,II,II0,IIN,DFDP:',&
9370  p,q,p0,q0,ni,ii,ii0,iin,dfdp, &
9371  'DFDPQ -- DFDP -- K:', k(0:ni,ii,ni), &
9372  'DFDPQ -- DFDP -- C:', c(0:ni,ii,ni), &
9373  'DFDPQ -- DFDP -- FP:', fp(ii0:iin)
9374  END IF
9375  ELSE
9376 #ifdef DFDPQ_SINGLE_POINT_WIDE_CHANNEL_WARNING
9377  WRITE(0,'(/1A,1A,4I6/)') 'DFDPQ WARNING -- ', &
9378  'single point wide channel, DFDP set to zero:',p,q,p0,q0
9379 #endif
9380  IF ( comp_f ) dfdp = zero
9381  IF ( comp_g ) dgdp = zero
9382  IF ( comp_h ) dhdp = zero
9383  IF ( comp_cp ) nsdp = 0
9384  END IF
9385 
9386  END IF
9387  !
9388  ! -------------------------------------------------------------------- /
9389  ! 3. Compute DF/DQ
9390  !
9391  IF ( comp_f.OR.comp_g.OR.comp_h.OR.comp_cq ) THEN
9392 
9393  IF ( mod(iclo,3).EQ.0 ) THEN
9394  j = n/2
9395  ELSE IF ( iclo.EQ.iclo_trpl ) THEN
9396  IF (q0-qrange(1).LT.n/2) THEN
9397  j = q0 - qrange(1)
9398  ELSE
9399  j = n/2
9400  END IF
9401  ELSE
9402  IF (q0-qrange(1).LT.n/2) THEN
9403  j = q0 - qrange(1)
9404  ELSE IF (qrange(2)-q0.LT.n/2) THEN
9405  j = n + q0 - qrange(2)
9406  ELSE
9407  j = n/2
9408  END IF
9409  END IF
9410 
9411  kp(:) = p
9412  kq(:) = q + k(:,j,n)
9413  IF ( .NOT.qtiled ) THEN
9414  IF ( mod(iclo,3).EQ.0 ) THEN
9415  kq = qrange(1) + mod(nq - 1 + mod(kq - qrange(1) + 1, nq), nq)
9416  END IF
9417  IF ( iclo.EQ.iclo_trpl .AND. .NOT.ptiled ) THEN
9418  WHERE ( kq.GT.qrange(2) )
9419  kp = prange(2) + prange(1) - kp
9420  kq = 2*qrange(2) - kq + 1
9421  END WHERE
9422  END IF
9423  END IF
9424 
9425  IF ( minval(kp).LT.lbp .OR. maxval(kp).GT.ubp .OR. &
9426  minval(kq).LT.lbq .OR. maxval(kq).GT.ubq ) THEN
9427  WRITE(0,'(/1A,/1A,1L2,8I6,/1A,1L2,8I6/)') 'DFDPQ ERROR -- '// &
9428  'stencil index coordinates outside array bounds', &
9429  'DFDPQ ERROR -- PTILED,PRANGE,P,P0,LBP,UBP,PMIN,PMAX:', &
9430  ptiled,prange,p,p0,lbp,ubp,minval(kp),maxval(kp), &
9431  'DFDPQ ERROR -- QTILED,QRANGE,Q,Q0,LBQ,UBQ,QMIN,QMAX:', &
9432  qtiled,qrange,q,q0,lbq,ubq,minval(kq),maxval(kq)
9433  istat = 1
9434  IF ( PRESENT(rc) ) THEN
9435  rc = istat
9436  RETURN
9437  ELSE
9438  CALL extcde (istat)
9439  END IF
9440  END IF
9441 
9442  IF ( comp_cq ) THEN
9443  iq(:) = p0
9444  jq(:) = q0 + k(:,j,n)
9445  IF ( mod(iclo,3).EQ.0 ) THEN
9446  jq = qrange(1) + mod(nq - 1 + mod(jq - qrange(1) + 1, nq), nq)
9447  END IF
9448  IF ( iclo.EQ.iclo_trpl ) THEN
9449  WHERE ( jq.GT.qrange(2) )
9450  iq = prange(2) + prange(1) - iq
9451  jq = 2*qrange(2) - jq + 1
9452  END WHERE
9453  END IF
9454  END IF
9455 
9456  DO l = 0, n
9457  IF ( ijg ) THEN
9458  IF ( comp_m ) mq(l) = mask(kp(l),kq(l))
9459  IF ( type_r4 ) THEN
9460  IF ( comp_f ) fq(l) = f4(kp(l),kq(l))
9461  IF ( comp_g ) gq(l) = g4(kp(l),kq(l))
9462  IF ( comp_h ) hq(l) = h4(kp(l),kq(l))
9463  ELSE
9464  IF ( comp_f ) fq(l) = f8(kp(l),kq(l))
9465  IF ( comp_g ) gq(l) = g8(kp(l),kq(l))
9466  IF ( comp_h ) hq(l) = h8(kp(l),kq(l))
9467  END IF
9468  ELSE
9469  IF ( comp_m ) mq(l) = mask(kq(l),kp(l))
9470  IF ( type_r4 ) THEN
9471  IF ( comp_f ) fq(l) = f4(kq(l),kp(l))
9472  IF ( comp_g ) gq(l) = g4(kq(l),kp(l))
9473  IF ( comp_h ) hq(l) = h4(kq(l),kp(l))
9474  ELSE
9475  IF ( comp_f ) fq(l) = f8(kq(l),kp(l))
9476  IF ( comp_g ) gq(l) = g8(kq(l),kp(l))
9477  IF ( comp_h ) hq(l) = h8(kq(l),kp(l))
9478  END IF
9479  END IF
9480  END DO
9481 
9482  jj = j
9483  nj = n
9484  jj0 = 0
9485  jjn = n
9486  IF ( comp_m ) THEN
9487  DO l = j-1, 0, -1
9488  IF ( mq(l) ) THEN
9489  mq(0:l) = .true.
9490  EXIT
9491  END IF
9492  END DO
9493  DO l = j+1, n
9494  IF ( mq(l) ) THEN
9495  mq(l:n) = .true.
9496  EXIT
9497  END IF
9498  END DO
9499  jj = count(.NOT.mq(0:j)) - 1
9500  nj = count(.NOT.mq(0:n)) - 1
9501  jj0 = j - jj
9502  jjn = jj0 + nj
9503  END IF
9504 #ifdef DFDPQ_SINGLE_POINT_WIDE_CHANNEL_ERROR
9505  IF ( nj.LE.0 ) THEN
9506  WRITE(0,'(/1A,1A,4I6/)') 'DFDPQ ERROR -- ', &
9507  'DFDQ -- single point wide channel not allowed',p,q,p0,q0
9508  istat = 1
9509  IF ( PRESENT(rc) ) THEN
9510  rc = istat
9511  RETURN
9512  ELSE
9513  CALL extcde (istat)
9514  END IF
9515  END IF
9516 #endif
9517 
9518  IF ( nj.GT.0 ) THEN
9519  IF ( comp_f ) dfdq = dot_product(c(0:nj,jj,nj),fq(jj0:jjn))
9520  IF ( comp_g ) dgdq = dot_product(c(0:nj,jj,nj),gq(jj0:jjn))
9521  IF ( comp_h ) dhdq = dot_product(c(0:nj,jj,nj),hq(jj0:jjn))
9522  IF ( comp_cq ) THEN
9523  IF ( ASSOCIATED(isdq) ) DEALLOCATE(isdq)
9524  IF ( ASSOCIATED(jsdq) ) DEALLOCATE(jsdq)
9525  IF ( ASSOCIATED(csdq) ) DEALLOCATE(csdq)
9526  nsdq = nj+1
9527  ALLOCATE(isdq(nsdq),jsdq(nsdq),csdq(nsdq))
9528  isdq(1:nsdq) = iq(jj0:jjn)
9529  jsdq(1:nsdq) = jq(jj0:jjn)
9530  csdq(1:nsdq) = c(0:nj,jj,nj)
9531  END IF
9532  IF ( debug .AND. comp_f ) THEN
9533  WRITE(fstr,'(A,I0,A,I0,A,I0,A)') '(/1A,8I6,E16.8,/1A,',&
9534  nj+1,'I16,/1A,',nj+1,'E16.8,/1A,',nj+1,'E16.8)'
9535  WRITE(*,trim(fstr)) &
9536  'DFDPQ -- DFDQ -- P,Q,P0,Q0,NJ,JJ,JJ0,JJN,DFDQ:',&
9537  p,q,p0,q0,nj,jj,jj0,jjn,dfdq, &
9538  'DFDPQ -- DFDQ -- K:', k(0:nj,jj,nj), &
9539  'DFDPQ -- DFDQ -- C:', c(0:nj,jj,nj), &
9540  'DFDPQ -- DFDQ -- FQ:', fq(jj0:jjn)
9541  END IF
9542  ELSE
9543 #ifdef DFDPQ_SINGLE_POINT_WIDE_CHANNEL_WARNING
9544  WRITE(0,'(/1A,1A,4I6/)') 'DFDPQ WARNING -- ', &
9545  'single point wide channel, DFDQ set to zero:',p,q,p0,q0
9546 #endif
9547  IF ( comp_f ) dfdq = zero
9548  IF ( comp_g ) dgdq = zero
9549  IF ( comp_h ) dhdq = zero
9550  IF ( comp_cq ) nsdq = 0
9551  END IF
9552 
9553  END IF
9554 
9555  END SUBROUTINE dfdpq
9556  !/
9557  !/ ------------------------------------------------------------------- /
9558  !/
9559  SUBROUTINE get_fdw2( N, M, K, C )
9560  ! *** INTERNAL SUBROUTINE ***
9561  INTEGER,INTENT(IN) :: n, m
9562  INTEGER,INTENT(OUT):: k(0:n,0:n)
9563  REAL(8),INTENT(OUT):: c(0:n,0:n)
9564  INTEGER :: i, j
9565  REAL(8) :: a(0:n), b(0:n,0:m)
9566 
9567  DO i = 0, n
9568  DO j = 0, n
9569  k(j,i) = j-i
9570  a(j) = k(j,i)
9571  END DO
9572  CALL w3fdwt( n, n, m, zero, a, b )
9573  c(0:n,i) = b(0:n,m)
9574  !WRITE(0,'(A,I1,2X,11I16)') 'I=',I,K(0:N,I)
9575  !WRITE(0,'(5X,11E16.8)') C(0:N,I)
9576  END DO
9577 
9578  END SUBROUTINE get_fdw2
9579  !/
9580  !/ ------------------------------------------------------------------- /
9581  !/
9582  SUBROUTINE get_fdw3( N, M, K, C )
9583  ! *** INTERNAL SUBROUTINE ***
9584  INTEGER,INTENT(IN) :: n, m
9585  INTEGER,INTENT(OUT):: k(0:n,0:n,1:n)
9586  REAL(8),INTENT(OUT):: c(0:n,0:n,1:n)
9587  INTEGER :: l, i, j
9588  REAL(8) :: a(0:n), b(0:n,0:m)
9589 
9590  DO l = 1, n
9591  !WRITE(0,'(A,I1,2X,11A)') 'L=',L,('----------------',I=0,L)
9592  DO i = 0, l
9593  DO j = 0, l
9594  k(j,i,l) = j-i
9595  a(j) = k(j,i,l)
9596  END DO
9597  CALL w3fdwt( l, n, m, zero, a, b )
9598  c(0:l,i,l) = b(0:l,m)
9599  !WRITE(0,'(A,I1,2X,11I16)') 'I=',I,K(0:L,I,L)
9600  !WRITE(0,'(5X,11E16.8)') C(0:L,I,L)
9601  END DO
9602  END DO
9603 
9604  END SUBROUTINE get_fdw3
9605  !/
9606  !/ ------------------------------------------------------------------- /
9607  !/
9608  !/
9609  !/ End Internal Support Routines ===================================== /
9610  !/
9611  !/
9612 
9613 
9614 
9615 
9616 
9617 
9618 
9619 
9620 #ifndef ENABLE_WW3
9621  !/
9622  !/ Local routines for use outside of WW3 ============================= /
9623  !/
9624  SUBROUTINE extcde(IEXIT)
9625 #ifdef ENABLE_MPI
9626  include "mpif.h"
9627 #endif
9628  INTEGER, INTENT(IN) :: iexit
9629 #ifdef ENABLE_MPI
9630  INTEGER :: ierr_mpi
9631  LOGICAL :: run
9632  CALL mpi_initialized ( run, ierr_mpi )
9633  IF ( run ) THEN
9634  CALL mpi_abort ( mpi_comm_world, iexit, ierr_mpi )
9635  END IF
9636 #endif
9637  CALL exit(iexit)
9638  END SUBROUTINE extcde
9639  !/
9640  !/ End local routines for use outside of WW3 ========================= /
9641  !/
9642 #endif
9643 
9644 
9645 
9646 
9647 
9648 
9649 
9650 
9651  !/
9652  !/ End of module W3GSRUMD ============================================ /
9653  !/
9654 END MODULE w3gsrumd
w3gsrumd::iclo_grdj
integer, parameter, public iclo_grdj
Definition: w3gsrumd.F90:317
include
cmake src_list cmake include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_switches.cmake) check_switches("$
Definition: CMakeLists.txt:15
w3gsrumd
Definition: w3gsrumd.F90:17
w3gsrumd::iclo_trdl
integer, parameter, public iclo_trdl
Definition: w3gsrumd.F90:318
w3gsrumd::iclo_smpl
integer, parameter, public iclo_smpl
Definition: w3gsrumd.F90:315
w3gsrumd::w3nnsd
subroutine, public w3nnsd(NNS)
Definition: w3gsrumd.F90:6931
w3gsrumd::w3nnsp
subroutine, public w3nnsp(NNS, IUNIT)
Definition: w3gsrumd.F90:7012
w3gsrumd::t_nns
Definition: w3gsrumd.F90:366
w3gsrumd::iclo_none
integer, parameter, public iclo_none
Definition: w3gsrumd.F90:314
w3servmd
Definition: w3servmd.F90:3
w3gsrumd::w3nnsc
type(t_nns) function, pointer, public w3nnsc(NLVL)
Definition: w3gsrumd.F90:6820
w3gsrumd::w3gsud
subroutine, public w3gsud(GSU)
Definition: w3gsrumd.F90:790
w3gsrumd::mskc_none
integer, parameter, public mskc_none
Definition: w3gsrumd.F90:281
w3servmd::strace
subroutine strace(IENT, SNAME)
Definition: w3servmd.F90:148
w3gsrumd::iclo_trpl
integer, parameter, public iclo_trpl
Definition: w3gsrumd.F90:319
w3gsrumd::mskc_part
integer, parameter, public mskc_part
Definition: w3gsrumd.F90:282
w3gsrumd::pi
real(8), parameter pi
Definition: w3gsrumd.F90:377
w3gsrumd::mskc_full
integer, parameter, public mskc_full
Definition: w3gsrumd.F90:283
w3gsrumd::w3gsup
subroutine, public w3gsup(GSU, IUNIT, LFULL)
Definition: w3gsrumd.F90:885
check
subroutine check(status)
N/A.
Definition: ww3_systrk.F90:1299
w3gsrumd::iclo_grdi
integer, parameter, public iclo_grdi
Definition: w3gsrumd.F90:316
w3gsrumd::t_gsu
Definition: w3gsrumd.F90:325