Line data Source code
1 : module rgrd_mod
2 : implicit none
3 : private
4 :
5 : public :: rgrd2
6 :
7 : contains
8 :
9 : !
10 : !
11 : ! ... file rgrd2.f
12 :
13 : ! this file contains documentation for subroutine rgrd2 followed by
14 : ! fortran code for rgrd2 and additional subroutines.
15 :
16 : ! ... author
17 :
18 : ! John C. Adams (NCAR 1997)
19 :
20 : ! ... subroutine rgrd2(nx,ny,x,y,p,mx,my,xx,yy,q,intpol,w,lw,iw,liw,ier)
21 :
22 : ! ... purpose
23 :
24 : ! subroutine rgrd2 interpolates the values p(i,j) on the orthogonal
25 : ! grid (x(i),y(j)) for i=1,...,nx and j=1,...,ny onto q(ii,jj) on the
26 : ! orthogonal grid (xx(ii),yy(jj)) for ii=1,...,mx and jj=1,...,my.
27 :
28 : ! ... language
29 :
30 : ! coded in portable FORTRAN77 and FORTRAN90
31 :
32 : ! ... test program
33 :
34 : ! file trgrd2.f on regridpack includes a test program for subroutine rgrd2
35 :
36 : ! ... method
37 :
38 : ! linear or cubic interpolation is used (independently) in
39 : ! each direction (see argument intpol).
40 :
41 : ! ... required files
42 :
43 : ! file rgrd1.f must be loaded with rgrd2.f. it includes
44 : ! subroutines called by the routines in rgrd2.f
45 :
46 : ! ... requirements
47 :
48 : ! each of the x,y grids must be strictly montonically increasing
49 : ! and each of the xx,yy grids must be montonically increasing (see
50 : ! ier = 4). in addition the (X,Y) region
51 :
52 : ! [xx(1),xx(mx)] X [yy(1),yy(my)]
53 :
54 : ! must lie within the (X,Y) region
55 :
56 : ! [x(1),x(nx)] X [y(1),y(ny)].
57 :
58 : ! extrapolation is not allowed (see ier=3). if these (X,Y)
59 : ! regions are identical and the orthogonal grids are UNIFORM
60 : ! in each direction then subroutine rgrd2u (see file rgrd2u.f)
61 : ! should be used instead of rgrd2.
62 :
63 : ! ... efficiency
64 :
65 : ! inner most loops in regridpack software vectorize.
66 : ! If the arguments mx,my (see below) have different values, optimal
67 : ! vectorization will be achieved if mx > my.
68 :
69 :
70 : ! *** input argument
71 :
72 :
73 : ! ... nx
74 :
75 : ! the integer dimension of the grid vector x and the first dimension
76 : ! of p. nx > 1 if intpol(1) = 1 or nx > 3 if intpol(1) = 3 is required.
77 :
78 : ! ... ny
79 :
80 : ! the integer dimension of the grid vector y and the second dimension
81 : ! of p. ny > 1 if intpol(2) = 1 or ny > 3 if intpol(2) = 3 is required.
82 :
83 : ! ... x
84 :
85 : ! a real nx vector of strictly increasing values which defines the x
86 : ! portion of the orthogonal grid on which p is given
87 :
88 : ! ... y
89 :
90 : ! a real ny vector of strictly increasing values which defines the y
91 : ! portion of the orthogonal grid on which p is given
92 :
93 : ! ... p
94 :
95 : ! a real nx by ny array of values given on the orthogonal (x,y) grid
96 :
97 : ! ... mx
98 :
99 : ! the integer dimension of the grid vector xx and the first dimension
100 : ! of q. mx > 0 is required.
101 :
102 : ! ... my
103 :
104 : ! the integer dimension of the grid vector yy and the second dimension
105 : ! of q. my > 0 is required.
106 :
107 : ! ... xx
108 :
109 : ! a real mx vector of increasing values which defines the x portion of the
110 : ! orthogonal grid on which q is defined. xx(1) < x(1) or xx(mx) > x(nx)
111 : ! is not allowed (see ier = 3)
112 :
113 : ! ... yy
114 :
115 : ! a real my vector of increasing values which defines the y portion of the
116 : ! orthogonal grid on which q is defined. yy(1) < y(1) or yy(my) > y(ny)
117 : ! is not allowed (see ier = 3)
118 :
119 : ! ... intpol
120 :
121 : ! an integer vector of dimension 2 which sets linear or cubic
122 : ! interpolation in the x,y directions as follows:
123 :
124 : ! intpol(1) = 1 sets linear interpolation in the x direction
125 : ! intpol(1) = 3 sets cubic interpolation in the x direction.
126 :
127 : ! intpol(2) = 1 sets linear interpolation in the y direction
128 : ! intpol(2) = 3 sets cubic interpolation in the y direction.
129 :
130 : ! values other than 1 or 3 in intpol are not allowed (ier = 5).
131 :
132 : ! ... w
133 :
134 : ! a real work space of length at least lw which must be provided in the
135 : ! routine calling rgrd2
136 :
137 : ! ... lw
138 :
139 : ! the integer length of the real work space w. let
140 :
141 : ! lwx = mx if intpol(1) = 1
142 : ! lwx = 4*mx if intpol(1) = 3
143 :
144 : ! lwy = my+2*mx if intpol(2) = 1
145 : ! lwy = 4*(mx+my) if intpol(2) = 3
146 :
147 : ! then lw must be greater than or equal to lwx+lwy
148 :
149 : ! ... iw
150 :
151 : ! an integer work space of length at least liw which must be provided in the
152 : ! routine calling rgrd2
153 :
154 : ! ... liw
155 :
156 : ! the integer length of the integer work space iw. liw must be at least mx+my
157 :
158 : ! *** output arguments
159 :
160 :
161 : ! ... q
162 :
163 : ! a real mx by my array of values on the (xx,yy) grid which are
164 : ! interpolated from p on the (x,y) grid
165 :
166 : ! ... ier
167 :
168 : ! an integer error flag set as follows:
169 :
170 : ! ier = 0 if no errors in input arguments are detected
171 :
172 : ! ier = 1 if min0(mx,my) < 1
173 :
174 : ! ier = 2 if nx < 2 when intpol(1)=1 or nx < 4 when intpol(1)=3 (or)
175 : ! ny < 2 when intpol(2)=1 or ny < 4 when intpol(2)=3
176 :
177 : ! ier = 3 if xx(1) < x(1) or x(nx) < xx(mx) (or)
178 : ! yy(1) < y(1) or y(ny) < yy(my) (or)
179 :
180 : ! *** to avoid this flag when end points are intended to be the
181 : ! same but may differ slightly due to roundoff error, they
182 : ! should be set exactly in the calling routine (e.g., if both
183 : ! grids have the same y boundaries then yy(1)=y(1) and yy(my)=y(ny)
184 : ! should be set before calling rgrd2)
185 :
186 : ! ier = 4 if one of the grids x,y is not strictly monotonically
187 : ! increasing or if one of the grids xx,yy is not
188 : ! montonically increasing. more precisely if:
189 :
190 : ! x(i+1) <= x(i) for some i such that 1 <= i < nx (or)
191 :
192 : ! y(j+1) <= y(j) for some j such that 1 <= j < ny (or)
193 :
194 : ! xx(ii+1) < xx(ii) for some ii such that 1 <= ii < mx (or)
195 :
196 : ! yy(jj+1) < yy(jj) for some jj such that 1 <= jj < my
197 :
198 : ! ier = 5 if lw or liw is to small (insufficient work space)
199 :
200 : ! ier = 6 if intpol(1) or intpol(2) is not equal to 1 or 3
201 :
202 : ! ************************************************************************
203 :
204 : ! end of rgrd2 documentation, fortran code follows:
205 :
206 : ! ************************************************************************
207 :
208 0 : subroutine rgrd2(nx,ny,x,y,p,mx,my,xx,yy,q,intpol,w,lw,iw,liw,ier)
209 :
210 : use shr_kind_mod,only: r8 => shr_kind_r8
211 :
212 : implicit none
213 :
214 : integer, intent(in) :: nx
215 : integer, intent(in) :: ny
216 : real(r8), intent(in) :: x(nx)
217 : real(r8), intent(in) :: y(ny)
218 : real(r8), intent(inout) :: p(nx,ny)
219 : integer, intent(in) :: mx
220 : integer, intent(in) :: my
221 : real(r8), intent(in) :: xx(mx)
222 : real(r8), intent(in) :: yy(my)
223 : real(r8), intent(out) :: q(mx,my)
224 : integer, intent(in) :: intpol(2)
225 : integer, intent(inout) :: lw
226 : real(r8), intent(inout) :: w(lw)
227 : integer, intent(inout) :: liw
228 : integer, intent(inout) :: iw(liw)
229 : integer, intent(out) :: ier
230 :
231 :
232 : integer :: i,ii,j,jj,j2,j3,j4,j5,j6,j7,j8,j9,i2,i3,i4,i5
233 : integer :: jy,lwx,lwy
234 :
235 :
236 : ! check input arguments
237 :
238 0 : ier = 1
239 :
240 : ! check (xx,yy) grid resolution
241 :
242 0 : IF (MIN0(mx,my) < 1) RETURN
243 :
244 : ! check intpol
245 :
246 0 : ier = 6
247 0 : IF (intpol(1) /= 1 .AND. intpol(1) /= 3) RETURN
248 0 : IF (intpol(2) /= 1 .AND. intpol(2) /= 3) RETURN
249 : ! write(6,"('rgrd2: nx,ny,mx,my = ',6i6)") nx,ny,mx,my,intpol
250 : ! write(6,"('rgrd2: alatm = ',/,(6e12.4))") y
251 : ! write(6,"('rgrd2: ylatm = ',/,(6e12.4))") yy
252 : ! write(6,"('rgrd2: ylonm = ',/,(6e12.4))") xx
253 : ! write(6,"('rgrd2: potm(1,:) = ',/,(8e12.4))") p(1,:)
254 :
255 : ! check (x,y) grid resolution
256 :
257 0 : ier = 2
258 0 : IF (intpol(1) == 1 .AND. nx < 2) RETURN
259 0 : IF (intpol(1) == 3 .AND. nx < 4) RETURN
260 0 : IF (intpol(2) == 1 .AND. ny < 2) RETURN
261 0 : IF (intpol(2) == 3 .AND. ny < 4) RETURN
262 :
263 : ! check work space lengths
264 :
265 0 : ier = 5
266 0 : IF (intpol(1) == 1) THEN
267 : lwx = mx
268 : ELSE
269 0 : lwx = 4*mx
270 : END IF
271 0 : IF (intpol(2) == 1) THEN
272 0 : lwy = my+2*mx
273 : ELSE
274 0 : lwy = 4*(mx+my)
275 : END IF
276 0 : IF (lw < lwx+lwy) RETURN
277 0 : IF (liw < mx+my) RETURN
278 :
279 : ! check (xx,yy) grid contained in (x,y) grid
280 :
281 0 : ier = 3
282 0 : IF (xx(1) < x(1) .OR. xx(mx) > x(nx)) RETURN
283 0 : IF (yy(1) < y(1) .OR. yy(my) > y(ny)) RETURN
284 :
285 : ! check montonicity of grids
286 :
287 0 : ier = 4
288 0 : DO i=2,nx
289 0 : IF (x(i-1) >= x(i)) RETURN
290 : END DO
291 0 : DO j=2,ny
292 0 : IF (y(j-1) >= y(j)) RETURN
293 : END DO
294 0 : DO ii=2,mx
295 0 : IF (xx(ii-1) > xx(ii)) RETURN
296 : END DO
297 0 : DO jj=2,my
298 0 : IF (yy(jj-1) > yy(jj)) RETURN
299 : END DO
300 :
301 : ! arguments o.k.
302 :
303 0 : ier = 0
304 :
305 : ! set pointer in integer work space
306 :
307 0 : jy = mx+1
308 0 : IF (intpol(2) == 1) THEN
309 :
310 : ! linearly interpolate in y
311 :
312 0 : j2 = 1
313 0 : j3 = j2
314 0 : j4 = j3+my
315 0 : j5 = j4
316 0 : j6 = j5
317 0 : j7 = j6
318 0 : j8 = j7+mx
319 0 : j9 = j8+mx
320 :
321 : ! set y interpolation indices and scales and linearly interpolate
322 :
323 0 : CALL linmx(ny,y,my,yy,iw(jy),w(j3))
324 0 : i2 = j9
325 :
326 : ! set work space portion and indices which depend on x interpolation
327 :
328 0 : IF (intpol(1) == 1) THEN
329 0 : i3 = i2
330 0 : i4 = i3
331 0 : i5 = i4
332 0 : CALL linmx(nx,x,mx,xx,iw,w(i3))
333 : ELSE
334 0 : i3 = i2+mx
335 0 : i4 = i3+mx
336 0 : i5 = i4+mx
337 0 : CALL cubnmx(nx,x,mx,xx,iw,w(i2),w(i3),w(i4),w(i5))
338 : END IF
339 : ! write(6,"('rgrd2: w(i2),w(i3),w(i4),w(i5) = ',4e12.4)")
340 : ! + w(i2),w(i3),w(i4),w(i5)
341 : CALL lint2(nx,ny,p,mx,my,q,intpol,iw(jy),w(j3), &
342 0 : w(j7),w(j8),iw,w(i2),w(i3),w(i4),w(i5))
343 :
344 : ! write(6,"('rgrd2: potout1 = ',/,(6e12.4))") q
345 :
346 0 : RETURN
347 :
348 : ELSE
349 :
350 : ! cubically interpolate in y, set indice pointers
351 :
352 0 : j2 = 1
353 0 : j3 = j2+my
354 0 : j4 = j3+my
355 0 : j5 = j4+my
356 0 : j6 = j5+my
357 0 : j7 = j6+mx
358 0 : j8 = j7+mx
359 0 : j9 = j8+mx
360 0 : CALL cubnmx(ny,y,my,yy,iw(jy),w(j2),w(j3),w(j4),w(j5))
361 0 : i2 = j9+mx
362 :
363 : ! set work space portion and indices which depend on x interpolation
364 :
365 0 : IF (intpol(1) == 1) THEN
366 0 : i3 = i2
367 0 : i4 = i3
368 0 : i5 = i4
369 0 : CALL linmx(nx,x,mx,xx,iw,w(i3))
370 : ELSE
371 0 : i3 = i2+mx
372 0 : i4 = i3+mx
373 0 : i5 = i4+mx
374 0 : CALL cubnmx(nx,x,mx,xx,iw,w(i2),w(i3),w(i4),w(i5))
375 : END IF
376 : CALL cubt2(nx,ny,p,mx,my,q,intpol,iw(jy),w(j2),w(j3), &
377 0 : w(j4),w(j5),w(j6),w(j7),w(j8),w(j9),iw,w(i2),w(i3),w(i4),w(i5))
378 :
379 : ! write(6,"('rgrd2: potout2 = ',/,(6e12.4))") q
380 :
381 0 : RETURN
382 : END IF
383 : END SUBROUTINE rgrd2
384 : !----------------------------------------------------------------------------
385 :
386 0 : subroutine lint2(nx,ny,p,mx,my,q,intpol,jy,dy,pj,pjp, ix,dxm,dx,dxp,dxpp)
387 :
388 : use shr_kind_mod,only: r8 => shr_kind_r8
389 :
390 : implicit none
391 :
392 : integer, intent(in) :: nx
393 : integer, intent(in) :: ny
394 : real(r8), intent(inout) :: p(nx,ny)
395 : integer, intent(in) :: mx
396 : integer, intent(in) :: my
397 : real(r8), intent(out) :: q(mx,my)
398 : integer, intent(in) :: intpol(2)
399 : integer, intent(in) :: jy(my)
400 : real(r8), intent(in) :: dy(my)
401 : real(r8), intent(out) :: pj(mx)
402 : real(r8), intent(inout) :: pjp(mx)
403 : integer, intent(inout) :: ix(mx)
404 : real(r8), intent(inout) :: dxm(mx)
405 : real(r8), intent(inout) :: dx(mx)
406 : real(r8), intent(inout) :: dxp(mx)
407 : real(r8), intent(inout) :: dxpp(mx)
408 :
409 : integer :: jsave,j,jj,ii
410 :
411 :
412 :
413 : ! linearly interpolate in y
414 :
415 0 : IF (intpol(1) == 1) THEN
416 :
417 : ! linear in x
418 :
419 : jsave = -1
420 0 : DO jj=1,my
421 0 : j = jy(jj)
422 0 : IF (j == jsave) THEN
423 :
424 : ! j pointer has not moved since last pass (no updates or interpolation)
425 :
426 0 : ELSE IF (j == jsave+1) THEN
427 :
428 : ! update j and interpolate j+1
429 :
430 0 : DO ii=1,mx
431 0 : pj(ii) = pjp(ii)
432 : END DO
433 0 : CALL lint1(nx,p(1,j+1),mx,pjp,ix,dx)
434 : ELSE
435 :
436 : ! interpolate j,j+1in pj,pjp on xx mesh
437 :
438 0 : CALL lint1(nx,p(1,j),mx,pj,ix,dx)
439 0 : CALL lint1(nx,p(1,j+1),mx,pjp,ix,dx)
440 : END IF
441 :
442 : ! save j pointer for next pass
443 :
444 0 : jsave = j
445 :
446 : ! linearly interpolate q(ii,jj) from pjp,pj in y direction
447 :
448 0 : DO ii=1,mx
449 0 : q(ii,jj) = pj(ii)+dy(jj)*(pjp(ii)-pj(ii))
450 : END DO
451 : END DO
452 :
453 : ELSE
454 :
455 : ! cubic in x
456 :
457 : jsave = -1
458 0 : DO jj=1,my
459 0 : j = jy(jj)
460 0 : IF (j == jsave) THEN
461 :
462 : ! j pointer has not moved since last pass (no updates or interpolation)
463 :
464 0 : ELSE IF (j == jsave+1) THEN
465 :
466 : ! update j and interpolate j+1
467 :
468 0 : DO ii=1,mx
469 0 : pj(ii) = pjp(ii)
470 : END DO
471 0 : CALL cubt1(nx,p(1,j+1),mx,pjp,ix,dxm,dx,dxp,dxpp)
472 : ELSE
473 :
474 : ! interpolate j,j+1 in pj,pjp on xx mesh
475 :
476 0 : CALL cubt1(nx,p(1,j),mx,pj,ix,dxm,dx,dxp,dxpp)
477 0 : CALL cubt1(nx,p(1,j+1),mx,pjp,ix,dxm,dx,dxp,dxpp)
478 : END IF
479 :
480 : ! save j pointer for next pass
481 :
482 0 : jsave = j
483 :
484 : ! linearly interpolate q(ii,jj) from pjp,pj in y direction
485 :
486 0 : DO ii=1,mx
487 0 : q(ii,jj) = pj(ii)+dy(jj)*(pjp(ii)-pj(ii))
488 : END DO
489 : END DO
490 : ! write(6,"('lint2: potm = ',/,(6e12.4))") p
491 : ! write(6,"('lint2: potout3 = ',/,(6e12.4))") q
492 : RETURN
493 : END IF
494 : end subroutine lint2
495 :
496 0 : subroutine cubt2(nx,ny,p,mx,my,q,intpol,jy,dym,dy,dyp, &
497 0 : dypp,pjm,pj,pjp,pjpp,ix,dxm,dx,dxp,dxpp)
498 :
499 : use shr_kind_mod,only: r8 => shr_kind_r8
500 :
501 : implicit none
502 :
503 : integer, intent(in) :: nx
504 : integer, intent(in) :: ny
505 : real(r8), intent(inout) :: p(nx,ny)
506 : integer, intent(in) :: mx
507 : integer, intent(in) :: my
508 : real(r8), intent(out) :: q(mx,my)
509 : integer, intent(in) :: intpol(2)
510 : integer, intent(in) :: jy(my)
511 : real(r8), intent(in) :: dym(my)
512 : real(r8), intent(in) :: dy(my)
513 : real(r8), intent(in) :: dyp(my)
514 : real(r8), intent(inout) :: dypp(my)
515 : real(r8), intent(out) :: pjm(mx)
516 : real(r8), intent(inout) :: pj(mx)
517 : real(r8), intent(inout) :: pjp(mx)
518 : real(r8), intent(inout) :: pjpp(mx)
519 : integer, intent(inout) :: ix(mx)
520 : real(r8), intent(inout) :: dxm(mx)
521 : real(r8), intent(inout) :: dx(mx)
522 : real(r8), intent(inout) :: dxp(mx)
523 : real(r8), intent(inout) :: dxpp(mx)
524 :
525 : integer :: jsave,j,jj,ii
526 :
527 :
528 :
529 :
530 0 : IF (intpol(1) == 1) THEN
531 :
532 : ! linear in x
533 :
534 : jsave = -3
535 0 : DO jj=1,my
536 :
537 : ! load closest four j lines containing interpolate on xx mesh
538 : ! for j-1,j,j+1,j+2 in pjm,pj,pjp,pjpp
539 :
540 0 : j = jy(jj)
541 0 : IF (j == jsave) THEN
542 :
543 : ! j pointer has not moved since last pass (no updates or interpolation)
544 :
545 0 : ELSE IF (j == jsave+1) THEN
546 :
547 : ! update j-1,j,j+1 and interpolate j+2
548 :
549 0 : DO ii=1,mx
550 0 : pjm(ii) = pj(ii)
551 0 : pj(ii) = pjp(ii)
552 0 : pjp(ii) = pjpp(ii)
553 : END DO
554 0 : CALL lint1(nx,p(1,j+2),mx,pjpp,ix,dx)
555 0 : ELSE IF (j == jsave+2) THEN
556 :
557 : ! update j-1,j and interpolate j+1,j+2
558 :
559 0 : DO ii=1,mx
560 0 : pjm(ii) = pjp(ii)
561 0 : pj(ii) = pjpp(ii)
562 : END DO
563 0 : CALL lint1(nx,p(1,j+1),mx,pjp,ix,dx)
564 0 : CALL lint1(nx,p(1,j+2),mx,pjpp,ix,dx)
565 0 : ELSE IF (j == jsave+3) THEN
566 :
567 : ! update j-1 and interpolate j,j+1,j+2
568 :
569 0 : DO ii=1,mx
570 0 : pjm(ii) = pjpp(ii)
571 : END DO
572 0 : CALL lint1(nx,p(1,j),mx,pj,ix,dx)
573 0 : CALL lint1(nx,p(1,j+1),mx,pjp,ix,dx)
574 0 : CALL lint1(nx,p(1,j+2),mx,pjpp,ix,dx)
575 : ELSE
576 :
577 : ! interpolate all four j-1,j,j+1,j+2
578 :
579 0 : CALL lint1(nx,p(1,j-1),mx,pjm,ix,dx)
580 0 : CALL lint1(nx,p(1,j),mx,pj,ix,dx)
581 0 : CALL lint1(nx,p(1,j+1),mx,pjp,ix,dx)
582 0 : CALL lint1(nx,p(1,j+2),mx,pjpp,ix,dx)
583 : END IF
584 :
585 : ! save j pointer for next pass
586 :
587 0 : jsave = j
588 :
589 : ! cubically interpolate q(ii,jj) from pjm,pj,pjp,pjpp in y direction
590 :
591 0 : DO ii=1,mx
592 0 : q(ii,jj) = dym(jj)*pjm(ii)+dy(jj)*pj(ii)+dyp(jj)*pjp(ii)+ &
593 0 : dypp(jj)*pjpp(ii)
594 : END DO
595 : END DO
596 : RETURN
597 :
598 : ELSE
599 :
600 : ! cubic in x
601 :
602 : jsave = -3
603 0 : DO jj=1,my
604 :
605 : ! load closest four j lines containing interpolate on xx mesh
606 : ! for j-1,j,j+1,j+2 in pjm,pj,pjp,pjpp
607 :
608 0 : j = jy(jj)
609 0 : IF (j == jsave) THEN
610 :
611 : ! j pointer has not moved since last pass (no updates or interpolation)
612 :
613 0 : ELSE IF (j == jsave+1) THEN
614 :
615 : ! update j-1,j,j+1 and interpolate j+2
616 :
617 0 : DO ii=1,mx
618 0 : pjm(ii) = pj(ii)
619 0 : pj(ii) = pjp(ii)
620 0 : pjp(ii) = pjpp(ii)
621 : END DO
622 0 : CALL cubt1(nx,p(1,j+2),mx,pjpp,ix,dxm,dx,dxp,dxpp)
623 0 : ELSE IF (j == jsave+2) THEN
624 :
625 : ! update j-1,j and interpolate j+1,j+2
626 :
627 0 : DO ii=1,mx
628 0 : pjm(ii) = pjp(ii)
629 0 : pj(ii) = pjpp(ii)
630 : END DO
631 0 : CALL cubt1(nx,p(1,j+1),mx,pjp,ix,dxm,dx,dxp,dxpp)
632 0 : CALL cubt1(nx,p(1,j+2),mx,pjpp,ix,dxm,dx,dxp,dxpp)
633 0 : ELSE IF (j == jsave+3) THEN
634 :
635 : ! update j-1 and interpolate j,j+1,j+2
636 :
637 0 : DO ii=1,mx
638 0 : pjm(ii) = pjpp(ii)
639 : END DO
640 0 : CALL cubt1(nx,p(1,j),mx,pj,ix,dxm,dx,dxp,dxpp)
641 0 : CALL cubt1(nx,p(1,j+1),mx,pjp,ix,dxm,dx,dxp,dxpp)
642 0 : CALL cubt1(nx,p(1,j+2),mx,pjpp,ix,dxm,dx,dxp,dxpp)
643 : ELSE
644 :
645 : ! interpolate all four j-1,j,j+1,j+2
646 :
647 0 : CALL cubt1(nx,p(1,j-1),mx,pjm,ix,dxm,dx,dxp,dxpp)
648 0 : CALL cubt1(nx,p(1,j),mx,pj,ix,dxm,dx,dxp,dxpp)
649 0 : CALL cubt1(nx,p(1,j+1),mx,pjp,ix,dxm,dx,dxp,dxpp)
650 0 : CALL cubt1(nx,p(1,j+2),mx,pjpp,ix,dxm,dx,dxp,dxpp)
651 : END IF
652 :
653 : ! save j pointer for next pass
654 :
655 0 : jsave = j
656 :
657 : ! cubically interpolate q(ii,jj) from pjm,pj,pjp,pjpp in y direction
658 :
659 0 : DO ii=1,mx
660 0 : q(ii,jj) = dym(jj)*pjm(ii)+dy(jj)*pj(ii)+dyp(jj)*pjp(ii)+ &
661 0 : dypp(jj)*pjpp(ii)
662 : END DO
663 : END DO
664 : RETURN
665 : END IF
666 : end subroutine cubt2
667 : !------------------------------------------------------------------------------
668 :
669 0 : subroutine lint1(nx,p,mx,q,ix,dx)
670 :
671 : use shr_kind_mod,only: r8 => shr_kind_r8
672 :
673 : implicit none
674 :
675 : integer, intent(in) :: nx
676 : real(r8), intent(in) :: p(nx)
677 : integer, intent(in) :: mx
678 : real(r8), intent(out) :: q(mx)
679 : integer, intent(in) :: ix(mx)
680 : real(r8), intent(in) :: dx(mx)
681 :
682 : integer :: ii,i
683 :
684 :
685 : ! linearly interpolate p on x onto q on xx
686 :
687 0 : DO ii=1,mx
688 0 : i = ix(ii)
689 0 : q(ii) = p(i)+dx(ii)*(p(i+1)-p(i))
690 : END DO
691 0 : RETURN
692 : end subroutine lint1
693 :
694 0 : subroutine cubt1(nx,p,mx,q,ix,dxm,dx,dxp,dxpp)
695 :
696 : use shr_kind_mod,only: r8 => shr_kind_r8
697 :
698 : implicit none
699 :
700 : integer, intent(in) :: nx
701 : real(r8), intent(in) :: p(nx)
702 : integer, intent(in) :: mx
703 : real(r8), intent(out) :: q(mx)
704 : integer, intent(in) :: ix(mx)
705 : real(r8), intent(in) :: dxm(mx)
706 : real(r8), intent(in) :: dx(mx)
707 : real(r8), intent(in) :: dxp(mx)
708 : real(r8), intent(inout) :: dxpp(mx)
709 :
710 : integer :: i,ii
711 :
712 :
713 : ! cubically interpolate p on x to q on xx
714 :
715 0 : DO ii=1,mx
716 0 : i = ix(ii)
717 0 : q(ii) = dxm(ii)*p(i-1)+dx(ii)*p(i)+dxp(ii)*p(i+1) &
718 0 : +dxpp(ii)*p(i+2)
719 : END DO
720 0 : RETURN
721 : end subroutine cubt1
722 :
723 0 : subroutine cubnmx(nx,x,mx,xx,ix,dxm,dx,dxp,dxpp)
724 :
725 : use shr_kind_mod,only: r8 => shr_kind_r8
726 :
727 : implicit none
728 :
729 : integer, intent(in) :: nx
730 : real(r8), intent(in) :: x(*)
731 : integer, intent(in) :: mx
732 : real(r8), intent(in) :: xx(*)
733 : integer, intent(out) :: ix(*)
734 : real(r8), intent(out) :: dxm(*)
735 : real(r8), intent(out) :: dx(*)
736 : real(r8), intent(out) :: dxp(*)
737 : real(r8), intent(out) :: dxpp(*)
738 :
739 : integer :: i,ii,isrt
740 :
741 0 : isrt = 1
742 0 : DO ii=1,mx
743 :
744 : ! set i in [2,nx-2] closest s.t.
745 : ! x(i-1),x(i),x(i+1),x(i+2) can interpolate xx(ii)
746 :
747 0 : DO i=isrt,nx-1
748 0 : IF (x(i+1) >= xx(ii)) THEN
749 0 : ix(ii) = MIN0(nx-2,MAX0(2,i))
750 0 : isrt = ix(ii)
751 0 : GO TO 3
752 : END IF
753 : END DO
754 0 : 3 CONTINUE
755 : END DO
756 :
757 : ! set cubic scale terms
758 :
759 0 : DO ii=1,mx
760 0 : i = ix(ii)
761 0 : dxm(ii) = (xx(ii)-x(i))*(xx(ii)-x(i+1))*(xx(ii)-x(i+2))/ &
762 0 : ((x(i-1)-x(i))*(x(i-1)-x(i+1))*(x(i-1)-x(i+2)))
763 : dx(ii) = (xx(ii)-x(i-1))*(xx(ii)-x(i+1))*(xx(ii)-x(i+2))/ &
764 0 : ((x(i)-x(i-1))*(x(i)-x(i+1))*(x(i)-x(i+2)))
765 : dxp(ii) = (xx(ii)-x(i-1))*(xx(ii)-x(i))*(xx(ii)-x(i+2))/ &
766 0 : ((x(i+1)-x(i-1))*(x(i+1)-x(i))*(x(i+1)-x(i+2)))
767 : dxpp(ii) = (xx(ii)-x(i-1))*(xx(ii)-x(i))*(xx(ii)-x(i+1))/ &
768 0 : ((x(i+2)-x(i-1))*(x(i+2)-x(i))*(x(i+2)-x(i+1)))
769 : END DO
770 0 : RETURN
771 : end subroutine cubnmx
772 : !------------------------------------------------------------------------------
773 :
774 0 : subroutine linmx(nx,x,mx,xx,ix,dx)
775 :
776 : ! set x grid pointers for xx grid and interpolation scale terms
777 :
778 : use shr_kind_mod,only: r8 => shr_kind_r8
779 :
780 : implicit none
781 :
782 : integer, intent(in) :: nx
783 : real(r8), intent(in) :: x(*)
784 : integer, intent(in) :: mx
785 : real(r8), intent(in) :: xx(*)
786 : integer, intent(out) :: ix(*)
787 : real(r8), intent(out) :: dx(*)
788 :
789 : integer :: isrt,ii,i
790 :
791 0 : isrt = 1
792 0 : do ii=1,mx
793 :
794 : ! find x(i) s.t. x(i) < xx(ii) <= x(i+1)
795 :
796 0 : DO i=isrt,nx-1
797 0 : IF (x(i+1) >= xx(ii)) THEN
798 0 : isrt = i
799 0 : ix(ii) = i
800 0 : GO TO 3
801 : END IF
802 : END DO
803 0 : 3 CONTINUE
804 : END DO
805 :
806 : ! set linear scale term
807 :
808 0 : DO ii=1,mx
809 0 : i = ix(ii)
810 0 : dx(ii) = (xx(ii)-x(i))/(x(i+1)-x(i))
811 : END DO
812 0 : RETURN
813 : end subroutine linmx
814 : !------------------------------------------------------------------------------
815 : end module rgrd_mod
|