/[MITgcm]/MITgcm/pkg/opps/opps_calc.F
ViewVC logotype

Contents of /MITgcm/pkg/opps/opps_calc.F

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.12 - (show annotations) (download)
Sun Jan 19 14:43:51 2014 UTC (10 years, 5 months ago) by jmc
Branch: MAIN
CVS Tags: checkpoint64y, checkpoint64x, checkpoint64z, checkpoint64u, checkpoint64t, checkpoint64w, checkpoint64v, checkpoint65, checkpoint65r, checkpoint65s, checkpoint65p, checkpoint65q, checkpoint65t, checkpoint65j, checkpoint65k, checkpoint65h, checkpoint65i, checkpoint65n, checkpoint65o, checkpoint65l, checkpoint65m, checkpoint65b, checkpoint65c, checkpoint65a, checkpoint65f, checkpoint65g, checkpoint65d, checkpoint65e
Changes since 1.11: +6 -7 lines
- avoid unused labels

1 C $Header: /u/gcmpack/MITgcm/pkg/opps/opps_calc.F,v 1.11 2012/06/27 22:34:07 jmc Exp $
2 C $Name: $
3
4 #include "OPPS_OPTIONS.h"
5 #undef OPPS_ORGCODE
6
7 C-- File opps_calc.F:
8 C-- Contents
9 C-- o OPPS_CALC
10 C-- o STATE1
11 C-- o NLOPPS
12
13 C---+----1----+----2----+----3----+----4----+----5----+----6----+----7-|--+----|
14 CBOP
15 C !ROUTINE: OPPS_CALC
16
17 C !INTERFACE: ======================================================
18 SUBROUTINE OPPS_CALC(
19 U tracerEnv,
20 I wVel,
21 I kMax, nTracer, nTracerInuse,
22 I I, J, bi, bj, myTime, myIter, myThid )
23
24 C !DESCRIPTION: \bv
25 C *=====================================================================*
26 C | SUBROUTINE OPPS_CALC |
27 C | o Compute all OPPS fields defined in OPPS.h |
28 C *=====================================================================*
29 C | This subroutine is based on the routine 3dconvection.F |
30 C | by E. Skyllingstad (?) |
31 C | plenty of modifications to make it work: |
32 C | - removed many unused parameters and variables |
33 C | - turned everything (back) into 1D code |
34 C | - pass variables, that are originally in common blocks: |
35 C | maxDepth |
36 C | - pass vertical velocity, set in OPPS_INTERFACE |
37 C | - do not use convadj for now (whatever that is) |
38 C | - changed two .LT. 0 to .LE. 0 statements (because of possible |
39 C | division) |
40 C | - replaced statement function state1 by call to a real function |
41 C | - removed range check, actually moved it up to OPPS_INTERFACE |
42 C | - avoid division by zero: if (Wd.EQ.0) dt = ...1/Wd |
43 C | - cleaned-up debugging |
44 C | - replaced local dz and GridThickness by global drF |
45 C | - replaced 1/dz by 1*recip_drF |
46 C | - replaced 9.81 with gravity (=9.81) |
47 C | - added a lot of comments that relate code to equation in paper |
48 C | (Paluszkiewicz+Romea, 1997, Dynamics of Atmospheres and Oceans, |
49 C | 26, pp. 95-130) |
50 C | - included passive tracer support. This is the main change and may |
51 C | not improve the readability of the code because of the joint |
52 C | treatment of active (theta, salt) and passive tracers. The array |
53 C | tracerEnv(Nr,2+PTRACERS_num) contains |
54 C | theta = tracerEnv(:,1), |
55 C | salt = tracerEnv(:,2), and |
56 C | ptracers = tracerEnv(:,3:PTRACERS_num+2). |
57 C | All related array names have been changed accordingly, so that |
58 C | instead of Sd(Nr) and Td(Nr) (plume salinity and temperature), we |
59 C | have Pd(Nr,nTracer) (tracer in plume), with Sd(:) = Pd(:,2), |
60 C | Td(:) = Pd(:,1), etc. |
61 C | o TODO: |
62 C | clean up the logic of the vertical loops and get rid off the |
63 C | GOTO statements |
64 C *=====================================================================*
65 C \ev
66
67 IMPLICIT NONE
68
69 C !USES: ============================================================
70 #include "SIZE.h"
71 #include "EEPARAMS.h"
72 #include "PARAMS.h"
73 #include "OPPS.h"
74 #include "GRID.h"
75
76 C !INPUT PARAMETERS: ===================================================
77 C Routine arguments
78 C bi, bj :: array indices on which to apply calculations
79 C myTime :: Current time in simulation
80
81 INTEGER I, J, bi, bj, KMax, nTracer, nTracerInUse
82 INTEGER myThid, myIter
83 _RL myTime
84 _RL tracerEnv(Nr,nTracer),wVel(Nr)
85
86 #ifdef ALLOW_OPPS
87 C !FUNCTIONS: ==========================================================
88 c EXTERNAL DIFFERENT_MULTIPLE
89 c LOGICAL DIFFERENT_MULTIPLE
90 _RL STATE1
91
92 C !LOCAL VARIABLES: ====================================================
93 C Local constants
94 C msgBuf :: Informational/error message buffer
95 CHARACTER*(MAX_LEN_MBUF) msgBuf
96 INTEGER K, K2, K2m1, K2p1, ktr
97 INTEGER ntime,nn,kmx,ic
98 INTEGER maxDepth
99
100 _RL wsqr,oldflux,newflux,entrainrate
101 _RL pmix
102 _RL D1, D2
103 _RL dz1,dz2
104 _RL radius,StartingFlux
105 _RL dtts,dt
106 C Arrays
107 _RL Paa(Nr,nTracer)
108 _RL wda(Nr), mda(Nr), pda(Nr,nTracer)
109 C
110 C Pd, Wd :: tracers, vertical velocity in plume
111 C Md :: plume mass flux (?)
112 C Ad :: fractional area covered by plume
113 C Dd :: density in plume
114 C De :: density of environment
115 C PlumeEntrainment ::
116 _RL Ad(Nr),Wd(Nr),Dd(Nr),Md(Nr)
117 _RL De(Nr)
118 _RL PlumeEntrainment(Nr)
119 _RL Pd(Nr,nTracer)
120 CEOP
121
122 C-- Check to see if should convect now
123 C IF ( DIFFERENT_MULTIPLE(cAdjFreq,myTime,deltaTClock) ) THEN
124 IF ( .true. ) THEN
125 C local initialization
126
127 C Copy some arrays
128 dtts = dTtracerLev(1)
129
130 C start k-loop
131
132 DO k=1,KMax-1
133
134 C initialize the plume T,S,density, and w velocity
135
136 DO ktr=1,nTracerInUse
137 Pd(k,ktr) = tracerEnv(k,ktr)
138 ENDDO
139 Dd(k)=STATE1(Pd(k,2),Pd(k,1),i,j,k,bi,bj,myThid)
140 De(k)=Dd(k)
141 CML print *, 'ml-opps:', i,j,k,tracerEnv(k,2),tracerEnv(k,1),
142 CML & Dd(k),Pd(k,1),Pd(k,2)
143 CML compute vertical velocity at cell centers from GCM velocity
144 Wd(k)= - .5*(wVel(K)+wVel(K+1))
145 CML(
146 CML avoid division by zero
147 CML IF (Wd(K) .EQ. 0.D0) Wd(K) = 2.23e-16
148 CML)
149
150 C guess at initial top grid cell vertical velocity
151
152 CML Wd(k) = 0.03
153
154 C these estimates of initial plume velocity based on plume size and
155 C top grid cell water mass
156
157 c Wd(k) = 0.5*drF(k)/(dtts*FRACTIONAL_AREA)
158 c Wd(k) = 0.5*drF(k)/dtts
159
160 wsqr=Wd(k)*Wd(k)
161 PlumeEntrainment(k) = 0.0
162
163 #ifdef ALLOW_OPPS_DEBUG
164 IF ( OPPSdebugLevel.GE.debLevB ) THEN
165 WRITE(msgBuf,'(A,I3)')
166 & 'S/R OPPS_CALC: doing old lowerparcel', k
167 CALL PRINT_MESSAGE( msgBuf, standardMessageUnit,
168 & SQUEEZE_RIGHT , 1)
169 ENDIF
170 #endif /* ALLOW_OPPS_DEBUG */
171 radius=PlumeRadius
172 StartingFlux=radius*radius*Wd(k)*Dd(k)
173 oldflux=StartingFlux
174
175 dz2=DrF(k)
176 DO k2=k,KMax-1
177 D1=STATE1( Pd(k2,2), Pd(k2,1),i,j,k2+1,bi,bj,myThid)
178 D2=STATE1( tracerEnv(k2+1,2), tracerEnv(k2+1,1),
179 & i,j,k2+1,bi,bj,myThid)
180 De(k2+1)=D2
181
182 C To start downward, parcel has to initially be heavier than environment
183 C but after it has started moving, we continue plume until plume tke or
184 C flux goes negative
185
186 CML & _hFacC(i,j,k-1,bi,bj)
187 CML & *_hFacC(i,j,k,bi,bj) .GT. 0.
188 CML & .AND.
189 IF (D2-D1 .LT. STABILITY_THRESHOLD.or.k2.ne.k) THEN
190 dz1=dz2
191 dz2=DrF(k2+1)
192
193 C find mass flux according to eq.(3) from paper by vertical integration
194
195 newflux=oldflux+e2*radius*Wd(k2)*Dd(k2)*
196 & .5*(dz1+dz2)
197 CML print *, 'ml-opps:', i,j,k,oldflux,newflux,e2,radius,
198 CML & Wd(k2),Dd(k2),Pd(k2,1),Pd(k2,2),dz1,dz2
199
200 PlumeEntrainment(k2+1) = newflux/StartingFlux
201
202 IF(newflux.LE.0.0) then
203 #ifdef ALLOW_OPPS_DEBUG
204 IF ( OPPSdebugLevel.GE.debLevA ) THEN
205 WRITE(msgBuf,'(A,I3)')
206 & 'S/R OPPS_CALC: Plume entrained to zero at level ', k2
207 CALL PRINT_MESSAGE( msgBuf, standardMessageUnit,
208 & SQUEEZE_RIGHT , 1)
209 ENDIF
210 #endif /* ALLOW_OPPS_DEBUG */
211 maxdepth = k2
212 if(maxdepth.eq.k) goto 1000
213 goto 1
214 endif
215
216 C entrainment rate is basically a scaled mass flux dM/M
217
218 entrainrate = (newflux - oldflux)/newflux
219 oldflux = newflux
220
221 C mix var(s) are the average environmental values over the two grid levels
222
223 DO ktr=1,nTracerInUse
224 pmix=(dz1*tracerEnv(k2,ktr)+dz2*tracerEnv(k2+1,ktr))
225 & /(dz1+dz2)
226 Pd(k2+1,ktr)=Pd(k2,ktr)
227 & - entrainrate*(pmix - Pd(k2,ktr))
228 ENDDO
229
230 C compute the density at this level for the buoyancy term in the
231 C vertical k.e. equation
232
233 Dd(k2+1)=STATE1(Pd(k2+1,2),Pd(k2+1,1),i,j,k2+1,bi,bj,myThid)
234
235 C next, solve for the vertical velocity k.e. using combined eq. (4)
236 C and eq (5) from the paper
237
238 #ifdef ALLOW_OPPS_DEBUG
239 IF ( OPPSdebugLevel.GE.debLevA ) THEN
240 WRITE(msgBuf,'(A,3E12.4,I3)')
241 & 'S/R OPPS_CALC: Dd,De,entr,k ',Dd(k2),De(k2),entrainrate,k2
242 CALL PRINT_MESSAGE( msgBuf, standardMessageUnit,
243 & SQUEEZE_RIGHT , 1)
244 ENDIF
245 #endif /* ALLOW_OPPS_DEBUG */
246 CML insert Eq. (4) into Eq. (5) to get something like this for wp^2
247 wsqr = wsqr - wsqr*abs(entrainrate)+ gravity*
248 & (dz1*(Dd(k2)-De(k2))/De(k2)
249 & +dz2*(Dd(k2+1)-De(k2+1))/De(k2+1))
250
251 C if negative k.e. then plume has reached max depth, get out of loop
252
253 IF(wsqr.LE.0.0)then
254 maxdepth = k2
255 #ifdef ALLOW_OPPS_DEBUG
256 IF ( OPPSdebugLevel.GE.debLevA ) THEN
257 WRITE(msgBuf,'(A,I3)')
258 & 'S/R OPPS_CALC: Plume velocity went to zero at level ', k2
259 CALL PRINT_MESSAGE( msgBuf, standardMessageUnit,
260 & SQUEEZE_RIGHT , 1)
261 WRITE(msgBuf,'(A,4A14)')
262 & 'S/R OPPS_CALC: ', 'wsqr', 'entrainrate',
263 & '(Dd-De)/De up', '(Dd-De)/De do'
264 CALL PRINT_MESSAGE( msgBuf, standardMessageUnit,
265 & SQUEEZE_RIGHT , 1)
266 WRITE(msgBuf,'(A,4E14.6)')
267 & 'S/R OPPS_CALC: ', wsqr, entrainrate,
268 & (Dd(k2)-De(k2))/De(k2), (Dd(k2+1)-De(k2+1))/De(k2+1)
269 CALL PRINT_MESSAGE( msgBuf, standardMessageUnit,
270 & SQUEEZE_RIGHT , 1)
271 ENDIF
272 #endif /* ALLOW_OPPS_DEBUG */
273 if(maxdepth.eq.k) goto 1000
274 goto 1
275 endif
276 Wd(k2+1)=sqrt(wsqr)
277
278 C compute a new radius based on the new mass flux at this grid level
279 C from Eq. (4)
280
281 radius=sqrt(newflux/(Wd(k2)*Dd(k2)))
282 ELSE
283 maxdepth=k2
284 if(maxdepth.eq.k) goto 1000
285 GOTO 1
286 ENDIF
287 ENDDO
288
289 C plume has reached the bottom
290
291 MaxDepth=kMax
292
293 1 CONTINUE
294
295 Ad(k)=FRACTIONAL_AREA
296 IC=0
297
298 C start iteration on fractional area, not used in OGCM implementation
299
300 DO IC=1,Max_ABE_Iterations
301
302 C next compute the mass flux beteen each grid box using the entrainment
303
304 Md(k)=Wd(k)*Ad(k)
305
306 DO k2=k+1,maxDepth
307 Md(k2)=Md(k)*PlumeEntrainment(k2)
308 #ifdef ALLOW_OPPS_DEBUG
309 IF ( OPPSdebugLevel.GE.debLevA ) THEN
310 WRITE(msgBuf,'(A,2E12.4,I3)')
311 & 'S/R OPPS_CALC: Md, Wd, and k are ',Md(k2),Wd(k2),k2
312 CALL PRINT_MESSAGE( msgBuf, standardMessageUnit,
313 & SQUEEZE_RIGHT , 1)
314 ENDIF
315 #endif /* ALLOW_OPPS_DEBUG */
316 ENDDO
317
318 C Now move on to calculate new temperature using flux from
319 C Td, Sd, Wd, ta, sa, and we. Values for these variables are at
320 C center of grid cell, use weighted average to get boundary values
321
322 C use a timestep limited by the GCM model timestep and the maximum plume
323 C velocity (CFL criteria)
324
325 C calculate the weighted wd, td, and sd
326 dt = dtts
327 do k2=k,maxDepth-1
328 IF ( Wd(K2) .NE. 0. _d 0 ) dt = min(dt,drF(k2)/Wd(k2))
329
330 C time integration will be integer number of steps to get one
331 C gcm time step
332
333 ntime = nint(0.5*int(dtts/dt))
334 if(ntime.eq.0) then
335 ntime = 1
336 endif
337
338 C make sure area weighted vertical velocities match; in other words
339 C make sure mass in equals mass out at the intersection of each grid
340 C cell. Eq. (20)
341
342 mda(k2) = (md(k2)*drF(k2)+md(k2+1)*drF(k2+1))/
343 * (drF(k2)+drF(k2+1))
344
345 wda(k2) = (wd(k2)*drF(k2)+wd(k2+1)*drF(k2+1))/
346 * (drF(k2)+drF(k2+1))
347
348 DO ktr = 1, nTracerInUse
349 Pda(k2,ktr) = Pd(k2,ktr)
350 Paa(k2,ktr) = tracerEnv(k2+1,ktr)
351 ENDDO
352
353 enddo
354 dt = min(dt,dtts)
355 #ifdef ALLOW_OPPS_DEBUG
356 IF ( OPPSdebugLevel.GE.debLevA ) THEN
357 WRITE(msgBuf,'(A,F14.4)')
358 & 'S/R OPPS_CALC: time step = ', dt
359 CALL PRINT_MESSAGE( msgBuf, standardMessageUnit,
360 & SQUEEZE_RIGHT , 1)
361 ENDIF
362 #endif /* ALLOW_OPPS_DEBUG */
363 DO ktr=1,nTracerInUse
364 Pda(maxdepth,ktr) = Pd(maxdepth,ktr)
365 ENDDO
366
367 kmx = maxdepth-1
368 do nn=1,ntime
369
370 C top point
371
372 DO ktr = 1,nTracerInUse
373 tracerEnv(k,ktr) = tracerEnv(k,ktr)-
374 & (mda(k)*(Pda(k,ktr)-Paa(k,ktr)))*dt*recip_drF(k)
375 ENDDO
376
377 C now do inner points if there are any
378
379 CML if(Maxdepth-k.gt.1) then
380 CML This if statement is superfluous
381 CML IF ( k .LT. Maxdepth-1 ) THEN
382 CML DO k2=k+1,Maxdepth-1
383 CML mda(maxDepth) = 0.
384 DO k2=k+1,kmx
385 k2m1 = max(k,k2-1)
386 k2p1 = max(k2+1,maxDepth)
387
388 DO ktr = 1,nTracerInUse
389 tracerEnv(k2,ktr) = tracerEnv(k2,ktr) +
390 & (mda(k2m1)*(Pda(k2m1,ktr)-Paa(k2m1,ktr))
391 & -mda(k2) *(Pda(k2,ktr) -Paa(k2,ktr)) )
392 & *dt*recip_drF(k2)
393 ENDDO
394 ENDDO
395 CML This if statement is superfluous
396 CML ENDIF
397
398 C bottom point
399
400 DO ktr=1,nTracerInUse
401 tracerEnv(kmx+1,ktr) = tracerEnv(kmx+1,ktr)+
402 & mda(kmx)*(Pda(kmx,ktr)-Paa(kmx,ktr))*dt*recip_drF(kmx+1)
403 ENDDO
404
405 C set the environmental temp and salinity to equal new fields
406
407 DO ktr=1,nTracerInUse
408 DO k2=1,kmx
409 paa(k2,ktr) = tracerEnv(k2+1,ktr)
410 ENDDO
411 ENDDO
412
413 C end loop on number of time integration steps
414
415 enddo
416 ENDDO
417
418 C count convection event in this grid cell
419
420 OPPSconvectCount(I,J,K,bi,bj) =
421 & OPPSconvectCount(I,J,K,bi,bj) + 1. _d 0
422
423 C jump here if k = maxdepth or if level not unstable, go to next
424 C profile point
425
426 1000 continue
427
428 C end of k-loop
429
430 ENDDO
431
432 C-- End IF (DIFFERENT_MULTIPLE)
433 ENDIF
434
435 RETURN
436 END
437
438 C---+----1----+----2----+----3----+----4----+----5----+----6----+----7-|--+----|
439
440 _RL FUNCTION STATE1( sLoc, tLoc, i, j, kRef, bi, bj, myThid )
441
442 C !DESCRIPTION: \bv
443 C *===============================================================*
444 C | o SUBROUTINE STATE1
445 C | Calculates rho(S,T,p)
446 C | It is absolutely necessary to compute
447 C | the full rho and not sigma=rho-rhoConst, because
448 C | density is used as a scale factor for fluxes and velocities
449 C *===============================================================*
450 C \ev
451
452 C !USES:
453 IMPLICIT NONE
454 C == Global variables ==
455 #include "SIZE.h"
456 #include "EEPARAMS.h"
457 #include "PARAMS.h"
458 #include "GRID.h"
459 #include "DYNVARS.h"
460
461 C !INPUT/OUTPUT PARAMETERS:
462 C == Routine arguments ==
463 INTEGER i, j, kRef, bi, bj, myThid
464 _RL tLoc, sLoc
465
466 C !LOCAL VARIABLES:
467 C == Local variables ==
468 _RL rhoLoc
469 _RL pLoc
470
471 CMLC estimate pressure from depth at cell centers
472 CML mtoSI = gravity*rhoConst
473 CML pLoc = ABS(rC(kRef))*mtoSI
474
475 IF ( usingZCoords ) THEN
476 C in Z coordinates the pressure is rho0 * (hydrostatic) Potential
477 IF ( useDynP_inEos_Zc ) THEN
478 C----------
479 C NOTE: For now, totPhiHyd only contains the Potential anomaly
480 C since PhiRef is not available for Atmos and has not (yet)
481 C been added in S/R DIAGS_PHI_HYD
482 C----------
483 pLoc = rhoConst*( totPhiHyd(i,j,kRef,bi,bj)
484 & -rC(kRef)*gravity
485 & )*maskC(i,j,kRef,bi,bj)
486 ELSE
487 pLoc = -rhoConst*rC(kRef)*gravity*maskC(i,j,kRef,bi,bj)
488 ENDIF
489 ELSEIF ( usingPCoords ) THEN
490 C in P coordinates the pressure is just the coordinate of
491 C the tracer point
492 pLoc = rC(kRef)* maskC(i,j,kRef,bi,bj)
493 ENDIF
494
495 CALL FIND_RHO_SCALAR( tLoc, sLoc, pLoc, rhoLoc, myThid )
496 STATE1 = rhoLoc
497
498 #endif /* ALLOW_OPPS */
499 RETURN
500 END
501
502 #ifdef OPPS_ORGCODE
503 C---+----1----+----2----+----3----+----4----+----5----+----6----+----7-|--+----|
504
505 C Listed below is the subroutine for use in parallel 3-d circulation code.
506 C It has been used in the parallel semtner-chervin code and is now being used
507 C In the POP code. The subroutine is called nlopps (long story to explain why).
508
509 C I've attached the version of lopps that we've been using in the simulations.
510 C There is one common block that is different from the standard model commons
511 C (countc) and it is not needed if the array convadj is not used. The routine
512 C does need "kmp" which is why the boundc common is included. For massively
513 C parallel codes (like POP) we think this will work well when converted from a
514 C "slab" (i=is,ie) to a column, which just means removing the "do i=is,ie" loop.
515 C There are differences between this
516 C code and the 1-d code and the earlier scheme implemented in 3-d models. These
517 C differences are described below.
518
519 subroutine nlopps(j,is,ie,ta,sa,gcmdz)
520
521 parameter (imt = 361 , jmt = 301 , km = 30 )
522
523 C Nlopps: E. Skyllingstad and T. Paluszkiewicz
524
525 C Version: December 11, 1996
526
527 C Nlopps: This version of lopps is significantly different from
528 C the original code developed by R. Romea and T. Paluskiewicz. The
529 C code uses a flux constraint to control the change in T and S at
530 C each grid level. First, a plume profile of T,S, and W are
531 C determined using the standard plume model, but with a detraining
532 C mass instead of entraining. Thus, the T and S plume
533 C characteristics still change, but the plume contracts in size
534 C rather than expanding ala classical entraining plumes. This
535 C is heuristically more in line with large eddy simulation results.
536 C At each grid level, the convergence of plume velocity determines
537 C the flux of T and S, which is conserved by using an upstream
538 C advection. The vertical velocity is balanced so that the area
539 C weighted upward velocity equals the area weighted downdraft
540 C velocity, ensuring mass conservation. The present implementation
541 C adjusts the plume for a time period equal to the time for 1/2 of
542 C the mass of the fastest moving level to move downward. As a
543 C consequence, the model does not completely adjust the profile at
544 C each model time step, but provides a smooth adjustment over time.
545
546 c include "params.h"
547 c include "plume_fast_inc.h"
548 c include "plume_fast.h"
549 c #include "loppsd.h"
550
551 real ta(imt,km),sa(imt,km),gcmdz(km),dz(km)
552 real pdensity,wsqr,oldflux,newflux,entrainrate,adtemp
553 REAL Del,D,dza1,dza2,kd,kd1,Smix,Thmix,PlumeS,PlumeT,PlumeD
554
555 INTEGER i,j,k
556 Clfh
557 integer is,ie,k2
558 Clfh
559 REAL D1,D2,state1,Density
560 REAL dz1,dz2
561 REAL radius,StartingFlux
562 real ttemp(km),stemp(km),taa(km),saa(km)
563 real wda(km),tda(km),sda(km),mda(km)
564 real dtts,dt,sumo,sumn
565 integer ntime,nn,kmx,ic
566
567 LOGICAL debug,done
568 INTEGER MAX_ABE_ITERATIONS
569 PARAMETER(MAX_ABE_ITERATIONS=1)
570 REAL PlumeRadius
571 REAL STABILITY_THRESHOLD
572 REAL FRACTIONAL_AREA
573 REAL MAX_FRACTIONAL_AREA
574 REAL VERTICAL_VELOCITY
575 REAL ENTRAINMENT_RATE
576 REAL e2
577 PARAMETER ( PlumeRadius = 100.D0 )
578 PARAMETER ( STABILITY_THRESHOLD = -1.E-4 )
579 PARAMETER ( FRACTIONAL_AREA = .1E0 )
580 PARAMETER ( MAX_FRACTIONAL_AREA = .8E0 )
581 PARAMETER ( VERTICAL_VELOCITY = .02E0 )
582 PARAMETER ( ENTRAINMENT_RATE = -.05E0 )
583 PARAMETER ( e2 = 2.E0*ENTRAINMENT_RATE )
584 ! Arrays.
585 REAL Ad(km),Sd(km),Td(km),Wd(km),Dd(km),Md(km)
586 REAL Se(km),Te(km),We(km),De(km)
587 REAL PlumeEntrainment(km)
588 REAL GridThickness(km)
589
590 C input kmp through a common block
591
592 common / boundc / wsx(imt,jmt),wsy(imt,jmt),hfs(imt,jmt),
593 1 ple(imt,jmt),kmp(imt,jmt),kmq(imt,jmt)
594 cwmseas
595 & ,wsx1(imt,jmt),wsy1(imt,jmt)
596 1 ,wsx2(imt,jmt),wsy2(imt,jmt)
597
598 C input the variables through a common
599
600 logical problem
601 common /countc/ convadj(imt,jmt,km),ics,depth(km),problem
602
603 C-----may want to setup an option to get this only on first call
604 C otherwise it is repetive
605 C griddz is initialize by call to setupgrid
606
607 dtts = 2400
608
609 do k=1,km
610 dz(k) = 0.01*gcmdz(k)
611 enddo
612
613 do k=1,km
614 GridThickness(k) = dz(k)
615 enddo
616
617 C modified to loop over slab
618
619 DO i=is,ie
620
621 numgridpoints=kmp(i,j)
622
623 C go to next column if only 1 grid point or on land
624
625 if(numgridpoints.le.1) goto 1100
626
627 C loop over depth
628
629 debug = .false.
630
631 C first save copy of initial profile
632
633 DO k=1,NumGridPoints
634 stemp(k)=sa(i,k)
635 ttemp(k)=ta(i,k)
636
637 C do a check of t and s range, if out of bounds set flag
638
639 if(problem) then
640 write(0,*)"Code in trouble before this nlopps call"
641 return
642 endif
643
644 if(sa(i,k).gt.40..or.ta(i,k).lt.-4.0) then
645 problem = .true.
646 write(0,*)"t out of range at j ",j
647 debug = .true.
648 return
649 endif
650 ENDDO
651
652 if(debug) then
653 write(*,*)"T and S Profile at ",i,j
654 write(*,*)(ta(i,k),sa(i,k),k=1,NumGridPoints)
655 endif
656
657 DO k=1,NumGridPoints-1
658
659 C initialize the plume T,S,density, and w velocity
660
661 Sd(k)=stemp(k)
662 Td(k)=ttemp(k)
663 Dd(k)=state1(stemp(k),ttemp(k),k)
664 De(k)=Dd(k)
665 c Wd(k)=VERTICAL_VELOCITY
666
667 C guess at initial top grid cell vertical velocity
668
669 Wd(k) = 0.03
670
671 C these estimates of initial plume velocity based on plume size and
672 C top grid cell water mass
673
674 c Wd(k) = 0.5*dz(k)/(dtts*FRACTIONAL_AREA)
675 c Wd(k) = 0.5*dz(k)/dtts
676
677 wsqr=Wd(k)*Wd(k)
678 PlumeEntrainment(k) = 0.0
679
680 if(debug) write(0,*) 'Doing old lowerparcel'
681 radius=PlumeRadius
682 StartingFlux=radius*radius*Wd(k)*Dd(k)
683 oldflux=StartingFlux
684
685 dz2=GridThickness(k)
686 DO k2=k,NumGridPoints-1
687 D1=state1(Sd(k2),Td(k2),k2+1)
688 D2=state1(stemp(k2+1),ttemp(k2+1),k2+1)
689 De(k2+1)=D2
690
691 C To start downward, parcel has to initially be heavier than environment
692 C but after it has started moving, we continue plume until plume tke or
693 C flux goes negative
694
695 IF (D2-D1 .LT. STABILITY_THRESHOLD.or.k2.ne.k) THEN
696 dz1=dz2
697 dz2=GridThickness(k2+1)
698
699 C define mass flux according to eq. 4 from paper
700
701 newflux=oldflux+e2*radius*Wd(k2)*Dd(k2)*0.50*
702 . (dz1+dz2)
703
704 PlumeEntrainment(k2+1) = newflux/StartingFlux
705
706 IF(newflux.LT.0.0) then
707 if(debug) then
708 write(0,*)"Plume entrained to zero at ",k2
709 endif
710 maxdepth = k2
711 if(maxdepth.eq.k) goto 1000
712 goto 1
713 endif
714
715 C entrainment rate is basically a scaled mass flux dM/M
716
717 entrainrate = (newflux - oldflux)/newflux
718 oldflux = newflux
719
720 C mix var(s) are the average environmental values over the two grid levels
721
722 smix=(dz1*stemp(k2)+dz2*stemp(k2+1))/(dz1+dz2)
723 thmix=(dz1*ttemp(k2)+dz2*ttemp(k2+1))/(dz1+dz2)
724
725 C first compute the new salinity and temperature for this level
726 C using equations 3.6 and 3.7 from the paper
727
728 sd(k2+1)=sd(k2) - entrainrate*(smix - sd(k2))
729 td(k2+1)=td(k2) - entrainrate*(thmix - td(k2))
730
731 C compute the density at this level for the buoyancy term in the
732 C vertical k.e. equation
733
734 Dd(k2+1)=state1(Sd(k2+1),Td(k2+1),k2+1)
735
736 C next, solve for the vertical velocity k.e. using combined eq. 4
737 C and eq 5 from the paper
738
739 if(debug) then
740 write(0,*)"Dd,De,entr,k ",Dd(k2),De(k2),entrainrate,k2
741 endif
742
743 wsqr = wsqr - wsqr*abs(entrainrate)+ 9.81*
744 . (dz1*(Dd(k2)-De(k2))/De(k2)
745 . +dz2*(Dd(k2+1)-De(k2+1))/De(k2+1))
746
747 C if negative k.e. then plume has reached max depth, get out of loop
748
749 IF(wsqr.LT.0.0)then
750 maxdepth = k2
751 if(debug) then
752 write(0,*)"Plume velocity went to zero at ",k2
753 endif
754 if(maxdepth.eq.k) goto 1000
755 goto 1
756 endif
757 Wd(k2+1)=sqrt(wsqr)
758
759 C compute a new radius based on the new mass flux at this grid level
760
761 radius=sqrt(newflux/(Wd(k2)*Dd(k2)))
762 ELSE
763 maxdepth=k2
764 if(maxdepth.eq.k) goto 1000
765 GOTO 1
766 ENDIF
767 ENDDO
768
769 C plume has reached the bottom
770
771 MaxDepth=NumGridPoints
772
773 1 continue
774
775 Ad(k)=FRACTIONAL_AREA
776 IC=0
777
778 C start iteration on fractional area, not used in OGCM implementation
779
780 DO IC=1,Max_ABE_Iterations
781
782 C next compute the mass flux beteen each grid box using the entrainment
783
784 92 continue
785 Md(k)=Wd(k)*Ad(k)
786
787 DO k2=k+1,MaxDepth
788 Md(k2)=Md(k)*PlumeEntrainment(k2)
789 if(debug) then
790 write(0,*)"Md, Wd, and k are ",Md(k2),Wd(k2),k2
791 endif
792 ENDDO
793
794 C Now move on to calculate new temperature using flux from
795 C Td, Sd, Wd, ta, sa, and we. Values for these variables are at
796 C center of grid cell, use weighted average to get boundary values
797
798 C use a timestep limited by the GCM model timestep and the maximum plume
799 C velocity (CFL criteria)
800
801 C calculate the weighted wd, td, and sd
802
803 dt = dtts
804 do k2=k,maxdepth-1
805 dt = min(dt,dz(k2)/wd(k2))
806
807 C time integration will be integer number of steps to get one
808 C gcm time step
809
810 ntime = nint(0.5*int(dtts/dt))
811 if(ntime.eq.0) then
812 ntime = 1
813 endif
814
815 C make sure area weighted vertical velocities match; in other words
816 C make sure mass in equals mass out at the intersection of each grid
817 C cell.
818
819 mda(k2) = (md(k2)*dz(k2)+md(k2+1)*dz(k2+1))/
820 * (dz(k2)+dz(k2+1))
821
822 wda(k2) = (wd(k2)*dz(k2)+wd(k2+1)*dz(k2+1))/
823 * (dz(k2)+dz(k2+1))
824
825 tda(k2) = td(k2)
826 sda(k2) = sd(k2)
827
828 taa(k2) = ttemp(k2+1)
829 saa(k2) = stemp(k2+1)
830
831 enddo
832 dt = min(dt,dtts)
833 if(debug) then
834 write(0,*)"Time step is ", dt
835 endif
836 tda(maxdepth) = td(maxdepth)
837 sda(maxdepth) = sd(maxdepth)
838
839 C do top and bottom points first
840
841 kmx = maxdepth-1
842 do nn=1,ntime
843
844 ttemp(k) = ttemp(k)-
845 * (mda(k)*(tda(k)-taa(k)))*dt*recip_drF(k)
846
847 stemp(k) = stemp(k)-
848 * (mda(k)*(sda(k)-saa(k)))*dt*recip_drF(k)
849
850 C now do inner points if there are any
851
852 if(Maxdepth-k.gt.1) then
853 do k2=k+1,Maxdepth-1
854
855 ttemp(k2) = ttemp(k2) +
856 * (mda(k2-1)*(tda(k2-1)-taa(k2-1))-
857 * mda(k2)*(tda(k2)-taa(k2)))
858 * *dt*recip_drF(k2)
859
860 stemp(k2) = stemp(k2) +
861 * (mda(k2-1)*(sda(k2-1)-saa(k2-1))-
862 * mda(k2)*(sda(k2)-saa(k2)))
863 * *dt*recip_drF(k2)
864
865 enddo
866 endif
867 ttemp(kmx+1) = ttemp(kmx+1)+
868 * (mda(kmx)*(tda(kmx)-taa(kmx)))*
869 * dt*recip_drF(kmx+1)
870
871 stemp(kmx+1) = stemp(kmx+1)+
872 * (mda(kmx)*(sda(kmx)-saa(kmx)))*
873 * dt*recip_drF(kmx+1)
874
875 C set the environmental temp and salinity to equal new fields
876
877 do k2=1,maxdepth-1
878 taa(k2) = ttemp(k2+1)
879 saa(k2) = stemp(k2+1)
880 enddo
881
882 C end loop on number of time integration steps
883
884 enddo
885 ENDDO
886 999 continue
887
888 C assume that it converged, so update the ta and sa with new fields
889
890 c if(i.gt.180.and.j.gt.200.and.i.lt.240) then
891 c write(*,*)"Converged ",i,j,k,maxdepth,ttemp(k+1),ta(i,k+1)
892 c endif
893 do k2=k,maxdepth
894 convadj(i,j,k2) = convadj(i,j,k2) + (ttemp(k2)-
895 * ta(i,k2))
896 sa(i,k2) = stemp(k2)
897 ta(i,k2) = ttemp(k2)
898 c if(i.gt.180.and.j.gt.200.and.i.lt.240) then
899 c write(*,*)"convadj ",convadj(i,j,k2)
900 c endif
901
902 C see if nlopps messed up
903
904 if(sa(i,k).gt.40..or.ta(i,k).lt.-4.0) then
905 problem = .true.
906 write(0,*)"t out of range at j after adjust",j
907 debug = .true.
908 endif
909
910 enddo
911
912 C jump here if k = maxdepth or if level not unstable, go to next
913 C profile point
914
915 1000 continue
916
917 C end loop on k, move on to next possible plume
918
919 ENDDO
920 1100 continue
921
922 C i loop
923
924 ENDDO
925 END
926
927 #endif /* OPPS_ORGCODE */

  ViewVC Help
Powered by ViewVC 1.1.22