Subversion Repositories lagranto.ocean

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 michaesp 1
c      *************************************************************
2
c      * This package provides a general interpolaton routine      *
3
c      *************************************************************	
4
 
5
c     The main interface routines are:
6
c         get_index3,4 : get the grid indices for interpolation
7
c         int_index3,4 : interpolate to the grid position
8
 
9
c     -------------------------------------------------------------
10
c     Get index in grid space for interpolation
11
c     -------------------------------------------------------------
12
 
13
      subroutine get_index4 (rid,rjd,rkd,xpo,ypo,ppo,rtp,
14
     >                       vert0,vert1,surf0,surf1,mode,
15
     >                       nx,ny,nz,lonw,lats,dlon,dlat,misdat)
16
 
17
c     Purpose:
18
c        This subroutine determines the indices (rid,rjd,rkd) in grid 
19
c        space for a point in physical space (xpo,ypo,ppo). The 
20
c        horizontal grid is specified by the south-west point (lats,lonw)
21
c        and the grid spacing (dlat,dlon). The vertical grid is given
22
c        by <vert(n1,n2,n3)>. The lower boundary (typicall surface 
23
c        pressure) is given by <surf(n1,n2)>.
24
c     Arguments:
25
c        rid,rjd,rkd  real  output   grid location to be interpolated to
26
c        xpo,ypo,ppo  real  input    physical coordinates
27
c        rtp          real  input    relative time position (0=beginning, 1=end)
28
c        n1,n2,n3     int   input    grid dimensions in x-, y- and p-direction
29
c        lats,lonw    real  input    south and west boundary of grid space
30
c        vert         real  input    vertical coordinate grid
31
c        surf         real  input    lower boundary (surface pressure)
32
c        mode         int   input    direction of vertical axis (p=1,th=-1)
33
c                                        1: linear, 1 -> nz (th)
34
c                                        2: linear, nz -> 1 (pv)
35
c                                        3: binary (z)
36
c                                        4: binary (p)
37
 
38
 
39
      implicit none
40
 
41
c     Declartion of function parameters
42
      integer   nx,ny,nz
43
      real      xpo,ypo,ppo,rtp
44
      real      vert0(nx*ny*nz),vert1(nx*ny*nz)
45
      real      surf0(nx*ny)   ,surf1(nx*ny*nz)
46
      real      rid,rjd,rkd
47
      real      dlat,dlon,lats,lonw
48
      real      misdat
49
      integer   mode
50
 
51
c     Set numerical parameters
52
      real      eps
53
      parameter (eps=1.e-10)
54
 
55
c     Auxiliary variables
56
      real      rid0,rjd0,rkd0,rid1,rjd1,rkd1
57
 
58
c     Externals 
59
      real      int_time
60
      external  int_time
61
 
62
c     Get the inidices
63
      if (abs(rtp).lt.eps) then
64
         call  get_index3 (rid,rjd,rkd,xpo,ypo,ppo,mode,
65
     >                     vert0,surf0,nx,ny,nz,lonw,lats,dlon,dlat)
66
      elseif (abs(rtp-1.).lt.eps) then
67
         call  get_index3 (rid,rjd,rkd,xpo,ypo,ppo,mode,
68
     >                     vert1,surf1,nx,ny,nz,lonw,lats,dlon,dlat)
69
      else
70
         call  get_index3 (rid0,rjd0,rkd0,xpo,ypo,ppo,mode,
71
     >                     vert0,surf0,nx,ny,nz,lonw,lats,dlon,dlat)
72
         call  get_index3 (rid1,rjd1,rkd1,xpo,ypo,ppo,mode,
73
     >                     vert1,surf1,nx,ny,nz,lonw,lats,dlon,dlat)
74
         rid = int_time (rid0,rid1,rtp,misdat)
75
         rjd = int_time (rjd0,rjd1,rtp,misdat)
76
         rkd = int_time (rkd0,rkd1,rtp,misdat)
77
 
78
      endif
79
 
80
      end
81
 
82
c     -------------------------------------------------------------
83
c     Interpolate to an arbitrary position in grid space and time
84
c     -------------------------------------------------------------
85
 
86
      real function int_index4 (ar0,ar1,n1,n2,n3,rid,rjd,rkd,rtp,misdat)
87
 
88
c     Purpose:
89
c        This subroutine interpolates a 3d-array to an arbitrary
90
c        location within the grid including a linear time-interpolation. 
91
c     Arguments:
92
c        rid,rjd,rkd  real  output   grid location to be interpolated to
93
c        xpo,ypo,ppo  real  input    physical coordinates
94
c        n1,n2,n3     int   input    grid dimensions in x-, y- and p-direction
95
c        lats,lonw    real  input    south and west boundary of grid space
96
c        vert         real  input    vertical coordinate grid
97
c        surf         real  input    lower boundary (surface pressure)
98
 
99
      implicit none
100
 
101
c     Declartion of function parameters
102
      integer   n1,n2,n3
103
      real      ar0(n1*n2*n3),ar1(n1*n2*n3)
104
      real      rid,rjd,rkd
105
      real      rtp
106
      real      misdat
107
 
108
c     Set numerical parameters
109
      real      eps
110
      parameter (eps=1.e-10)
111
 
112
c     Externals  
113
      real      int_index3,int_time
114
      external  int_index3,int_time
115
 
116
c     Auxiliary variables
117
      real      val0,val1,val
118
 
119
c     Do the 3d-interpolation
120
      if (abs(rtp).lt.eps) then
121
         val = int_index3 (ar0,n1,n2,n3,rid,rjd,rkd,misdat)
122
      elseif (abs(rtp-1.).lt.eps) then
123
         val = int_index3 (ar1,n1,n2,n3,rid,rjd,rkd,misdat)
124
      else
125
         val0 = int_index3 (ar0,n1,n2,n3,rid,rjd,rkd,misdat)
126
         val1 = int_index3 (ar1,n1,n2,n3,rid,rjd,rkd,misdat)
127
         val  = int_time (val0,val1,rtp,misdat)
128
      endif
129
 
130
c     Return value
131
      int_index4 = val
132
 
133
      return
134
      end
135
 
136
 
137
c     -------------------------------------------------------------
138
c     Interpolate to an arbitrary position in grid space
139
c     -------------------------------------------------------------
140
 
141
      real function int_index3 (ar,n1,n2,n3,rid,rjd,rkd,misdat)
142
 
143
c     Purpose:
144
c        This subroutine interpolates a 3d-array to an arbitrary
145
c        location within the grid. The interpolation includes the 
146
c        testing of the missing data flag 'misdat'. If one dimension
147
c        is 1, a 2d-interpolation is performed; if two dimensions
148
c        are 1, it is a 1d-interpolation; if all three dimensions are
149
c        1, no interpolation is performed and the input value is
150
c        returned.
151
c     Arguments:
152
c        ar        real  input   input data array
153
c        n1,n2,n3  int   input   dimensions of ar
154
c        ri,rj,rk  real  input   grid location to be interpolated to
155
c        misdat    real  input   missing data flag (on if misdat<>0)
156
 
157
      implicit none
158
 
159
c     Declartion of function parameters 
160
      integer   n1,n2,n3
161
      real      ar(n1*n2*n3)
162
      real      rid,rjd,rkd
163
      real      misdat
164
 
165
c     Set numerical parameters
166
      real      eps
167
      parameter (eps=1.e-10)
168
 
169
c     Local variables
170
      integer   i,j,k,ip1,jp1,kp1
171
      real      frac0i,frac0j,frac0k,frac1i,frac1j,frac1k
172
      real      ri,rj,rk
173
      real      val000,val001,val010,val011,val100,val101,val110,val111
174
      real      frc000,frc001,frc010,frc011,frc100,frc101,frc110,frc111
175
      real      frc
176
      real      mdv
177
      real      val
178
 
179
c     Elementary test for dimensions
180
      if ( (n1.lt.1).or.(n2.lt.1).or.(n3.lt.1) ) then
181
         print*,'Invalid grid dimensions ',n1,n2,n3
182
         stop
183
      endif
184
 
185
c     Activate or inactive the missing data check (quick and dirty)
186
      if (misdat.ne.0.) then
187
         mdv = misdat
188
      else
189
         mdv = 257.22725394015
190
      endif
191
 
192
c     Bring the indices into the grid space
193
      ri = amax1(1.,amin1(float(n1),rid))
194
      rj = amax1(1.,amin1(float(n2),rjd))
195
      rk = amax1(1.,amin1(float(n3),rkd))
196
 
197
c     Get the index of the west-south-bottom corner of the box
198
      i   = min0(int(ri),n1-1)
199
      ip1 = i+1
200
      j   = min0(int(rj),n2-1)
201
      jp1 = j+1
202
      k   = min0(int(rk),n3-1)
203
      kp1 = k+1
204
 
205
c     Special handling for 2d arrays
206
      if (n3.eq.1) then
207
         k=1
208
         kp1=1
209
      endif
210
 
211
c     Get location relative to grid box
212
      if ( i.ne.ip1 ) then
213
         frac0i = ri-float(i)
214
         frac1i = 1.-frac0i
215
      else
216
         frac0i = 0.
217
         frac1i = 1.
218
      endif
219
      if ( j.ne.jp1 ) then
220
         frac0j = rj-float(j)
221
         frac1j = 1.-frac0j
222
      else
223
         frac0j = 0.
224
         frac1j = 1.
225
      endif
226
      if ( k.ne.kp1 ) then
227
         frac0k = rk-float(k)
228
         frac1k = 1.-frac0k
229
      else
230
         frac0k = 0.
231
         frac1k = 1.
232
      endif
233
 
234
c     On a grid point - take the grid point value 
235
      if ( ( abs(frac0i).lt.eps ).and.
236
     >     ( abs(frac0j).lt.eps ).and.
237
     >     ( abs(frac0k).lt.eps ) ) then
238
 
239
         val = ar( i + n1*(j -1) + n1*n2*(k -1) )
240
         goto 100
241
 
242
      endif
243
 
244
c     Init the fractions
245
      frc000 = frac1i * frac1j * frac1k
246
      frc001 = frac0i * frac1j * frac1k
247
      frc010 = frac1i * frac0j * frac1k
248
      frc011 = frac0i * frac0j * frac1k
249
      frc100 = frac1i * frac1j * frac0k
250
      frc101 = frac0i * frac1j * frac0k
251
      frc110 = frac1i * frac0j * frac0k
252
      frc111 = frac0i * frac0j * frac0k
253
 
254
c     Init the values
255
      val000 = ar( i   + n1*(j  -1) + n1*n2*(k  -1) )
256
      val001 = ar( ip1 + n1*(j  -1) + n1*n2*(k  -1) )
257
      val010 = ar( i   + n1*(jp1-1) + n1*n2*(k  -1) )
258
      val011 = ar( ip1 + n1*(jp1-1) + n1*n2*(k  -1) )
259
      val100 = ar( i   + n1*(j  -1) + n1*n2*(kp1-1) )
260
      val101 = ar( ip1 + n1*(j  -1) + n1*n2*(kp1-1) )
261
      val110 = ar( i   + n1*(jp1-1) + n1*n2*(kp1-1) )
262
      val111 = ar( ip1 + n1*(jp1-1) + n1*n2*(kp1-1) )
263
 
264
c     Handle missing data
265
      if ( abs(val000-mdv).lt.eps ) frc000 = 0.
266
      if ( abs(val001-mdv).lt.eps ) frc001 = 0.
267
      if ( abs(val010-mdv).lt.eps ) frc010 = 0.
268
      if ( abs(val011-mdv).lt.eps ) frc011 = 0.
269
      if ( abs(val100-mdv).lt.eps ) frc100 = 0.
270
      if ( abs(val101-mdv).lt.eps ) frc101 = 0.
271
      if ( abs(val110-mdv).lt.eps ) frc110 = 0.
272
      if ( abs(val111-mdv).lt.eps ) frc111 = 0.
273
 
274
c     Build the final value
275
      frc = frc000 + frc001 + frc010 + frc011 + 
276
     >      frc100 + frc101 + frc110 + frc111   
277
      if ( frc.gt.0. ) then
278
         val = 1./frc * ( frc000 * val000 + frc001 * val001 +
279
     >                    frc010 * val010 + frc011 * val011 +
280
     >                    frc100 * val100 + frc101 * val101 +
281
     >                    frc110 * val110 + frc111 * val111 )
282
      else
283
         val = misdat
284
      endif
285
 
286
c     Return the value 
287
 100  continue
288
 
289
      int_index3 = val
290
 
291
      end
292
 
293
 
294
c     -------------------------------------------------------------
295
c     Time interpolation
296
c     -------------------------------------------------------------
297
 
298
      real function int_time (val0,val1,reltpos,misdat)
299
 
300
c     Purpose:
301
c        This subroutine interpolates linearly in time between two
302
c        values.
303
c     Arguments:
304
c        val0      real  input   value at time 0
305
c        val1      real  input   value at time 1
306
c        reltpos   real  input   relative time (between 0 and 1)
307
c        misdat    real  input   missing data flag (on if misdat<>0)
308
 
309
      implicit none
310
 
311
c     Declaration of parameters
312
      real      val0
313
      real      val1
314
      real      reltpos
315
      real      misdat
316
 
317
c     Numerical epsilon
318
      real      eps
319
      parameter (eps=1.e-10)
320
 
321
c     Local variables
322
      real      val
323
      real      mdv
324
 
325
c     Activate or inactive the missing data check (quick and dirty)
326
      if (misdat.ne.0.) then
327
         mdv = misdat
328
      else
329
         mdv = 257.22725394015
330
      endif
331
 
332
c     Do the linear interpolation
333
      if ( abs(reltpos).lt.eps ) then
334
         val = val0
335
      elseif ( abs(reltpos-1.).lt.eps ) then
336
         val = val1
337
      elseif ( (abs(val0-mdv).gt.eps).and.
338
     >         (abs(val1-mdv).gt.eps) ) then
339
         val = (1.-reltpos)*val0+reltpos*val1
340
      else
341
         val = mdv
342
      endif
343
 
344
c     Return value
345
      int_time = val
346
 
347
      end
348
 
349
 
350
c     -------------------------------------------------------------
351
c     Get the position of a physical point in grid space
352
c     -------------------------------------------------------------
353
 
354
      subroutine get_index3 (rid,rjd,rkd,xpo,ypo,ppo,mode,
355
     >                       vert,surf,nx,ny,nz,lonw,lats,dlon,dlat)
356
 
357
c     Purpose:
358
c        This subroutine determines the indices (rid,rjd,rkd) in grid 
359
c        space for a point in physical space (xpo,ypo,ppo). The 
360
c        horizontal grid is specified by the south-west point (lats,lonw)
361
c        and the grid spacing (dlat,dlon). The vertical grid is given
362
c        by <vert(n1,n2,n3)>. The lower boundary (typicall surface 
363
c        pressure) is given by <surf(n1,n2)>.
364
c     Arguments:
365
c        rid,rjd,rkd  real  output   grid location to be interpolated to
366
c        xpo,ypo,ppo  real  input    physical coordinates
367
c        n1,n2,n3     int   input    grid dimensions in x-, y- and p-direction
368
c        lats,lonw    real  input    south and west boundary of grid space
369
c        vert         real  input    vertical coordinate grid
370
c        surf         real  input    lower boundary (surface pressure)
371
c        mode         int   input    direction of vertical axis 
372
c                                        1: linear, 1 -> nz (th)
373
c                                        2: linear, nz -> 1 (pv)
374
c                                        3: binary (z)
375
c                                        4: binary (p)
376
 
377
 
378
      implicit none
379
 
380
c     Declartion of function parameters
381
      integer   nx,ny,nz
382
      real      vert(nx*ny*nz)
383
      real      surf(nx*ny)
384
      real      rid,rjd,rkd
385
      real      xpo,ypo,ppo
386
      real      dlat,dlon,lats,lonw
387
      integer   mode
388
 
389
c     Numerical epsilon
390
      real      eps
391
      parameter (eps=1.e-10)
392
 
393
c     Local variables
394
      integer   i,j,k
395
      real      ppo0,ppo1,ppom,psur
396
      integer   i0,im,i1
397
 
398
c     Externals 
399
      real      int_index3
400
      external  int_index3
401
 
402
c     Get the horizontal grid indices
403
      rid=(xpo-lonw)/dlon+1.
404
      rjd=(ypo-lats)/dlat+1.
405
 
406
c     Two-dimensional interpolation on horizontal plane: return
407
      if ( nz.eq.1 ) then
408
         rkd = 1.
409
         goto 100
410
      endif
411
 
412
c     Lowest-level interpolation: return
413
      if ( abs(ppo).lt.eps ) then
414
         rkd = 1.
415
         goto 100
416
      endif
417
 
418
c     Get the pressure at the lowest level and at the surface
419
      ppo0 = int_index3(vert,nx,ny,nz,rid,rjd,real(1),0.)
420
      psur = int_index3(surf,nx,ny, 1,rid,rjd,real(1),0.)
421
 
422
c     Decide whether the pressure is ascending or descending
423
      if ( mode.eq.4 ) then
424
       ppo1 = int_index3(vert,nx,ny,nz,rid,rjd,real(nz),0.)
425
       if ( ppo1.gt.ppo0 ) then
426
          ppo0 = ppo1
427
       endif
428
       endif
429
 
430
c     (p-mode) The point is between the surface and the lowest level: return
431
      if ( mode.eq.4 ) then
432
        if ( (ppo.ge.ppo0).and.(ppo.le.psur).or.
433
     >       (ppo.le.ppo0).and.(ppo.ge.psur) )
434
     >  then
435
           psur = int_index3(surf,nx,ny, 1,rid,rjd,real(1),0.)
436
           rkd  = (psur-ppo)/(psur-ppo0)
437
           goto 100
438
        endif
439
      endif
440
 
441
c     (z-mode) The point is between the surface and the lowest level: return
442
      if ( mode.eq.3 ) then
443
        if ( (ppo.ge.ppo0).and.(ppo.le.psur).or.
444
     >       (ppo.le.ppo0).and.(ppo.ge.psur) )
445
     >  then
446
           psur = int_index3(surf,nx,ny, 1,rid,rjd,real(1),0.)
447
           rkd  = 1.
448
           goto 100
449
        endif
450
       endif
451
 
452
c     Full-level search (TH): linear ascending scanning through all levels
453
      if ( mode.eq.1 ) then
454
 
455
         ppo0 = int_index3(vert,nx,ny,nz,rid,rjd,real(1),0.)
456
         rkd=0
457
         do i=1,nz-1
458
            ppo1 = int_index3(vert,nx,ny,nz,rid,rjd,real(i+1),0.)
459
            if ( (ppo0.lt.ppo).and.(ppo1.ge.ppo) ) then
460
               rkd=real(i)+(ppo0-ppo)/(ppo0-ppo1)
461
               goto 100
462
            endif
463
            ppo0 = ppo1
464
         enddo
465
 
466
c     Full-level search (PV): linear descending scanning through all levels
467
      elseif ( mode.eq.2 ) then
468
 
469
         ppo1 = int_index3(vert,nx,ny,nz,rid,rjd,real(nz),0.)
470
         rkd=0
471
         do i=nz-1,1,-1
472
            ppo0 = int_index3(vert,nx,ny,nz,rid,rjd,real(i),0.)
473
            if ( (ppo1.gt.ppo).and.(ppo0.le.ppo) ) then
474
               rkd=real(i)+(ppo0-ppo)/(ppo0-ppo1)
475
               goto 100
476
            endif
477
            ppo1 = ppo0
478
         enddo
479
 
480
c      Full-level search (Z):  binary search
481
       elseif ( mode.eq.3 ) then
482
 
483
         rkd  = 0
484
         i0   = 1
485
         i1   = nz
486
         ppo0 = int_index3(vert,nx,ny,nz,rid,rjd,real( 1),0.)
487
         ppo1 = int_index3(vert,nx,ny,nz,rid,rjd,real(nz),0.)
488
 
489
         do while ( i1.gt.(i0+1) )
490
            im   = (i0+i1)/2
491
            ppom = int_index3(vert,nx,ny,nz,rid,rjd,real(im),0.)
492
            if (ppom.gt.ppo) then
493
               i1   = im
494
               ppo1 = ppom
495
            else
496
               i0   = im
497
               ppo0 = ppom
498
            endif
499
 
500
         enddo
501
 
502
         rkd=real(i0)+(ppo0-ppo)/(ppo0-ppo1)
503
 
504
c     Full-level search (P):  binary search 
505
      elseif ( mode.eq.4 ) then
506
 
507
         rkd  = 0
508
         i0   = 1
509
         i1   = nz
510
         ppo0 = int_index3(vert,nx,ny,nz,rid,rjd,real( 1),0.)
511
         ppo1 = int_index3(vert,nx,ny,nz,rid,rjd,real(nz),0.)
512
 
513
         do while ( i1.gt.(i0+1) )
514
            im   = (i0+i1)/2
515
            ppom = int_index3(vert,nx,ny,nz,rid,rjd,real(im),0.)
516
            if (ppom.lt.ppo) then
517
               i1   = im
518
               ppo1 = ppom
519
            else
520
               i0   = im
521
               ppo0 = ppom
522
            endif
523
         enddo
524
 
525
         rkd=real(i0)+(ppo0-ppo)/(ppo0-ppo1)
526
 
527
      endif
528
 
529
c     Exit point for subroutine
530
 100  continue
531
 
532
      end
533