NCEPLIBS-ip 4.0.0
neighbor_interp_mod.f90
1module neighbor_interp_mod
2 use gdswzd_mod
3 use polfix_mod
4 use ip_grids_mod
5 implicit none
6
7 private
9
11 module procedure interpolate_neighbor_scalar
12 module procedure interpolate_neighbor_vector
13 end interface interpolate_neighbor
14
15contains
16
17 SUBROUTINE interpolate_neighbor_scalar(IPOPT,grid_in,grid_out, &
18 MI,MO,KM,IBI,LI,GI, &
19 NO,RLAT,RLON,IBO,LO,GO,IRET)
20 !$$$ SUBPROGRAM DOCUMENTATION BLOCK
21 !
22 ! SUBPROGRAM: POLATES2 INTERPOLATE SCALAR FIELDS (NEIGHBOR)
23 ! PRGMMR: IREDELL ORG: W/NMC23 DATE: 96-04-10
24 !
25 ! ABSTRACT: THIS SUBPROGRAM PERFORMS NEIGHBOR INTERPOLATION
26 ! FROM ANY GRID TO ANY GRID FOR SCALAR FIELDS.
27 ! OPTIONS ALLOW CHOOSING THE WIDTH OF THE GRID SQUARE
28 ! (IPOPT(1)) TO SEARCH FOR VALID DATA, WHICH DEFAULTS TO 1
29 ! (IF IPOPT(1)=-1). ODD WIDTH SQUARES ARE CENTERED ON
30 ! THE NEAREST INPUT GRID POINT; EVEN WIDTH SQUARES ARE
31 ! CENTERED ON THE NEAREST FOUR INPUT GRID POINTS.
32 ! SQUARES ARE SEARCHED FOR VALID DATA IN A SPIRAL PATTERN
33 ! STARTING FROM THE CENTER. NO SEARCHING IS DONE WHERE
34 ! THE OUTPUT GRID IS OUTSIDE THE INPUT GRID.
35 ! ONLY HORIZONTAL INTERPOLATION IS PERFORMED.
36 ! THE CODE RECOGNIZES THE FOLLOWING PROJECTIONS, WHERE
37 ! "IGDTNUMI/O" IS THE GRIB 2 GRID DEFINTION TEMPLATE NUMBER
38 ! FOR THE INPUT AND OUTPUT GRIDS, RESPECTIVELY:
39 ! (IGDTNUMI/O=00) EQUIDISTANT CYLINDRICAL
40 ! (IGDTNUMI/O=01) ROTATED EQUIDISTANT CYLINDRICAL. "E" AND
41 ! NON-"E" STAGGERED
42 ! (IGDTNUMI/O=10) MERCATOR CYLINDRICAL
43 ! (IGDTNUMI/O=20) POLAR STEREOGRAPHIC AZIMUTHAL
44 ! (IGDTNUMI/O=30) LAMBERT CONFORMAL CONICAL
45 ! (IGDTNUMI/O=40) GAUSSIAN CYLINDRICAL
46 ! AS AN ADDED BONUS THE NUMBER OF OUTPUT GRID POINTS
47 ! AND THEIR LATITUDES AND LONGITUDES ARE ALSO RETURNED.
48 ! ON THE OTHER HAND, THE OUTPUT CAN BE A SET OF STATION POINTS
49 ! IF IGDTNUMO<0, IN WHICH CASE THE NUMBER OF POINTS
50 ! AND THEIR LATITUDES AND LONGITUDES MUST BE INPUT.
51 ! INPUT BITMAPS WILL BE INTERPOLATED TO OUTPUT BITMAPS.
52 ! OUTPUT BITMAPS WILL ALSO BE CREATED WHEN THE OUTPUT GRID
53 ! EXTENDS OUTSIDE OF THE DOMAIN OF THE INPUT GRID.
54 ! THE OUTPUT FIELD IS SET TO 0 WHERE THE OUTPUT BITMAP IS OFF.
55 !
56 ! PROGRAM HISTORY LOG:
57 ! 96-04-10 IREDELL
58 ! 1999-04-08 IREDELL SPLIT IJKGDS INTO TWO PIECES
59 ! 2001-06-18 IREDELL INCLUDE SPIRAL SEARCH OPTION
60 ! 2006-01-04 GAYNO MINOR BUG FIX
61 ! 2007-10-30 IREDELL SAVE WEIGHTS AND THREAD FOR PERFORMANCE
62 ! 2012-06-26 GAYNO FIX OUT-OF-BOUNDS ERROR. SEE NCEPLIBS
63 ! TICKET #9.
64 ! 2015-01-27 GAYNO REPLACE CALLS TO GDSWIZ WITH NEW MERGED
65 ! VERSION OF GDSWZD.
66 ! 2015-07-13 GAYNO CONVERT TO GRIB 2. REPLACE GRIB 1 KGDS ARRAYS
67 ! WITH GRIB 2 GRID DEFINITION TEMPLATE ARRAYS.
68 !
69 ! USAGE: CALL POLATES2(IPOPT,IGDTNUMI,IGDTMPLI,IGDTLENI, &
70 ! IGDTNUMO,IGDTMPLO,IGDTLENO, &
71 ! MI,MO,KM,IBI,LI,GI, &
72 ! NO,RLAT,RLON,IBO,LO,GO,IRET)
73 !
74 ! INPUT ARGUMENT LIST:
75 ! IPOPT - INTEGER (20) INTERPOLATION OPTIONS
76 ! IPOPT(1) IS WIDTH OF SQUARE TO EXAMINE IN SPIRAL SEARCH
77 ! (DEFAULTS TO 1 IF IPOPT(1)=-1)
78 ! IGDTNUMI - INTEGER GRID DEFINITION TEMPLATE NUMBER - INPUT GRID.
79 ! CORRESPONDS TO THE GFLD%IGDTNUM COMPONENT OF THE
80 ! NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE:
81 ! 00 - EQUIDISTANT CYLINDRICAL
82 ! 01 - ROTATED EQUIDISTANT CYLINDRICAL. "E"
83 ! AND NON-"E" STAGGERED
84 ! 10 - MERCATOR CYCLINDRICAL
85 ! 20 - POLAR STEREOGRAPHIC AZIMUTHAL
86 ! 30 - LAMBERT CONFORMAL CONICAL
87 ! 40 - GAUSSIAN EQUIDISTANT CYCLINDRICAL
88 ! IGDTMPLI - INTEGER (IGDTLENI) GRID DEFINITION TEMPLATE ARRAY -
89 ! INPUT GRID. CORRESPONDS TO THE GFLD%IGDTMPL COMPONENT
90 ! OF THE NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE
91 ! (SECTION 3 INFO). SEE COMMENTS IN ROUTINE
92 ! IPOLATES FOR COMPLETE DEFINITION.
93 ! IGDTLENI - INTEGER NUMBER OF ELEMENTS OF THE GRID DEFINITION
94 ! TEMPLATE ARRAY - INPUT GRID. CORRESPONDS TO THE GFLD%IGDTLEN
95 ! COMPONENT OF THE NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE.
96 ! IGDTNUMO - INTEGER GRID DEFINITION TEMPLATE NUMBER - OUTPUT GRID.
97 ! CORRESPONDS TO THE GFLD%IGDTNUM COMPONENT OF THE
98 ! NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE. IGDTNUMO<0
99 ! MEANS INTERPOLATE TO RANDOM STATION POINTS.
100 ! OTHERWISE, SAME DEFINITION AS "IGDTNUMI".
101 ! IGDTMPLO - INTEGER (IGDTLENO) GRID DEFINITION TEMPLATE ARRAY -
102 ! OUTPUT GRID. CORRESPONDS TO THE GFLD%IGDTMPL COMPONENT
103 ! OF THE NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE.
104 ! (SECTION 3 INFO). SEE COMMENTS IN ROUTINE
105 ! IPOLATES FOR COMPLETE DEFINITION.
106 ! IGDTLENO - INTEGER NUMBER OF ELEMENTS OF THE GRID DEFINITION
107 ! TEMPLATE ARRAY - OUTPUT GRID. CORRESPONDS TO THE GFLD%IGDTLEN
108 ! COMPONENT OF THE NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE.
109 ! MI - INTEGER SKIP NUMBER BETWEEN INPUT GRID FIELDS IF KM>1
110 ! OR DIMENSION OF INPUT GRID FIELDS IF KM=1
111 ! MO - INTEGER SKIP NUMBER BETWEEN OUTPUT GRID FIELDS IF KM>1
112 ! OR DIMENSION OF OUTPUT GRID FIELDS IF KM=1
113 ! KM - INTEGER NUMBER OF FIELDS TO INTERPOLATE
114 ! IBI - INTEGER (KM) INPUT BITMAP FLAGS
115 ! LI - LOGICAL*1 (MI,KM) INPUT BITMAPS (IF SOME IBI(K)=1)
116 ! GI - REAL (MI,KM) INPUT FIELDS TO INTERPOLATE
117 ! NO - INTEGER NUMBER OF OUTPUT POINTS (ONLY IF IGDTNUMO<0)
118 ! RLAT - REAL (NO) OUTPUT LATITUDES IN DEGREES (IF IGDTNUMO<0)
119 ! RLON - REAL (NO) OUTPUT LONGITUDES IN DEGREES (IF IGDTNUMO<0)
120 !
121 ! OUTPUT ARGUMENT LIST:
122 ! NO - INTEGER NUMBER OF OUTPUT POINTS (ONLY IF IGDTNUMO>=0)
123 ! RLAT - REAL (MO) OUTPUT LATITUDES IN DEGREES (IF IGDTNUMO>=0)
124 ! RLON - REAL (MO) OUTPUT LONGITUDES IN DEGREES (IF IGDTNUMO>=0)
125 ! IBO - INTEGER (KM) OUTPUT BITMAP FLAGS
126 ! LO - LOGICAL*1 (MO,KM) OUTPUT BITMAPS (ALWAYS OUTPUT)
127 ! GO - REAL (MO,KM) OUTPUT FIELDS INTERPOLATED
128 ! IRET - INTEGER RETURN CODE
129 ! 0 SUCCESSFUL INTERPOLATION
130 ! 2 UNRECOGNIZED INPUT GRID OR NO GRID OVERLAP
131 ! 3 UNRECOGNIZED OUTPUT GRID
132 !
133 ! SUBPROGRAMS CALLED:
134 ! GDSWZD GRID DESCRIPTION SECTION WIZARD
135 ! IJKGDS0 SET UP PARAMETERS FOR IJKGDS1
136 ! IJKGDS1 RETURN FIELD POSITION FOR A GIVEN GRID POINT
137 ! POLFIXS MAKE MULTIPLE POLE SCALAR VALUES CONSISTENT
138 ! CHECK_GRIDS2 DETERMINE IF INPUT OR OUTPUT GRIDS HAVE CHANGED
139 ! BETWEEN CALLS TO THIS ROUTINE.
140 !
141 ! ATTRIBUTES:
142 ! LANGUAGE: FORTRAN 90
143 !
144 !$$$
145 !
146 class(ip_grid), intent(in) :: grid_in, grid_out
147 INTEGER, INTENT(IN ) :: IPOPT(20)
148 INTEGER, INTENT(IN ) :: MI,MO,KM
149 INTEGER, INTENT(IN ) :: IBI(KM)
150 INTEGER, INTENT(INOUT) :: NO
151 INTEGER, INTENT( OUT) :: IRET, IBO(KM)
152 !
153 LOGICAL*1, INTENT(IN ) :: LI(MI,KM)
154 LOGICAL*1, INTENT( OUT) :: LO(MO,KM)
155 !
156 REAL, INTENT(IN ) :: GI(MI,KM)
157 REAL, INTENT(INOUT) :: RLAT(MO),RLON(MO)
158 REAL, INTENT( OUT) :: GO(MO,KM)
159 !
160 REAL, PARAMETER :: FILL=-9999.
161 !
162 INTEGER :: I1,J1,IXS,JXS
163 INTEGER :: MSPIRAL,N,K,NK
164 INTEGER :: NV
165 INTEGER :: MX,KXS,KXT,IX,JX,NX
166 !
167 LOGICAL :: SAME_GRIDI, SAME_GRIDO
168 !
169 REAL :: XPTS(MO),YPTS(MO)
170 logical :: to_station_points
171
172 INTEGER, SAVE :: NOX=-1,iretx=-1
173 INTEGER, ALLOCATABLE, SAVE :: NXY(:)
174 REAL, ALLOCATABLE, SAVE :: RLATX(:),RLONX(:),XPTSX(:),YPTSX(:)
175 class(ip_grid), allocatable, save :: prev_grid_in, prev_grid_out
176 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
177 ! SET PARAMETERS
178 iret=0
179 mspiral=max(ipopt(1),1)
180 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
181 if (.not. allocated(prev_grid_in) .or. .not. allocated(prev_grid_out)) then
182 allocate(prev_grid_in, source = grid_in)
183 allocate(prev_grid_out, source = grid_out)
184
185 same_gridi = .false.
186 same_grido = .false.
187 else
188 same_gridi = grid_in == prev_grid_in
189 same_grido = grid_out == prev_grid_out
190
191 if (.not. same_gridi .or. .not. same_grido) then
192 deallocate(prev_grid_in)
193 deallocate(prev_grid_out)
194
195 allocate(prev_grid_in, source = grid_in)
196 allocate(prev_grid_out, source = grid_out)
197 end if
198 end if
199
200 select type(grid_out)
201 type is(ip_station_points_grid)
202 to_station_points = .true.
203 class default
204 to_station_points = .false.
205 end select
206 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
207 ! SAVE OR SKIP WEIGHT COMPUTATION
208 IF(iret.EQ.0.AND.(to_station_points.OR..NOT.same_gridi.OR..NOT.same_grido))THEN
209 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
210 ! COMPUTE NUMBER OF OUTPUT POINTS AND THEIR LATITUDES AND LONGITUDES.
211 IF(.not. to_station_points) THEN
212 CALL gdswzd(grid_out, 0,mo,fill,xpts,ypts,rlon,rlat,no)
213 IF(no.EQ.0) iret=3
214 ENDIF
215 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
216 ! LOCATE INPUT POINTS
217 CALL gdswzd(grid_in,-1,no,fill,xpts,ypts,rlon,rlat,nv)
218 IF(iret.EQ.0.AND.nv.EQ.0) iret=2
219 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
220 ! ALLOCATE AND SAVE GRID DATA
221 IF(nox.NE.no) THEN
222 IF(nox.GE.0) DEALLOCATE(rlatx,rlonx,xptsx,yptsx,nxy)
223 ALLOCATE(rlatx(no),rlonx(no),xptsx(no),yptsx(no),nxy(no))
224 nox=no
225 ENDIF
226 iretx=iret
227 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
228 ! COMPUTE WEIGHTS
229 IF(iret.EQ.0) THEN
230 !$OMP PARALLEL DO PRIVATE(N) SCHEDULE(STATIC)
231 DO n=1,no
232 rlonx(n)=rlon(n)
233 rlatx(n)=rlat(n)
234 xptsx(n)=xpts(n)
235 yptsx(n)=ypts(n)
236 IF(xpts(n).NE.fill.AND.ypts(n).NE.fill) THEN
237 nxy(n) = grid_in%field_pos(nint(xpts(n)), nint(ypts(n)))
238 ELSE
239 nxy(n)=0
240 ENDIF
241 ENDDO
242 ENDIF
243 ENDIF
244 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
245 ! INTERPOLATE OVER ALL FIELDS
246 IF(iret.EQ.0.AND.iretx.EQ.0) THEN
247 IF(.not. to_station_points) THEN
248 no=nox
249 DO n=1,no
250 rlon(n)=rlonx(n)
251 rlat(n)=rlatx(n)
252 ENDDO
253 ENDIF
254 DO n=1,no
255 xpts(n)=xptsx(n)
256 ypts(n)=yptsx(n)
257 ENDDO
258 !$OMP PARALLEL DO PRIVATE(NK,K,N,I1,J1,IXS,JXS,MX,KXS,KXT,IX,JX,NX) SCHEDULE(STATIC)
259 DO nk=1,no*km
260 k=(nk-1)/no+1
261 n=nk-no*(k-1)
262 go(n,k)=0
263 lo(n,k)=.false.
264 IF(nxy(n).GT.0) THEN
265 IF(ibi(k).EQ.0.OR.li(nxy(n),k)) THEN
266 go(n,k)=gi(nxy(n),k)
267 lo(n,k)=.true.
268 ! SPIRAL AROUND UNTIL VALID DATA IS FOUND.
269 ELSEIF(mspiral.GT.1) THEN
270 i1=nint(xpts(n))
271 j1=nint(ypts(n))
272 ixs=sign(1.,xpts(n)-i1)
273 jxs=sign(1.,ypts(n)-j1)
274 DO mx=2,mspiral**2
275 kxs=sqrt(4*mx-2.5)
276 kxt=mx-(kxs**2/4+1)
277 SELECT CASE(mod(kxs,4))
278 CASE(1)
279 ix=i1-ixs*(kxs/4-kxt)
280 jx=j1-jxs*kxs/4
281 CASE(2)
282 ix=i1+ixs*(1+kxs/4)
283 jx=j1-jxs*(kxs/4-kxt)
284 CASE(3)
285 ix=i1+ixs*(1+kxs/4-kxt)
286 jx=j1+jxs*(1+kxs/4)
287 CASE DEFAULT
288 ix=i1-ixs*kxs/4
289 jx=j1+jxs*(kxs/4-kxt)
290 END SELECT
291 nx = grid_in%field_pos(ix, jx)
292 IF(nx.GT.0) THEN
293 IF(li(nx,k)) THEN
294 go(n,k)=gi(nx,k)
295 lo(n,k)=.true.
296 EXIT
297 ENDIF
298 ENDIF
299 ENDDO
300 ENDIF
301 ENDIF
302 ENDDO
303
304 DO k=1,km
305 ibo(k)=ibi(k)
306 IF(.NOT.all(lo(1:no,k))) ibo(k)=1
307 ENDDO
308
309 select type(grid_out)
310 type is(ip_equid_cylind_grid)
311 CALL polfixs(no,mo,km,rlat,ibo,lo,go)
312 end select
313 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
314 ELSE
315 IF(iret.EQ.0) iret=iretx
316 IF(.not. to_station_points) no=0
317 ENDIF
318 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
319 END SUBROUTINE interpolate_neighbor_scalar
320
321 SUBROUTINE interpolate_neighbor_vector(IPOPT,grid_in,grid_out, &
322 MI,MO,KM,IBI,LI,UI,VI, &
323 NO,RLAT,RLON,CROT,SROT,IBO,LO,UO,VO,IRET)
324 !$$$ SUBPROGRAM DOCUMENTATION BLOCK
325 !
326 ! SUBPROGRAM: POLATEV2 INTERPOLATE VECTOR FIELDS (NEIGHBOR)
327 ! PRGMMR: IREDELL ORG: W/NMC23 DATE: 96-04-10
328 !
329 ! ABSTRACT: THIS SUBPROGRAM PERFORMS NEIGHBOR INTERPOLATION
330 ! FROM ANY GRID TO ANY GRID FOR VECTOR FIELDS.
331 ! OPTIONS ALLOW CHOOSING THE WIDTH OF THE GRID SQUARE
332 ! (IPOPT(1)) TO SEARCH FOR VALID DATA, WHICH DEFAULTS TO 1
333 ! (IF IPOPT(1)=-1). ODD WIDTH SQUARES ARE CENTERED ON
334 ! THE NEAREST INPUT GRID POINT; EVEN WIDTH SQUARES ARE
335 ! CENTERED ON THE NEAREST FOUR INPUT GRID POINTS.
336 ! SQUARES ARE SEARCHED FOR VALID DATA IN A SPIRAL PATTERN
337 ! STARTING FROM THE CENTER. NO SEARCHING IS DONE WHERE
338 ! THE OUTPUT GRID IS OUTSIDE THE INPUT GRID.
339 ! ONLY HORIZONTAL INTERPOLATION IS PERFORMED.
340 !
341 ! THE INPUT AND OUTPUT GRIDS ARE DEFINED BY THEIR GRIB 2 GRID
342 ! DEFINITION TEMPLATE AS DECODED BY THE NCEP G2 LIBRARY. THE
343 ! CODE RECOGNIZES THE FOLLOWING PROJECTIONS, WHERE
344 ! "IGDTNUMI/O" IS THE GRIB 2 GRID DEFINTION TEMPLATE NUMBER
345 ! FOR THE INPUT AND OUTPUT GRIDS, RESPECTIVELY:
346 ! (IGDTNUMI/O=00) EQUIDISTANT CYLINDRICAL
347 ! (IGDTNUMI/O=01) ROTATED EQUIDISTANT CYLINDRICAL. "E" AND
348 ! NON-"E" STAGGERED
349 ! (IGDTNUMI/O=10) MERCATOR CYLINDRICAL
350 ! (IGDTNUMI/O=20) POLAR STEREOGRAPHIC AZIMUTHAL
351 ! (IGDTNUMI/O=30) LAMBERT CONFORMAL CONICAL
352 ! (IGDTNUMI/O=40) GAUSSIAN CYLINDRICAL
353 !
354 ! THE INPUT AND OUTPUT VECTORS ARE ROTATED SO THAT THEY ARE
355 ! EITHER RESOLVED RELATIVE TO THE DEFINED GRID
356 ! IN THE DIRECTION OF INCREASING X AND Y COORDINATES
357 ! OR RESOLVED RELATIVE TO EASTERLY AND NORTHERLY DIRECTIONS,
358 ! AS DESIGNATED BY THEIR RESPECTIVE GRID DEFINITION SECTIONS.
359 !
360 ! AS AN ADDED BONUS THE NUMBER OF OUTPUT GRID POINTS
361 ! AND THEIR LATITUDES AND LONGITUDES ARE ALSO RETURNED
362 ! ALONG WITH THEIR VECTOR ROTATION PARAMETERS.
363 ! ON THE OTHER HAND, THE OUTPUT CAN BE A SET OF STATION POINTS
364 ! IF IGDTNUMO<0, IN WHICH CASE THE NUMBER OF POINTS
365 ! AND THEIR LATITUDES AND LONGITUDES MUST BE INPUT
366 ! ALONG WITH THEIR VECTOR ROTATION PARAMETERS.
367 !
368 ! INPUT BITMAPS WILL BE INTERPOLATED TO OUTPUT BITMAPS.
369 ! OUTPUT BITMAPS WILL ALSO BE CREATED WHEN THE OUTPUT GRID
370 ! EXTENDS OUTSIDE OF THE DOMAIN OF THE INPUT GRID.
371 ! THE OUTPUT FIELD IS SET TO 0 WHERE THE OUTPUT BITMAP IS OFF.
372 !
373 ! PROGRAM HISTORY LOG:
374 ! 96-04-10 IREDELL
375 ! 1999-04-08 IREDELL SPLIT IJKGDS INTO TWO PIECES
376 ! 2001-06-18 IREDELL INCLUDE SPIRAL SEARCH OPTION
377 ! 2002-01-17 IREDELL SAVE DATA FROM LAST CALL FOR OPTIMIZATION
378 ! 2006-01-04 GAYNO MINOR BUG FIX
379 ! 2007-10-30 IREDELL SAVE WEIGHTS AND THREAD FOR PERFORMANCE
380 ! 2012-06-26 GAYNO FIX OUT-OF-BOUNDS ERROR. SEE NCEPLIBS
381 ! TICKET #9.
382 ! 2015-01-27 GAYNO REPLACE CALLS TO GDSWIZ WITH NEW MERGED
383 ! ROUTINE GDSWZD.
384 ! 2015-07-13 GAYNO CONVERT TO GRIB 2. REPLACE GRIB 1 KGDS ARRAYS
385 ! WITH GRIB 2 GRID DEFINITION TEMPLATE ARRAYS.
386 !
387 ! USAGE: CALL POLATEV2(IPOPT,IGDTNUMI,IGDTMPLI,IGDTLENI, &
388 ! IGDTNUMO,IGDTMPLO,IGDTLENO, &
389 ! MI,MO,KM,IBI,LI,UI,VI, &
390 ! NO,RLAT,RLON,CROT,SROT,IBO,LO,UO,VO,IRET)
391 !
392 ! INPUT ARGUMENT LIST:
393 ! IPOPT - INTEGER (20) INTERPOLATION OPTIONS
394 ! IPOPT(1) IS WIDTH OF SQUARE TO EXAMINE IN SPIRAL SEARCH
395 ! (DEFAULTS TO 1 IF IPOPT(1)=-1)
396 ! IGDTNUMI - INTEGER GRID DEFINITION TEMPLATE NUMBER - INPUT GRID.
397 ! CORRESPONDS TO THE GFLD%IGDTNUM COMPONENT OF THE
398 ! NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE:
399 ! 00 - EQUIDISTANT CYLINDRICAL
400 ! 01 - ROTATED EQUIDISTANT CYLINDRICAL. "E"
401 ! AND NON-"E" STAGGERED
402 ! 10 - MERCATOR CYCLINDRICAL
403 ! 20 - POLAR STEREOGRAPHIC AZIMUTHAL
404 ! 30 - LAMBERT CONFORMAL CONICAL
405 ! 40 - GAUSSIAN EQUIDISTANT CYCLINDRICAL
406 ! IGDTMPLI - INTEGER (IGDTLENI) GRID DEFINITION TEMPLATE ARRAY -
407 ! INPUT GRID. CORRESPONDS TO THE GFLD%IGDTMPL COMPONENT
408 ! OF THE NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE
409 ! (SECTION 3 INFO). SEE COMMENTS IN ROUTINE
410 ! IPOLATEV FOR COMPLETE DEFINITION.
411 ! IGDTLENI - INTEGER NUMBER OF ELEMENTS OF THE GRID DEFINITION
412 ! TEMPLATE ARRAY - INPUT GRID. CORRESPONDS TO THE GFLD%IGDTLEN
413 ! COMPONENT OF THE NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE.
414 ! IGDTNUMO - INTEGER GRID DEFINITION TEMPLATE NUMBER - OUTPUT GRID.
415 ! CORRESPONDS TO THE GFLD%IGDTNUM COMPONENT OF THE
416 ! NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE. IGDTNUMO<0
417 ! MEANS INTERPOLATE TO RANDOM STATION POINTS.
418 ! OTHERWISE, SAME DEFINITION AS "IGDTNUMI".
419 ! IGDTMPLO - INTEGER (IGDTLENO) GRID DEFINITION TEMPLATE ARRAY -
420 ! OUTPUT GRID. CORRESPONDS TO THE GFLD%IGDTMPL COMPONENT
421 ! OF THE NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE.
422 ! (SECTION 3 INFO). SEE COMMENTS IN ROUTINE
423 ! IPOLATEV FOR COMPLETE DEFINITION.
424 ! IGDTLENO - INTEGER NUMBER OF ELEMENTS OF THE GRID DEFINITION
425 ! TEMPLATE ARRAY - OUTPUT GRID. CORRESPONDS TO THE GFLD%IGDTLEN
426 ! COMPONENT OF THE NCEP G2 LIBRARY GRIDMOD DATA STRUCTURE.
427 ! MI - INTEGER SKIP NUMBER BETWEEN INPUT GRID FIELDS IF KM>1
428 ! OR DIMENSION OF INPUT GRID FIELDS IF KM=1
429 ! MO - INTEGER SKIP NUMBER BETWEEN OUTPUT GRID FIELDS IF KM>1
430 ! OR DIMENSION OF OUTPUT GRID FIELDS IF KM=1
431 ! KM - INTEGER NUMBER OF FIELDS TO INTERPOLATE
432 ! IBI - INTEGER (KM) INPUT BITMAP FLAGS
433 ! LI - LOGICAL*1 (MI,KM) INPUT BITMAPS (IF SOME IBI(K)=1)
434 ! UI - REAL (MI,KM) INPUT U-COMPONENT FIELDS TO INTERPOLATE
435 ! VI - REAL (MI,KM) INPUT V-COMPONENT FIELDS TO INTERPOLATE
436 ! RLAT - REAL (MO) OUTPUT LATITUDES IN DEGREES (IF IGDTNUMO<0)
437 ! RLON - REAL (MO) OUTPUT LONGITUDES IN DEGREES (IF IGDTNUMO<0)
438 ! CROT - REAL (MO) VECTOR ROTATION COSINES (IF IGDTNUMO<0)
439 ! SROT - REAL (MO) VECTOR ROTATION SINES (IF IGDTNUMO<0)
440 ! (UGRID=CROT*UEARTH-SROT*VEARTH;
441 ! VGRID=SROT*UEARTH+CROT*VEARTH)
442 !
443 ! OUTPUT ARGUMENT LIST:
444 ! NO - INTEGER NUMBER OF OUTPUT POINTS (ONLY IF IGDTNUMO>=0)
445 ! RLAT - REAL (MO) OUTPUT LATITUDES IN DEGREES (IF IGDTNUMO>=0)
446 ! RLON - REAL (MO) OUTPUT LONGITUDES IN DEGREES (IF IGDTNUMO>=0)
447 ! CROT - REAL (NO) VECTOR ROTATION COSINES (IF IGDTNUMO>=0)
448 ! SROT - REAL (NO) VECTOR ROTATION SINES (IF IGDTNUMO>=0)
449 ! (UGRID=CROT*UEARTH-SROT*VEARTH;
450 ! VGRID=SROT*UEARTH+CROT*VEARTH)
451 ! IBO - INTEGER (KM) OUTPUT BITMAP FLAGS
452 ! LO - LOGICAL*1 (MO,KM) OUTPUT BITMAPS (ALWAYS OUTPUT)
453 ! UO - REAL (MO,KM) OUTPUT U-COMPONENT FIELDS INTERPOLATED
454 ! VO - REAL (MO,KM) OUTPUT V-COMPONENT FIELDS INTERPOLATED
455 ! IRET - INTEGER RETURN CODE
456 ! 0 SUCCESSFUL INTERPOLATION
457 ! 2 UNRECOGNIZED INPUT GRID OR NO GRID OVERLAP
458 ! 3 UNRECOGNIZED OUTPUT GRID
459 !
460 ! SUBPROGRAMS CALLED:
461 ! CHECK_GRIDS2V CHECK IF INPUT OR OUTPUT GRIDS HAVE CHANGED
462 ! GDSWZD GRID DESCRIPTION SECTION WIZARD
463 ! MOVECT MOVE A VECTOR ALONG A GREAT CIRCLE
464 ! POLFIXV MAKE MULTIPLE POLE VECTOR VALUES CONSISTENT
465 !
466 ! ATTRIBUTES:
467 ! LANGUAGE: FORTRAN 90
468 !
469 !$$$
470
471 class(ip_grid), intent(in) :: grid_in, grid_out
472 INTEGER, INTENT(IN ) :: IPOPT(20)
473 INTEGER, INTENT(IN ) :: IBI(KM),MI,MO,KM
474 INTEGER, INTENT(INOUT) :: NO
475 INTEGER, INTENT( OUT) :: IRET, IBO(KM)
476 !
477 LOGICAL*1, INTENT(IN ) :: LI(MI,KM)
478 LOGICAL*1, INTENT( OUT) :: LO(MO,KM)
479 !
480 REAL, INTENT(IN ) :: UI(MI,KM),VI(MI,KM)
481 REAL, INTENT(INOUT) :: CROT(MO),SROT(MO)
482 REAL, INTENT(INOUT) :: RLAT(MO),RLON(MO)
483 REAL, INTENT( OUT) :: UO(MO,KM),VO(MO,KM)
484 !
485 REAL, PARAMETER :: FILL=-9999.
486 !
487 INTEGER :: I1,J1,IXS,JXS,MX
488 INTEGER :: KXS,KXT,IX,JX,NX
489 INTEGER :: MSPIRAL,N,K,NK,NV
490 !
491 LOGICAL :: SAME_GRIDI, SAME_GRIDO
492 !
493 REAL :: CX,SX,CM,SM,UROT,VROT
494 REAL :: XPTS(MO),YPTS(MO)
495 REAL :: CROI(MI),SROI(MI)
496 REAL :: XPTI(MI),YPTI(MI),RLOI(MI),RLAI(MI)
497
498 logical :: to_station_points
499
500 INTEGER, SAVE :: NOX=-1,iretx=-1
501 INTEGER, ALLOCATABLE, SAVE :: NXY(:)
502
503 REAL, ALLOCATABLE, SAVE :: RLATX(:),RLONX(:),XPTSX(:),YPTSX(:)
504 REAL, ALLOCATABLE, SAVE :: CROTX(:),SROTX(:),CXY(:),SXY(:)
505 class(ip_grid), allocatable, save :: prev_grid_in, prev_grid_out
506 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
507 ! SET PARAMETERS
508 iret=0
509 mspiral=max(ipopt(1),1)
510 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
511
512 if (.not. allocated(prev_grid_in) .or. .not. allocated(prev_grid_out)) then
513 allocate(prev_grid_in, source = grid_in)
514 allocate(prev_grid_out, source = grid_out)
515
516 same_gridi = .false.
517 same_grido = .false.
518 else
519 same_gridi = grid_in == prev_grid_in
520 same_grido = grid_out == prev_grid_out
521
522 if (.not. same_gridi .or. .not. same_grido) then
523 deallocate(prev_grid_in)
524 deallocate(prev_grid_out)
525
526 allocate(prev_grid_in, source = grid_in)
527 allocate(prev_grid_out, source = grid_out)
528 end if
529 end if
530
531 select type(grid_out)
532 type is(ip_station_points_grid)
533 to_station_points = .true.
534 class default
535 to_station_points = .false.
536 end select
537
538 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
539 ! SAVE OR SKIP WEIGHT COMPUTATION
540 IF(iret.EQ.0.AND.(to_station_points.OR..NOT.same_gridi.OR..NOT.same_grido))THEN
541 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
542 ! COMPUTE NUMBER OF OUTPUT POINTS AND THEIR LATITUDES AND LONGITUDES.
543 IF(.not. to_station_points) THEN
544 CALL gdswzd(grid_out, 0,mo,fill,xpts,ypts,rlon,rlat, &
545 no,crot,srot)
546 IF(no.EQ.0) iret=3
547 ENDIF
548 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
549 ! LOCATE INPUT POINTS
550 CALL gdswzd(grid_in,-1,no,fill,xpts,ypts,rlon,rlat,nv)
551 IF(iret.EQ.0.AND.nv.EQ.0) iret=2
552 CALL gdswzd(grid_in, 0,mi,fill,xpti,ypti,rloi,rlai, &
553 nv,croi,sroi)
554 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
555 ! ALLOCATE AND SAVE GRID DATA
556 IF(nox.NE.no) THEN
557 IF(nox.GE.0) DEALLOCATE(rlatx,rlonx,xptsx,yptsx,crotx,srotx,nxy,cxy,sxy)
558 ALLOCATE(rlatx(no),rlonx(no),xptsx(no),yptsx(no), &
559 crotx(no),srotx(no),nxy(no),cxy(no),sxy(no))
560 nox=no
561 ENDIF
562 iretx=iret
563 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
564 ! COMPUTE WEIGHTS
565 IF(iret.EQ.0) THEN
566 !$OMP PARALLEL DO PRIVATE(N,CM,SM) SCHEDULE(STATIC)
567 DO n=1,no
568 rlonx(n)=rlon(n)
569 rlatx(n)=rlat(n)
570 xptsx(n)=xpts(n)
571 yptsx(n)=ypts(n)
572 crotx(n)=crot(n)
573 srotx(n)=srot(n)
574 IF(xpts(n).NE.fill.AND.ypts(n).NE.fill) THEN
575 nxy(n) = grid_in%field_pos(nint(xpts(n)),nint(ypts(n)))
576 IF(nxy(n).GT.0) THEN
577 CALL movect(rlai(nxy(n)),rloi(nxy(n)),rlat(n),rlon(n),cm,sm)
578 cxy(n)=cm*croi(nxy(n))+sm*sroi(nxy(n))
579 sxy(n)=sm*croi(nxy(n))-cm*sroi(nxy(n))
580 ENDIF
581 ELSE
582 nxy(n)=0
583 ENDIF
584 ENDDO
585 ENDIF
586 ENDIF
587 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
588 ! INTERPOLATE OVER ALL FIELDS
589 IF(iret.EQ.0.AND.iretx.EQ.0) THEN
590 IF(.not. to_station_points) THEN
591 no=nox
592 DO n=1,no
593 rlon(n)=rlonx(n)
594 rlat(n)=rlatx(n)
595 crot(n)=crotx(n)
596 srot(n)=srotx(n)
597 ENDDO
598 ENDIF
599 DO n=1,no
600 xpts(n)=xptsx(n)
601 ypts(n)=yptsx(n)
602 ENDDO
603 !$OMP PARALLEL DO &
604 !$OMP PRIVATE(NK,K,N,I1,J1,IXS,JXS,MX,KXS,KXT,IX,JX,NX) &
605 !$OMP PRIVATE(CM,SM,CX,SX,UROT,VROT) SCHEDULE(STATIC)
606 DO nk=1,no*km
607 k=(nk-1)/no+1
608 n=nk-no*(k-1)
609 uo(n,k)=0
610 vo(n,k)=0
611 lo(n,k)=.false.
612 IF(nxy(n).GT.0) THEN
613 IF(ibi(k).EQ.0.OR.li(nxy(n),k)) THEN
614 urot=cxy(n)*ui(nxy(n),k)-sxy(n)*vi(nxy(n),k)
615 vrot=sxy(n)*ui(nxy(n),k)+cxy(n)*vi(nxy(n),k)
616 uo(n,k)=crot(n)*urot-srot(n)*vrot
617 vo(n,k)=srot(n)*urot+crot(n)*vrot
618 lo(n,k)=.true.
619 ! SPIRAL AROUND UNTIL VALID DATA IS FOUND.
620 ELSEIF(mspiral.GT.1) THEN
621 i1=nint(xpts(n))
622 j1=nint(ypts(n))
623 ixs=sign(1.,xpts(n)-i1)
624 jxs=sign(1.,ypts(n)-j1)
625 DO mx=2,mspiral**2
626 kxs=sqrt(4*mx-2.5)
627 kxt=mx-(kxs**2/4+1)
628 SELECT CASE(mod(kxs,4))
629 CASE(1)
630 ix=i1-ixs*(kxs/4-kxt)
631 jx=j1-jxs*kxs/4
632 CASE(2)
633 ix=i1+ixs*(1+kxs/4)
634 jx=j1-jxs*(kxs/4-kxt)
635 CASE(3)
636 ix=i1+ixs*(1+kxs/4-kxt)
637 jx=j1+jxs*(1+kxs/4)
638 CASE DEFAULT
639 ix=i1-ixs*kxs/4
640 jx=j1+jxs*(kxs/4-kxt)
641 END SELECT
642 nx = grid_in%field_pos(ix, jx)
643 IF(nx.GT.0) THEN
644 IF(li(nx,k)) THEN
645 CALL movect(rlai(nx),rloi(nx),rlat(n),rlon(n),cm,sm)
646 cx=cm*croi(nx)+sm*sroi(nx)
647 sx=sm*croi(nx)-cm*sroi(nx)
648 urot=cx*ui(nx,k)-sx*vi(nx,k)
649 vrot=sx*ui(nx,k)+cx*vi(nx,k)
650 uo(n,k)=crot(n)*urot-srot(n)*vrot
651 vo(n,k)=srot(n)*urot+crot(n)*vrot
652 lo(n,k)=.true.
653 EXIT
654 ENDIF
655 ENDIF
656 ENDDO
657 ENDIF
658 ENDIF
659 ENDDO
660 DO k=1,km
661 ibo(k)=ibi(k)
662 IF(.NOT.all(lo(1:no,k))) ibo(k)=1
663 ENDDO
664
665 select type(grid_out)
666 type is(ip_equid_cylind_grid)
667 CALL polfixv(no,mo,km,rlat,rlon,ibo,lo,uo,vo)
668 end select
669
670 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
671 ELSE
672 IF(iret.EQ.0) iret=iretx
673 IF(.not. to_station_points) no=0
674 ENDIF
675 ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
676 END SUBROUTINE interpolate_neighbor_vector
677
678end module neighbor_interp_mod
Driver module for gdswzd routines.
Definition: gdswzd_mod.f90:25