File: calcpv.f

package info (click to toggle)
flextra 5.0-18
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 928 kB
  • sloc: fortran: 7,018; makefile: 61; sh: 17
file content (301 lines) | stat: -rw-r--r-- 10,419 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
      subroutine calcpv(n)
C
********************************************************************************
*                                                                              *
*  Calculation of potential vorticity on 3-d grid.                             *
*                                                                              *
*     Author: P. James                                                         *
*     3 February 2000                                                          *
*                                                                              *
********************************************************************************
*                                                                              *
* Variables:                                                                   *
* n                  temporal index for meteorological fields (1 to 3)         *
*                                                                              *
* Constants:                                                                   *
*                                                                              *
********************************************************************************

      include 'includepar'
      include 'includecom'

      integer n,ix,jy,i,j,k,kl,ii,jj,klvrp,klvrm,klpt,kup,kdn,kch
      integer jyvp,jyvm,ixvp,ixvm,jumpx,jumpy,jux,juy,ivrm,ivrp,ivr
      integer nlck
      real vx(2),uy(2),phi,tanphi,cosphi,dvdx,dudy,f
      real theta,thetap,thetam,dthetadp,dt1,dt2,dt,ppmk
      real height(nuvzmax),pvavr,ppml(nuvzmax)
      real thup,thdn

C Set number of levels to check for adjacent theta
      nlck=nuvz/3
      do 5 k=1,nuvz
        height(k)=akz(k)/p0+bkz(k)
5     continue
C *** Precalculate all theta levels for efficiency
        do 9 jy=0,ny-1
        do 14 kl=1,nuvz
        do 13 ix=0,nx-1
          ppmk=akz(kl)+bkz(kl)*ps(ix,jy,1,n)
          th(ix,jy,kl,n)=tt(ix,jy,kl,n)*(100000./ppmk)**kappa
13      continue
14      continue
9       continue
C
C Loop over entire grid
***********************
      do 10 jy=0,ny-1
        if (sglobal.and.jy.eq.0) goto 10
        if (nglobal.and.jy.eq.ny-1) goto 10
        phi = (ylat0 + jy * dy) * pi / 180.
        f = 0.00014585 * sin(phi)
        tanphi = tan(phi)
        cosphi = cos(phi)
C Provide a virtual jy+1 and jy-1 in case we are on domain edge (Lat)
          jyvp=jy+1
          jyvm=jy-1
          if (jy.eq.0) jyvm=0
          if (jy.eq.ny-1) jyvp=ny-1
C Define absolute gap length
          jumpy=2
          if (jy.eq.0.or.jy.eq.ny-1) jumpy=1
          if (sglobal.and.jy.eq.1) then
             jyvm=1
             jumpy=1
          end if
          if (nglobal.and.jy.eq.ny-2) then
             jyvp=ny-2
             jumpy=1
          end if
          juy=jumpy
C
        do 11 ix=0,nx-1
C Provide a virtual ix+1 and ix-1 in case we are on domain edge (Long)
          ixvp=ix+1
          ixvm=ix-1
          jumpx=2
          if (xglobal) then
             ivrp=ixvp
             ivrm=ixvm
             if (ixvm.lt.0) ivrm=ixvm+nx-1
             if (ixvp.ge.nx) ivrp=ixvp-nx+1
          else
            if (ix.eq.0) ixvm=0
            if (ix.eq.nx-1) ixvp=nx-1
            ivrp=ixvp
            ivrm=ixvm
C Define absolute gap length
            if (ix.eq.0.or.ix.eq.nx-1) jumpx=1
          end if
          jux=jumpx
C Precalculate pressure values for efficiency
          do 8 kl=1,nuvz
            ppml(kl)=akz(kl)+bkz(kl)*ps(ix,jy,1,n)
8         continue
C
C Loop over the vertical
************************

          do 12 kl=1,nuvz
            theta=th(ix,jy,kl,n)
            klvrp=kl+1
            klvrm=kl-1
            klpt=kl
C If top or bottom level, dthetadp is evaluated between the current
C level and the level inside, otherwise between level+1 and level-1
C
            if (klvrp.gt.nuvz) klvrp=nuvz
            if (klvrm.lt.1) klvrm=1
            thetap=th(ix,jy,klvrp,n)
            thetam=th(ix,jy,klvrm,n)
            dthetadp=(thetap-thetam)/(ppml(klvrp)-ppml(klvrm))
            
C Compute vertical position at pot. temperature surface on subgrid
C and the wind at that position
******************************************************************
C a) in x direction
            ii=0
            do 20 i=ixvm,ixvp,jumpx
              ivr=i
              if (xglobal) then
                 if (i.lt.0) ivr=ivr+nx-1
                 if (i.ge.nx) ivr=ivr-nx+1
              end if
              ii=ii+1
C Search adjacent levels for current theta value
C Spiral out from current level for efficiency
              kup=klpt-1
              kdn=klpt
              kch=0
40            continue
C Upward branch
              kup=kup+1
              if (kch.ge.nlck) goto 21     ! No more levels to check, 
C                                            ! and no values found
              if (kup.ge.nuvz) goto 41
              kch=kch+1
              k=kup
              thdn=th(ivr,jy,k,n)
              thup=th(ivr,jy,k+1,n)
          if (((thdn.ge.theta).and.(thup.le.theta)).or.
     +    ((thdn.le.theta).and.(thup.ge.theta))) then
                  dt1=abs(theta-thdn)
                  dt2=abs(theta-thup)
                  dt=dt1+dt2
                  if (dt.lt.eps) then   ! Avoid division by zero error
                    dt1=0.5             ! G.W., 10.4.1996
                    dt2=0.5
                    dt=1.0
                  endif
              vx(ii)=(vv(ivr,jy,k,n)*dt2+vv(ivr,jy,k+1,n)*dt1)/dt
                  goto 20
                endif
41            continue
C Downward branch
              kdn=kdn-1
              if (kdn.lt.1) goto 40
              kch=kch+1
              k=kdn
              thdn=th(ivr,jy,k,n)
              thup=th(ivr,jy,k+1,n)
          if (((thdn.ge.theta).and.(thup.le.theta)).or.
     +    ((thdn.le.theta).and.(thup.ge.theta))) then
                  dt1=abs(theta-thdn)
                  dt2=abs(theta-thup)
                  dt=dt1+dt2
                  if (dt.lt.eps) then   ! Avoid division by zero error
                    dt1=0.5             ! G.W., 10.4.1996
                    dt2=0.5
                    dt=1.0
                  endif
              vx(ii)=(vv(ivr,jy,k,n)*dt2+vv(ivr,jy,k+1,n)*dt1)/dt
                  goto 20
                endif
                goto 40
C This section used when no values were found
21          continue
C Must use vv at current level and long. jux becomes smaller by 1
            vx(ii)=vv(ix,jy,kl,n)
            jux=jux-1
C Otherwise OK
20          continue
          if (jux.gt.0) then
          dvdx=(vx(2)-vx(1))/float(jux)/(dx*pi/180.)
          else
          dvdx=vv(ivrp,jy,kl,n)-vv(ivrm,jy,kl,n)
          dvdx=dvdx/float(jumpx)/(dx*pi/180.)
C Only happens if no equivalent theta value
C can be found on either side, hence must use values
C from either side, same pressure level.
          end if

C b) in y direction

            jj=0
            do 50 j=jyvm,jyvp,jumpy
              jj=jj+1
C Search adjacent levels for current theta value
C Spiral out from current level for efficiency
              kup=klpt-1
              kdn=klpt
              kch=0
70            continue
C Upward branch
              kup=kup+1
              if (kch.ge.nlck) goto 51     ! No more levels to check, 
C                                          ! and no values found
              if (kup.ge.nuvz) goto 71
              kch=kch+1
              k=kup
              thdn=th(ix,j,k,n)
              thup=th(ix,j,k+1,n)
          if (((thdn.ge.theta).and.(thup.le.theta)).or.
     +    ((thdn.le.theta).and.(thup.ge.theta))) then
                  dt1=abs(theta-thdn)
                  dt2=abs(theta-thup)
                  dt=dt1+dt2
                  if (dt.lt.eps) then   ! Avoid division by zero error
                    dt1=0.5             ! G.W., 10.4.1996
                    dt2=0.5
                    dt=1.0
                  endif
                  uy(jj)=(uu(ix,j,k,n)*dt2+uu(ix,j,k+1,n)*dt1)/dt
                  goto 50
                endif
71            continue
C Downward branch
              kdn=kdn-1
              if (kdn.lt.1) goto 70
              kch=kch+1
              k=kdn
              thdn=th(ix,j,k,n)
              thup=th(ix,j,k+1,n)
          if (((thdn.ge.theta).and.(thup.le.theta)).or.
     +    ((thdn.le.theta).and.(thup.ge.theta))) then
                  dt1=abs(theta-thdn)
                  dt2=abs(theta-thup)
                  dt=dt1+dt2
                  if (dt.lt.eps) then   ! Avoid division by zero error
                    dt1=0.5             ! G.W., 10.4.1996
                    dt2=0.5
                    dt=1.0
                  endif
                  uy(jj)=(uu(ix,j,k,n)*dt2+uu(ix,j,k+1,n)*dt1)/dt
                  goto 50
                endif
                goto 70
C This section used when no values were found
51          continue
C Must use uu at current level and lat. juy becomes smaller by 1
            uy(jj)=uu(ix,jy,kl,n)
            juy=juy-1
C Otherwise OK
50          continue
          if (juy.gt.0) then
          dudy=(uy(2)-uy(1))/float(juy)/(dy*pi/180.)
          else
          dudy=uu(ix,jyvp,kl,n)-uu(ix,jyvm,kl,n)
          dudy=dudy/float(jumpy)/(dy*pi/180.)
          end if
C
          pv(ix,jy,kl,n)=dthetadp*(f+(dvdx/cosphi-dudy
     +    +uu(ix,jy,kl,n)*tanphi)/r_earth)*(-1.e6)*9.81
C
C Resest jux and juy
          jux=jumpx
          juy=jumpy
12        continue
11        continue                                                            
10        continue
C
C Fill in missing PV values on poles, if present
C Use mean PV of surrounding latitude ring
C
          if (sglobal) then
             do 80 kl=1,nuvz
                pvavr=0.
                do 81 ix=0,nx-1
                   pvavr=pvavr+pv(ix,1,kl,n)
81              continue
                pvavr=pvavr/float(nx)
                jy=0
                do 82 ix=0,nx-1
                   pv(ix,jy,kl,n)=pvavr
82              continue
80           continue
          end if
          if (nglobal) then
             do 90 kl=1,nuvz
                pvavr=0.
                do 91 ix=0,nx-1
                   pvavr=pvavr+pv(ix,ny-2,kl,n)
91              continue
                pvavr=pvavr/float(nx)
                jy=ny-1
                do 92 ix=0,nx-1
                   pv(ix,jy,kl,n)=pvavr
92              continue
90           continue
          end if
      return
      end