GCC Code Coverage Report


Directory: ./
File: phys/slab_heat_transp_mod.f90
Date: 2022-01-11 19:19:34
Exec Total Coverage
Lines: 0 484 0.0%
Branches: 0 594 0.0%

Line Branch Exec Source
1 !
2 MODULE slab_heat_transp_mod
3 !
4 ! Slab ocean : temperature tendencies due to horizontal diffusion
5 ! and / or Ekman transport
6
7 USE mod_grid_phy_lmdz, ONLY: nbp_lon, nbp_lat, klon_glo
8 IMPLICIT NONE
9
10 ! Variables copied over from dyn3d dynamics:
11 REAL,SAVE,ALLOCATABLE :: fext(:) ! Coriolis f times cell area
12 !$OMP THREADPRIVATE(fext)
13 REAL,SAVE,ALLOCATABLE :: beta(:) ! df/dy
14 !$OMP THREADPRIVATE(beta)
15 REAL,SAVE,ALLOCATABLE :: unsairez(:) ! 1/cell area
16 !$OMP THREADPRIVATE(unsairez)
17 REAL,SAVE,ALLOCATABLE :: unsaire(:)
18 !$OMP THREADPRIVATE(unsaire)
19 REAL,SAVE,ALLOCATABLE :: cu(:) ! cell longitude dim (m)
20 !$OMP THREADPRIVATE(cu)
21 REAL,SAVE,ALLOCATABLE :: cv(:) ! cell latitude dim (m)
22 !$OMP THREADPRIVATE(cv)
23 REAL,SAVE,ALLOCATABLE :: cuvsurcv(:) ! cu/cv (v points)
24 !$OMP THREADPRIVATE(cuvsurcv)
25 REAL,SAVE,ALLOCATABLE :: cvusurcu(:) ! cv/cu (u points)
26 !$OMP THREADPRIVATE(cvusurcu)
27 REAL,SAVE,ALLOCATABLE :: aire(:) ! cell area
28 !$OMP THREADPRIVATE(aire)
29 REAL,SAVE :: apoln ! area of north pole points
30 !$OMP THREADPRIVATE(apoln)
31 REAL,SAVE :: apols ! area of south pole points
32 !$OMP THREADPRIVATE(apols)
33 REAL,SAVE,ALLOCATABLE :: aireu(:) ! area of u cells
34 !$OMP THREADPRIVATE(aireu)
35 REAL,SAVE,ALLOCATABLE :: airev(:) ! area of v cells
36 !$OMP THREADPRIVATE(airev)
37
38 ! Local parameters for slab transport
39 LOGICAL,SAVE :: alpha_var ! variable coef for deep temp (1 layer)
40 !$OMP THREADPRIVATE(alpha_var)
41 LOGICAL,SAVE :: slab_upstream ! upstream scheme ? (1 layer)
42 !$OMP THREADPRIVATE(slab_upstream)
43 LOGICAL,SAVE :: slab_sverdrup ! use wind stress curl at equator
44 !$OMP THREADPRIVATE(slab_sverdrup)
45 LOGICAL,SAVE :: slab_tyeq ! use merid wind stress at equator
46 !$OMP THREADPRIVATE(slab_tyeq)
47 LOGICAL,SAVE :: ekman_zonadv ! use zonal advection by Ekman currents
48 !$OMP THREADPRIVATE(ekman_zonadv)
49 LOGICAL,SAVE :: ekman_zonavg ! zonally average wind stress
50 !$OMP THREADPRIVATE(ekman_zonavg)
51
52 REAL,SAVE :: alpham
53 !$OMP THREADPRIVATE(alpham)
54 REAL,SAVE :: gmkappa
55 !$OMP THREADPRIVATE(gmkappa)
56 REAL,SAVE :: gm_smax
57 !$OMP THREADPRIVATE(gm_smax)
58
59 ! geometry variables : f, beta, mask...
60 REAL,SAVE,ALLOCATABLE :: zmasqu(:) ! continent mask for zonal mass flux
61 !$OMP THREADPRIVATE(zmasqu)
62 REAL,SAVE,ALLOCATABLE :: zmasqv(:) ! continent mask for merid mass flux
63 !$OMP THREADPRIVATE(zmasqv)
64 REAL,SAVE,ALLOCATABLE :: unsfv(:) ! 1/f, v points
65 !$OMP THREADPRIVATE(unsfv)
66 REAL,SAVE,ALLOCATABLE :: unsbv(:) ! 1/beta
67 !$OMP THREADPRIVATE(unsbv)
68 REAL,SAVE,ALLOCATABLE :: unsev(:) ! 1/epsilon (drag)
69 !$OMP THREADPRIVATE(unsev)
70 REAL,SAVE,ALLOCATABLE :: unsfu(:) ! 1/F, u points
71 !$OMP THREADPRIVATE(unsfu)
72 REAL,SAVE,ALLOCATABLE :: unseu(:)
73 !$OMP THREADPRIVATE(unseu)
74
75 ! Routines from dyn3d, valid on global dynamics grid only:
76 PRIVATE :: gr_fi_dyn, gr_dyn_fi ! to go between 1D nd 2D horiz grid
77 PRIVATE :: gr_scal_v,gr_v_scal,gr_scal_u ! change on 2D grid U,V, T points
78 PRIVATE :: grad,diverg
79
80 CONTAINS
81
82 SUBROUTINE ini_slab_transp_geom(ip1jm,ip1jmp1,unsairez_,fext_,unsaire_,&
83 cu_,cuvsurcv_,cv_,cvusurcu_, &
84 aire_,apoln_,apols_, &
85 aireu_,airev_,rlatv, rad, omeg)
86 ! number of points in lon, lat
87 IMPLICIT NONE
88 ! Routine copies some geometry variables from the dynamical core
89 ! see global vars for meaning
90 INTEGER,INTENT(IN) :: ip1jm
91 INTEGER,INTENT(IN) :: ip1jmp1
92 REAL,INTENT(IN) :: unsairez_(ip1jm)
93 REAL,INTENT(IN) :: fext_(ip1jm)
94 REAL,INTENT(IN) :: unsaire_(ip1jmp1)
95 REAL,INTENT(IN) :: cu_(ip1jmp1)
96 REAL,INTENT(IN) :: cuvsurcv_(ip1jm)
97 REAL,INTENT(IN) :: cv_(ip1jm)
98 REAL,INTENT(IN) :: cvusurcu_(ip1jmp1)
99 REAL,INTENT(IN) :: aire_(ip1jmp1)
100 REAL,INTENT(IN) :: apoln_
101 REAL,INTENT(IN) :: apols_
102 REAL,INTENT(IN) :: aireu_(ip1jmp1)
103 REAL,INTENT(IN) :: airev_(ip1jm)
104 REAL,INTENT(IN) :: rlatv(nbp_lat-1)
105 REAL,INTENT(IN) :: rad
106 REAL,INTENT(IN) :: omeg
107
108 CHARACTER (len = 20) :: modname = 'slab_heat_transp'
109 CHARACTER (len = 80) :: abort_message
110
111 ! Sanity check on dimensions
112 if ((ip1jm.ne.((nbp_lon+1)*(nbp_lat-1))).or. &
113 (ip1jmp1.ne.((nbp_lon+1)*nbp_lat))) then
114 abort_message="ini_slab_transp_geom Error: wrong array sizes"
115 CALL abort_physic(modname,abort_message,1)
116 endif
117 ! Allocations could be done only on master process/thread...
118 allocate(unsairez(ip1jm))
119 unsairez(:)=unsairez_(:)
120 allocate(fext(ip1jm))
121 fext(:)=fext_(:)
122 allocate(unsaire(ip1jmp1))
123 unsaire(:)=unsaire_(:)
124 allocate(cu(ip1jmp1))
125 cu(:)=cu_(:)
126 allocate(cuvsurcv(ip1jm))
127 cuvsurcv(:)=cuvsurcv_(:)
128 allocate(cv(ip1jm))
129 cv(:)=cv_(:)
130 allocate(cvusurcu(ip1jmp1))
131 cvusurcu(:)=cvusurcu_(:)
132 allocate(aire(ip1jmp1))
133 aire(:)=aire_(:)
134 apoln=apoln_
135 apols=apols_
136 allocate(aireu(ip1jmp1))
137 aireu(:)=aireu_(:)
138 allocate(airev(ip1jm))
139 airev(:)=airev_(:)
140 allocate(beta(nbp_lat-1))
141 beta(:)=2*omeg*cos(rlatv(:))/rad
142
143 END SUBROUTINE ini_slab_transp_geom
144
145 SUBROUTINE ini_slab_transp(zmasq)
146
147 ! USE ioipsl_getin_p_mod, only: getin_p
148 USE IOIPSL, ONLY : getin
149 IMPLICIT NONE
150
151 REAL zmasq(klon_glo) ! ocean / continent mask, 1=continent
152 REAL zmasq_2d((nbp_lon+1)*nbp_lat)
153 REAL ff((nbp_lon+1)*(nbp_lat-1)) ! Coriolis parameter
154 REAL eps ! epsilon friction timescale (s-1)
155 INTEGER :: slab_ekman
156 INTEGER i
157 INTEGER :: iim,iip1,jjp1,ip1jm,ip1jmp1
158
159 ! Some definition for grid size
160 ip1jm=(nbp_lon+1)*(nbp_lat-1)
161 ip1jmp1=(nbp_lon+1)*nbp_lat
162 iim=nbp_lon
163 iip1=nbp_lon+1
164 jjp1=nbp_lat
165 ip1jm=(nbp_lon+1)*(nbp_lat-1)
166 ip1jmp1=(nbp_lon+1)*nbp_lat
167
168 ! Options for Heat transport
169 ! Alpha variable?
170 alpha_var=.FALSE.
171 CALL getin('slab_alphav',alpha_var)
172 print *,'alpha variable',alpha_var
173 ! centered ou upstream scheme for meridional transport
174 slab_upstream=.FALSE.
175 CALL getin('slab_upstream',slab_upstream)
176 print *,'upstream slab scheme',slab_upstream
177 ! Sverdrup balance at equator ?
178 slab_sverdrup=.TRUE.
179 CALL getin('slab_sverdrup',slab_sverdrup)
180 print *,'Sverdrup balance',slab_sverdrup
181 ! Use tauy for meridional flux at equator ?
182 slab_tyeq=.TRUE.
183 CALL getin('slab_tyeq',slab_tyeq)
184 print *,'Tauy forcing at equator',slab_tyeq
185 ! Use tauy for meridional flux at equator ?
186 ekman_zonadv=.TRUE.
187 CALL getin('slab_ekman_zonadv',ekman_zonadv)
188 print *,'Use Ekman flow in zonal direction',ekman_zonadv
189 ! Use tauy for meridional flux at equator ?
190 ekman_zonavg=.FALSE.
191 CALL getin('slab_ekman_zonavg',ekman_zonavg)
192 print *,'Use zonally-averaged wind stress ?',ekman_zonavg
193 ! Value of alpha
194 alpham=2./3.
195 CALL getin('slab_alpha',alpham)
196 print *,'slab_alpha',alpham
197 ! GM k coefficient (m2/s) for 2-layers
198 gmkappa=1000.
199 CALL getin('slab_gmkappa',gmkappa)
200 print *,'slab_gmkappa',gmkappa
201 ! GM k coefficient (m2/s) for 2-layers
202 gm_smax=2e-3
203 CALL getin('slab_gm_smax',gm_smax)
204 print *,'slab_gm_smax',gm_smax
205 ! -----------------------------------------------------------
206 ! Define ocean / continent mask (no flux into continent cell)
207 allocate(zmasqu(ip1jmp1))
208 allocate(zmasqv(ip1jm))
209 zmasqu=1.
210 zmasqv=1.
211
212 ! convert mask to 2D grid
213 CALL gr_fi_dyn(1,iip1,jjp1,zmasq,zmasq_2d)
214 ! put flux mask to 0 at boundaries of continent cells
215 DO i=1,ip1jmp1-1
216 IF (zmasq_2d(i).GT.1e-5 .OR. zmasq_2d(i+1).GT.1e-5) THEN
217 zmasqu(i)=0.
218 ENDIF
219 END DO
220 DO i=iip1,ip1jmp1,iip1
221 zmasqu(i)=zmasqu(i-iim)
222 END DO
223 DO i=1,ip1jm
224 IF (zmasq_2d(i).GT.1e-5 .OR. zmasq_2d(i+iip1).GT.1e-5) THEN
225 zmasqv(i)=0.
226 END IF
227 END DO
228
229 ! -----------------------------------------------------------
230 ! Coriolis and friction for Ekman transport
231 slab_ekman=2
232 CALL getin("slab_ekman",slab_ekman)
233 IF (slab_ekman.GT.0) THEN
234 allocate(unsfv(ip1jm))
235 allocate(unsev(ip1jm))
236 allocate(unsfu(ip1jmp1))
237 allocate(unseu(ip1jmp1))
238 allocate(unsbv(ip1jm))
239
240 eps=1e-5 ! Drag
241 CALL getin('slab_eps',eps)
242 print *,'epsilon=',eps
243 ff=fext*unsairez ! Coriolis
244 ! coefs to convert tau_x, tau_y to Ekman mass fluxes
245 ! on 2D grid v points
246 ! Compute correction factor [0 1] near the equator (f<<eps)
247 IF (slab_sverdrup) THEN
248 ! New formulation, sharper near equator, when eps gives Rossby Radius
249 DO i=1,ip1jm
250 unsev(i)=exp(-ff(i)*ff(i)/eps**2)
251 ENDDO
252 ELSE
253 DO i=1,ip1jm
254 unsev(i)=eps**2/(ff(i)*ff(i)+eps**2)
255 ENDDO
256 END IF ! slab_sverdrup
257 ! 1/beta
258 DO i=1,jjp1-1
259 unsbv((i-1)*iip1+1:i*iip1)=unsev((i-1)*iip1+1:i*iip1)/beta(i)
260 END DO
261 ! 1/f
262 ff=SIGN(MAX(ABS(ff),eps/100.),ff) ! avoid value 0 at equator...
263 DO i=1,ip1jm
264 unsfv(i)=(1.-unsev(i))/ff(i)
265 END DO
266 ! compute values on 2D u grid
267 ! 1/eps
268 unsev(:)=unsev(:)/eps
269 CALL gr_v_scal(1,unsfv,unsfu)
270 CALL gr_v_scal(1,unsev,unseu)
271 END IF
272
273 END SUBROUTINE ini_slab_transp
274
275 SUBROUTINE divgrad_phy(nlevs,temp,delta)
276 ! Computes temperature tendency due to horizontal diffusion :
277 ! T Laplacian, later multiplied by diffusion coef and time-step
278
279 IMPLICIT NONE
280
281 INTEGER, INTENT(IN) :: nlevs ! nlevs : slab layers
282 REAL, INTENT(IN) :: temp(klon_glo,nlevs) ! slab temperature
283 REAL , INTENT(OUT) :: delta(klon_glo,nlevs) ! temp laplacian (heat flux div.)
284 REAL :: delta_2d((nbp_lon+1)*nbp_lat,nlevs)
285 REAL ghx((nbp_lon+1)*nbp_lat,nlevs), ghy((nbp_lon+1)*(nbp_lat-1),nlevs)
286 INTEGER :: ll,iip1,jjp1
287
288 iip1=nbp_lon+1
289 jjp1=nbp_lat
290
291 ! transpose temp to 2D horiz. grid
292 CALL gr_fi_dyn(nlevs,iip1,jjp1,temp,delta_2d)
293 ! computes gradient (proportional to heat flx)
294 CALL grad(nlevs,delta_2d,ghx,ghy)
295 ! put flux to 0 at ocean / continent boundary
296 DO ll=1,nlevs
297 ghx(:,ll)=ghx(:,ll)*zmasqu
298 ghy(:,ll)=ghy(:,ll)*zmasqv
299 END DO
300 ! flux divergence
301 CALL diverg(nlevs,ghx,ghy,delta_2d)
302 ! laplacian back to 1D grid
303 CALL gr_dyn_fi(nlevs,iip1,jjp1,delta_2d,delta)
304
305 RETURN
306 END SUBROUTINE divgrad_phy
307
308 SUBROUTINE slab_ekman1(tx_phy,ty_phy,ts_phy,dt_phy)
309 ! 1.5 Layer Ekman transport temperature tendency
310 ! note : tendency dt later multiplied by (delta t)/(rho.H)
311 ! to convert from divergence of heat fluxes to T
312
313 IMPLICIT NONE
314
315 ! tx, ty : wind stress (different grids)
316 ! fluxm, fluz : mass *or heat* fluxes
317 ! dt : temperature tendency
318 INTEGER ij
319
320 ! ts surface temp, td deep temp (diagnosed)
321 REAL ts_phy(klon_glo)
322 REAL ts((nbp_lon+1)*nbp_lat),td((nbp_lon+1)*nbp_lat)
323 ! zonal and meridional wind stress
324 REAL tx_phy(klon_glo),ty_phy(klon_glo)
325 REAL tyu((nbp_lon+1)*nbp_lat),txu((nbp_lon+1)*nbp_lat)
326 REAL txv((nbp_lon+1)*(nbp_lat-1)),tyv((nbp_lon+1)*(nbp_lat-1))
327 REAL tcurl((nbp_lon+1)*(nbp_lat-1))
328 ! zonal and meridional Ekman mass fluxes at u, v points (2D grid)
329 REAL fluxz((nbp_lon+1)*nbp_lat),fluxm((nbp_lon+1)*(nbp_lat-1))
330 ! vertical and absolute mass fluxes (to estimate alpha)
331 REAL fluxv((nbp_lon+1)*nbp_lat),fluxt((nbp_lon+1)*(nbp_lat-1))
332 ! temperature tendency
333 REAL dt((nbp_lon+1)*nbp_lat),dt_phy(klon_glo)
334 REAL alpha((nbp_lon+1)*nbp_lat) ! deep temperature coef
335
336 INTEGER iim,iip1,iip2,jjp1,ip1jm,ip1jmi1,ip1jmp1
337
338 ! Grid definitions
339 iim=nbp_lon
340 iip1=nbp_lon+1
341 iip2=nbp_lon+2
342 jjp1=nbp_lat
343 ip1jm=(nbp_lon+1)*(nbp_lat-1) ! = iip1*jjm
344 ip1jmi1=(nbp_lon+1)*(nbp_lat-1)-(nbp_lon+1) ! = ip1jm - iip1
345 ip1jmp1=(nbp_lon+1)*nbp_lat ! = iip1*jjp1
346
347 ! Convert taux,y to 2D scalar grid
348 ! Note: 2D grid size = iim*jjm. iip1=iim+1
349 ! First and last points in zonal direction are the same
350 ! we use 1 index ij from 1 to (iim+1)*(jjm+1)
351 ! north and south poles
352 tx_phy(1)=0.
353 tx_phy(klon_glo)=0.
354 ty_phy(1)=0.
355 ty_phy(klon_glo)=0.
356 CALL gr_fi_dyn(1,iip1,jjp1,tx_phy,txu)
357 CALL gr_fi_dyn(1,iip1,jjp1,ty_phy,tyu)
358 ! convert to u,v grid (Arakawa C)
359 ! Multiply by f or eps to get mass flux
360 ! Meridional mass flux
361 CALL gr_scal_v(1,txu,txv) ! wind stress at v points
362 IF (slab_sverdrup) THEN ! Sverdrup bal. near equator
363 tcurl=(txu(1:ip1jm)-txu(iip2:ip1jmp1))/cv(:)
364 fluxm=-tcurl*unsbv-txv*unsfv ! in kg.s-1.m-1 (zonal distance)
365 ELSE
366 CALL gr_scal_v(1,tyu,tyv)
367 fluxm=tyv*unsev-txv*unsfv ! in kg.s-1.m-1 (zonal distance)
368 ENDIF
369 ! Zonal mass flux
370 CALL gr_scal_u(1,txu,txu) ! wind stress at u points
371 CALL gr_scal_u(1,tyu,tyu)
372 fluxz=tyu*unsfu+txu*unseu
373
374 ! Correct flux: continent mask and horiz grid size
375 ! multiply m-flux by mask and dx: flux in kg.s-1
376 fluxm=fluxm*cv*cuvsurcv*zmasqv
377 ! multiply z-flux by mask and dy: flux in kg.s-1
378 fluxz=fluxz*cu*cvusurcu*zmasqu
379
380 ! Compute vertical and absolute mass flux (for variable alpha)
381 IF (alpha_var) THEN
382 DO ij=iip2,ip1jm
383 fluxv(ij)=fluxz(ij)-fluxz(ij-1)-fluxm(ij)+fluxm(ij-iip1)
384 fluxt(ij)=ABS(fluxz(ij))+ABS(fluxz(ij-1)) &
385 +ABS(fluxm(ij))+ABS(fluxm(ij-iip1))
386 ENDDO
387 DO ij=iip1,ip1jmi1,iip1
388 fluxt(ij+1)=fluxt(ij+iip1)
389 fluxv(ij+1)=fluxv(ij+iip1)
390 END DO
391 fluxt(1)=SUM(ABS(fluxm(1:iim)))
392 fluxt(ip1jmp1)=SUM(ABS(fluxm(ip1jm-iim:ip1jm-1)))
393 fluxv(1)=-SUM(fluxm(1:iim))
394 fluxv(ip1jmp1)=SUM(fluxm(ip1jm-iim:ip1jm-1))
395 fluxt=MAX(fluxt,1.e-10)
396 ENDIF
397
398 ! Compute alpha coefficient.
399 ! Tdeep = Tsurf * alpha + 271.35 * (1-alpha)
400 IF (alpha_var) THEN
401 ! increase alpha (and Tdeep) in downwelling regions
402 ! and decrease in upwelling regions
403 ! to avoid "hot spots" where there is surface convergence
404 DO ij=iip2,ip1jm
405 alpha(ij)=alpham-fluxv(ij)/fluxt(ij)*(1.-alpham)
406 ENDDO
407 alpha(1:iip1)=alpham-fluxv(1)/fluxt(1)*(1.-alpham)
408 alpha(ip1jm+1:ip1jmp1)=alpham-fluxv(ip1jmp1)/fluxt(ip1jmp1)*(1.-alpham)
409 ELSE
410 alpha(:)=alpham
411 ! Tsurf-Tdeep ~ 10� in the Tropics
412 ENDIF
413
414 ! Estimate deep temperature
415 CALL gr_fi_dyn(1,iip1,jjp1,ts_phy,ts)
416 DO ij=1,ip1jmp1
417 td(ij)=271.35+(ts(ij)-271.35)*alpha(ij)
418 td(ij)=MIN(td(ij),ts(ij))
419 END DO
420
421 ! Meridional heat flux: multiply mass flux by (ts-td)
422 ! flux in K.kg.s-1
423 IF (slab_upstream) THEN
424 ! upstream scheme to avoid hot spots
425 DO ij=1,ip1jm
426 IF (fluxm(ij).GE.0.) THEN
427 fluxm(ij)=fluxm(ij)*(ts(ij+iip1)-td(ij))
428 ELSE
429 fluxm(ij)=fluxm(ij)*(ts(ij)-td(ij+iip1))
430 END IF
431 END DO
432 ELSE
433 ! centered scheme better in mid-latitudes
434 DO ij=1,ip1jm
435 fluxm(ij)=fluxm(ij)*(ts(ij+iip1)+ts(ij)-td(ij)-td(ij+iip1))/2.
436 END DO
437 ENDIF
438
439 ! Zonal heat flux
440 ! upstream scheme
441 DO ij=iip2,ip1jm
442 fluxz(ij)=fluxz(ij)*(ts(ij)+ts(ij+1)-td(ij+1)-td(ij))/2.
443 END DO
444 DO ij=iip1*2,ip1jmp1,iip1
445 fluxz(ij)=fluxz(ij-iim)
446 END DO
447
448 ! temperature tendency = divergence of heat fluxes
449 ! dt in K.s-1.kg.m-2 (T trend times mass/horiz surface)
450 DO ij=iip2,ip1jm
451 dt(ij)=(fluxz(ij-1)-fluxz(ij)+fluxm(ij)-fluxm(ij-iip1)) &
452 /aire(ij) ! aire : grid area
453 END DO
454 DO ij=iip1,ip1jmi1,iip1
455 dt(ij+1)=dt(ij+iip1)
456 END DO
457 ! special treatment at the Poles
458 dt(1)=SUM(fluxm(1:iim))/apoln
459 dt(ip1jmp1)=-SUM(fluxm(ip1jm-iim:ip1jm-1))/apols
460 dt(2:iip1)=dt(1)
461 dt(ip1jm+1:ip1jmp1)=dt(ip1jmp1)
462
463 ! tendencies back to 1D grid
464 CALL gr_dyn_fi(1,iip1,jjp1,dt,dt_phy)
465
466 RETURN
467 END SUBROUTINE slab_ekman1
468
469 SUBROUTINE slab_ekman2(tx_phy,ty_phy,ts_phy,dt_phy_ek,dt_phy_gm,slab_gm)
470 ! Temperature tendency for 2-layers slab ocean
471 ! note : tendency dt later multiplied by (delta time)/(rho.H)
472 ! to convert from divergence of heat fluxes to T
473
474 ! 11/16 : Inclusion of GM-like eddy advection
475
476 IMPLICIT NONE
477
478 LOGICAL,INTENT(in) :: slab_gm
479 ! Here, temperature and flux variables are on 2 layers
480 INTEGER ij
481
482 ! wind stress variables
483 REAL tx_phy(klon_glo),ty_phy(klon_glo)
484 REAL txv((nbp_lon+1)*(nbp_lat-1)), tyv((nbp_lon+1)*(nbp_lat-1))
485 REAL tyu((nbp_lon+1)*nbp_lat),txu((nbp_lon+1)*nbp_lat)
486 REAL tcurl((nbp_lon+1)*(nbp_lat-1))
487 ! slab temperature on 1D, 2D grid
488 REAL ts_phy(klon_glo,2), ts((nbp_lon+1)*nbp_lat,2)
489 ! Temperature gradient, v-points
490 REAL dty((nbp_lon+1)*(nbp_lat-1)),dtx((nbp_lon+1)*nbp_lat)
491 ! Vertical temperature difference, V-points
492 REAL dtz((nbp_lon+1)*(nbp_lat-1))
493 ! zonal and meridional mass fluxes at u, v points (2D grid)
494 REAL fluxz((nbp_lon+1)*nbp_lat), fluxm((nbp_lon+1)*(nbp_lat-1))
495 ! vertical mass flux between the 2 layers
496 REAL fluxv_ek((nbp_lon+1)*nbp_lat)
497 REAL fluxv_gm((nbp_lon+1)*nbp_lat)
498 ! zonal and meridional heat fluxes
499 REAL fluxtz((nbp_lon+1)*nbp_lat,2)
500 REAL fluxtm((nbp_lon+1)*(nbp_lat-1),2)
501 ! temperature tendency (in K.s-1.kg.m-2)
502 REAL dt_ek((nbp_lon+1)*nbp_lat,2), dt_phy_ek(klon_glo,2)
503 REAL dt_gm((nbp_lon+1)*nbp_lat,2), dt_phy_gm(klon_glo,2)
504 ! helper vars
505 REAL zonavg, fluxv
506 REAL, PARAMETER :: sea_den=1025. ! sea water density
507
508 INTEGER iim,iip1,iip2,jjp1,ip1jm,ip1jmi1,ip1jmp1
509
510 ! Grid definitions
511 iim=nbp_lon
512 iip1=nbp_lon+1
513 iip2=nbp_lon+2
514 jjp1=nbp_lat
515 ip1jm=(nbp_lon+1)*(nbp_lat-1) ! = iip1*jjm
516 ip1jmi1=(nbp_lon+1)*(nbp_lat-1)-(nbp_lon+1) ! = ip1jm - iip1
517 ip1jmp1=(nbp_lon+1)*nbp_lat ! = iip1*jjp1
518 ! Convert temperature to 2D grid
519 CALL gr_fi_dyn(2,iip1,jjp1,ts_phy,ts)
520
521 ! ------------------------------------
522 ! Ekman mass fluxes and Temp tendency
523 ! ------------------------------------
524 ! Convert taux,y to 2D scalar grid
525 ! north and south poles tx,ty no meaning
526 tx_phy(1)=0.
527 tx_phy(klon_glo)=0.
528 ty_phy(1)=0.
529 ty_phy(klon_glo)=0.
530 CALL gr_fi_dyn(1,iip1,jjp1,tx_phy,txu)
531 CALL gr_fi_dyn(1,iip1,jjp1,ty_phy,tyu)
532 IF (ekman_zonavg) THEN ! use zonal average of wind stress
533 DO ij=1,jjp1-2
534 zonavg=SUM(txu(ij*iip1+1:ij*iip1+iim))/iim
535 txu(ij*iip1+1:(ij+1)*iip1)=zonavg
536 zonavg=SUM(tyu(ij*iip1+1:ij*iip1+iim))/iim
537 tyu(ij*iip1+1:(ij+1)*iip1)=zonavg
538 END DO
539 END IF
540
541 ! Divide taux,y by f or eps, and convert to 2D u,v grids
542 ! (Arakawa C grid)
543 ! Meridional flux
544 CALL gr_scal_v(1,txu,txv) ! wind stress at v points
545 fluxm=-txv*unsfv ! in kg.s-1.m-1 (zonal distance)
546 IF (slab_sverdrup) THEN ! Sverdrup bal. near equator
547 tcurl=(txu(1:ip1jm)-txu(iip2:ip1jmp1))/cv(:) ! dtx/dy
548 !poles curl = 0
549 tcurl(1:iip1)=0.
550 tcurl(ip1jmi1+1:ip1jm)=0.
551 fluxm=fluxm-tcurl*unsbv
552 ENDIF
553 IF (slab_tyeq) THEN ! meridional wind forcing at equator
554 CALL gr_scal_v(1,tyu,tyv)
555 fluxm=fluxm+tyv*unsev ! in kg.s-1.m-1 (zonal distance)
556 ENDIF
557 ! apply continent mask, multiply by horiz grid dimension
558 fluxm=fluxm*cv*cuvsurcv*zmasqv
559
560 ! Zonal flux
561 IF (ekman_zonadv) THEN
562 CALL gr_scal_u(1,txu,txu) ! wind stress at u points
563 CALL gr_scal_u(1,tyu,tyu)
564 fluxz=tyu*unsfu+txu*unseu
565 ! apply continent mask, multiply by horiz grid dimension
566 fluxz=fluxz*cu*cvusurcu*zmasqu
567 END IF
568
569 ! Vertical mass flux from mass budget (divergence of horiz fluxes)
570 IF (ekman_zonadv) THEN
571 DO ij=iip2,ip1jm
572 fluxv_ek(ij)=fluxz(ij)-fluxz(ij-1)-fluxm(ij)+fluxm(ij-iip1)
573 ENDDO
574 ELSE
575 DO ij=iip2,ip1jm
576 fluxv_ek(ij)=-fluxm(ij)+fluxm(ij-iip1)
577 ENDDO
578 END IF
579 DO ij=iip1,ip1jmi1,iip1
580 fluxv_ek(ij+1)=fluxv_ek(ij+iip1)
581 END DO
582 ! vertical mass flux at Poles
583 fluxv_ek(1)=-SUM(fluxm(1:iim))
584 fluxv_ek(ip1jmp1)=SUM(fluxm(ip1jm-iim:ip1jm-1))
585
586 ! Meridional heat fluxes
587 DO ij=1,ip1jm
588 ! centered scheme
589 fluxtm(ij,1)=fluxm(ij)*(ts(ij+iip1,1)+ts(ij,1))/2.
590 fluxtm(ij,2)=-fluxm(ij)*(ts(ij+iip1,2)+ts(ij,2))/2.
591 END DO
592
593 ! Zonal heat fluxes
594 ! Schema upstream
595 IF (ekman_zonadv) THEN
596 DO ij=iip2,ip1jm
597 IF (fluxz(ij).GE.0.) THEN
598 fluxtz(ij,1)=fluxz(ij)*ts(ij,1)
599 fluxtz(ij,2)=-fluxz(ij)*ts(ij+1,2)
600 ELSE
601 fluxtz(ij,1)=fluxz(ij)*ts(ij+1,1)
602 fluxtz(ij,2)=-fluxz(ij)*ts(ij,2)
603 ENDIF
604 ENDDO
605 DO ij=iip1*2,ip1jmp1,iip1
606 fluxtz(ij,:)=fluxtz(ij-iim,:)
607 END DO
608 ELSE
609 fluxtz(:,:)=0.
610 ENDIF
611
612 ! Temperature tendency, horizontal advection:
613 DO ij=iip2,ip1jm
614 dt_ek(ij,:)=fluxtz(ij-1,:)-fluxtz(ij,:) &
615 +fluxtm(ij,:)-fluxtm(ij-iip1,:)
616 END DO
617 ! Poles
618 dt_ek(1,:)=SUM(fluxtm(1:iim,:),dim=1)
619 dt_ek(ip1jmp1,:)=-SUM(fluxtm(ip1jm-iim:ip1jm-1,:),dim=1)
620
621 ! ------------------------------------
622 ! GM mass fluxes and Temp tendency
623 ! ------------------------------------
624 IF (slab_gm) THEN
625 ! Vertical Temperature difference T1-T2 on v-grid points
626 CALL gr_scal_v(1,ts(:,1)-ts(:,2),dtz)
627 dtz(:)=MAX(dtz(:),0.25)
628 ! Horizontal Temperature differences
629 CALL grad(1,(ts(:,1)+ts(:,2))/2.,dtx,dty)
630 ! Meridional flux = -k.s (s=dyT/dzT)
631 ! Continent mask, multiply by dz/dy
632 fluxm=dty/dtz*500.*cuvsurcv*zmasqv
633 ! slope limitation, multiply by kappa
634 fluxm=-gmkappa*SIGN(MIN(ABS(fluxm),gm_smax*cv*cuvsurcv),dty)
635 ! convert to kg/s
636 fluxm(:)=fluxm(:)*sea_den
637 ! Zonal flux = 0. (temporary)
638 fluxz(:)=0.
639 ! Vertical mass flux from mass budget (divergence of horiz fluxes)
640 DO ij=iip2,ip1jm
641 fluxv_gm(ij)=fluxz(ij)-fluxz(ij-1)-fluxm(ij)+fluxm(ij-iip1)
642 ENDDO
643 DO ij=iip1,ip1jmi1,iip1
644 fluxv_gm(ij+1)=fluxv_gm(ij+iip1)
645 END DO
646 ! vertical mass flux at Poles
647 fluxv_gm(1)=-SUM(fluxm(1:iim))
648 fluxv_gm(ip1jmp1)=SUM(fluxm(ip1jm-iim:ip1jm-1))
649
650 ! Meridional heat fluxes
651 DO ij=1,ip1jm
652 ! centered scheme
653 fluxtm(ij,1)=fluxm(ij)*(ts(ij+iip1,1)+ts(ij,1))/2.
654 fluxtm(ij,2)=-fluxm(ij)*(ts(ij+iip1,2)+ts(ij,2))/2.
655 END DO
656
657 ! Zonal heat fluxes
658 ! Schema upstream
659 DO ij=iip2,ip1jm
660 IF (fluxz(ij).GE.0.) THEN
661 fluxtz(ij,1)=fluxz(ij)*ts(ij,1)
662 fluxtz(ij,2)=-fluxz(ij)*ts(ij+1,2)
663 ELSE
664 fluxtz(ij,1)=fluxz(ij)*ts(ij+1,1)
665 fluxtz(ij,2)=-fluxz(ij)*ts(ij,2)
666 ENDIF
667 ENDDO
668 DO ij=iip1*2,ip1jmp1,iip1
669 fluxtz(ij,:)=fluxtz(ij-iim,:)
670 END DO
671
672 ! Temperature tendency :
673 ! divergence of horizontal heat fluxes
674 DO ij=iip2,ip1jm
675 dt_gm(ij,:)=fluxtz(ij-1,:)-fluxtz(ij,:) &
676 +fluxtm(ij,:)-fluxtm(ij-iip1,:)
677 END DO
678 ! Poles
679 dt_gm(1,:)=SUM(fluxtm(1:iim,:),dim=1)
680 dt_gm(ip1jmp1,:)=-SUM(fluxtm(ip1jm-iim:ip1jm-1,:),dim=1)
681 ELSE
682 dt_gm(:,:)=0.
683 fluxv_gm(:)=0.
684 ENDIF ! slab_gm
685
686 ! ------------------------------------
687 ! Temp tendency from vertical advection
688 ! Divide by cell area
689 ! ------------------------------------
690 ! vertical heat flux = mass flux * T, upstream scheme
691 DO ij=iip2,ip1jm
692 fluxv=fluxv_ek(ij)+fluxv_gm(ij) ! net flux, needed for upstream scheme
693 IF (fluxv.GT.0.) THEN
694 dt_ek(ij,1)=dt_ek(ij,1)+fluxv_ek(ij)*ts(ij,2)
695 dt_ek(ij,2)=dt_ek(ij,2)-fluxv_ek(ij)*ts(ij,2)
696 dt_gm(ij,1)=dt_gm(ij,1)+fluxv_gm(ij)*ts(ij,2)
697 dt_gm(ij,2)=dt_gm(ij,2)-fluxv_gm(ij)*ts(ij,2)
698 ELSE
699 dt_ek(ij,1)=dt_ek(ij,1)+fluxv_ek(ij)*ts(ij,1)
700 dt_ek(ij,2)=dt_ek(ij,2)-fluxv_ek(ij)*ts(ij,1)
701 dt_gm(ij,1)=dt_gm(ij,1)+fluxv_gm(ij)*ts(ij,1)
702 dt_gm(ij,2)=dt_gm(ij,2)-fluxv_gm(ij)*ts(ij,1)
703 ENDIF
704 ! divide by cell area
705 dt_ek(ij,:)=dt_ek(ij,:)/aire(ij)
706 dt_gm(ij,:)=dt_gm(ij,:)/aire(ij)
707 END DO
708 ! North Pole
709 fluxv=fluxv_ek(1)+fluxv_gm(1)
710 IF (fluxv.GT.0.) THEN
711 dt_ek(1,1)=dt_ek(1,1)+fluxv_ek(1)*ts(1,2)
712 dt_ek(1,2)=dt_ek(1,2)-fluxv_ek(1)*ts(1,2)
713 dt_gm(1,1)=dt_gm(1,1)+fluxv_gm(1)*ts(1,2)
714 dt_gm(1,2)=dt_gm(1,2)-fluxv_gm(1)*ts(1,2)
715 ELSE
716 dt_ek(1,1)=dt_ek(1,1)+fluxv_ek(1)*ts(1,1)
717 dt_ek(1,2)=dt_ek(1,2)-fluxv_ek(1)*ts(1,1)
718 dt_gm(1,1)=dt_gm(1,1)+fluxv_gm(1)*ts(1,1)
719 dt_gm(1,2)=dt_gm(1,2)-fluxv_gm(1)*ts(1,1)
720 ENDIF
721 dt_ek(1,:)=dt_ek(1,:)/apoln
722 dt_gm(1,:)=dt_gm(1,:)/apoln
723 ! South pole
724 fluxv=fluxv_ek(ip1jmp1)+fluxv_gm(ip1jmp1)
725 IF (fluxv.GT.0.) THEN
726 dt_ek(ip1jmp1,1)=dt_ek(ip1jmp1,1)+fluxv_ek(ip1jmp1)*ts(ip1jmp1,2)
727 dt_ek(ip1jmp1,2)=dt_ek(ip1jmp1,2)-fluxv_ek(ip1jmp1)*ts(ip1jmp1,2)
728 dt_gm(ip1jmp1,1)=dt_gm(ip1jmp1,1)+fluxv_gm(ip1jmp1)*ts(ip1jmp1,2)
729 dt_gm(ip1jmp1,2)=dt_gm(ip1jmp1,2)-fluxv_gm(ip1jmp1)*ts(ip1jmp1,2)
730 ELSE
731 dt_ek(ip1jmp1,1)=dt_ek(ip1jmp1,1)+fluxv_ek(ip1jmp1)*ts(ip1jmp1,1)
732 dt_ek(ip1jmp1,2)=dt_ek(ip1jmp1,2)-fluxv_ek(ip1jmp1)*ts(ip1jmp1,1)
733 dt_gm(ip1jmp1,1)=dt_gm(ip1jmp1,1)+fluxv_gm(ip1jmp1)*ts(ip1jmp1,1)
734 dt_gm(ip1jmp1,2)=dt_gm(ip1jmp1,2)-fluxv_gm(ip1jmp1)*ts(ip1jmp1,1)
735 ENDIF
736 dt_ek(ip1jmp1,:)=dt_ek(ip1jmp1,:)/apols
737 dt_gm(ip1jmp1,:)=dt_gm(ip1jmp1,:)/apols
738
739 dt_ek(2:iip1,1)=dt_ek(1,1)
740 dt_ek(2:iip1,2)=dt_ek(1,2)
741 dt_gm(2:iip1,1)=dt_gm(1,1)
742 dt_gm(2:iip1,2)=dt_gm(1,2)
743 dt_ek(ip1jm+1:ip1jmp1,1)=dt_ek(ip1jmp1,1)
744 dt_ek(ip1jm+1:ip1jmp1,2)=dt_ek(ip1jmp1,2)
745 dt_gm(ip1jm+1:ip1jmp1,1)=dt_gm(ip1jmp1,1)
746 dt_gm(ip1jm+1:ip1jmp1,2)=dt_gm(ip1jmp1,2)
747
748 DO ij=iip1,ip1jmi1,iip1
749 dt_gm(ij+1,:)=dt_gm(ij+iip1,:)
750 dt_ek(ij+1,:)=dt_ek(ij+iip1,:)
751 END DO
752
753 ! T tendency back to 1D grid...
754 CALL gr_dyn_fi(2,iip1,jjp1,dt_ek,dt_phy_ek)
755 CALL gr_dyn_fi(2,iip1,jjp1,dt_gm,dt_phy_gm)
756
757 RETURN
758 END SUBROUTINE slab_ekman2
759
760 SUBROUTINE slab_gmdiff(ts_phy,dt_phy)
761 ! Temperature tendency for 2-layers slab ocean
762 ! Due to Gent-McWilliams type eddy-induced advection
763
764 IMPLICIT NONE
765
766 ! Here, temperature and flux variables are on 2 layers
767 INTEGER ij
768 ! Temperature gradient, v-points
769 REAL dty((nbp_lon+1)*(nbp_lat-1)),dtx((nbp_lon+1)*nbp_lat)
770 ! Vertical temperature difference, V-points
771 REAL dtz((nbp_lon+1)*(nbp_lat-1))
772 ! slab temperature on 1D, 2D grid
773 REAL ts_phy(klon_glo,2),ts((nbp_lon+1)*nbp_lat,2)
774 ! zonal and meridional mass fluxes at u, v points (2D grid)
775 REAL fluxz((nbp_lon+1)*nbp_lat), fluxm((nbp_lon+1)*(nbp_lat-1))
776 ! vertical mass flux between the 2 layers
777 REAL fluxv((nbp_lon+1)*nbp_lat)
778 ! zonal and meridional heat fluxes
779 REAL fluxtz((nbp_lon+1)*nbp_lat,2)
780 REAL fluxtm((nbp_lon+1)*(nbp_lat-1),2)
781 ! temperature tendency (in K.s-1.kg.m-2)
782 REAL dt((nbp_lon+1)*nbp_lat,2), dt_phy(klon_glo,2)
783
784 INTEGER iim,iip1,iip2,jjp1,ip1jm,ip1jmi1,ip1jmp1
785
786 ! Grid definitions
787 iim=nbp_lon
788 iip1=nbp_lon+1
789 iip2=nbp_lon+2
790 jjp1=nbp_lat
791 ip1jm=(nbp_lon+1)*(nbp_lat-1) ! = iip1*jjm
792 ip1jmi1=(nbp_lon+1)*(nbp_lat-1)-(nbp_lon+1) ! = ip1jm - iip1
793 ip1jmp1=(nbp_lon+1)*nbp_lat ! = iip1*jjp1
794
795 ! Convert temperature to 2D grid
796 CALL gr_fi_dyn(2,iip1,jjp1,ts_phy,ts)
797 ! Vertical Temperature difference T1-T2 on v-grid points
798 CALL gr_scal_v(1,ts(:,1)-ts(:,2),dtz)
799 dtz(:)=MAX(dtz(:),0.25)
800 ! Horizontal Temperature differences
801 CALL grad(1,(ts(:,1)+ts(:,2))/2.,dtx,dty)
802 ! Meridional flux = -k.s (s=dyT/dzT)
803 ! Continent mask, multiply by dz/dy
804 fluxm=dty/dtz*500.*cuvsurcv*zmasqv
805 ! slope limitation, multiply by kappa
806 fluxm=-gmkappa*SIGN(MIN(ABS(fluxm),gm_smax*cv*cuvsurcv),dty)
807 ! Zonal flux = 0. (temporary)
808 fluxz(:)=0.
809 ! Vertical mass flux from mass budget (divergence of horiz fluxes)
810 DO ij=iip2,ip1jm
811 fluxv(ij)=fluxz(ij)-fluxz(ij-1)-fluxm(ij)+fluxm(ij-iip1)
812 ENDDO
813 DO ij=iip1,ip1jmi1,iip1
814 fluxv(ij+1)=fluxv(ij+iip1)
815 END DO
816 ! vertical mass flux at Poles
817 fluxv(1)=-SUM(fluxm(1:iim))
818 fluxv(ip1jmp1)=SUM(fluxm(ip1jm-iim:ip1jm-1))
819 fluxv=fluxv
820
821 ! Meridional heat fluxes
822 DO ij=1,ip1jm
823 ! centered scheme
824 fluxtm(ij,1)=fluxm(ij)*(ts(ij+iip1,1)+ts(ij,1))/2.
825 fluxtm(ij,2)=-fluxm(ij)*(ts(ij+iip1,2)+ts(ij,2))/2.
826 END DO
827
828 ! Zonal heat fluxes
829 ! Schema upstream
830 DO ij=iip2,ip1jm
831 IF (fluxz(ij).GE.0.) THEN
832 fluxtz(ij,1)=fluxz(ij)*ts(ij,1)
833 fluxtz(ij,2)=-fluxz(ij)*ts(ij+1,2)
834 ELSE
835 fluxtz(ij,1)=fluxz(ij)*ts(ij+1,1)
836 fluxtz(ij,2)=-fluxz(ij)*ts(ij,2)
837 ENDIF
838 ENDDO
839 DO ij=iip1*2,ip1jmp1,iip1
840 fluxtz(ij,:)=fluxtz(ij-iim,:)
841 END DO
842
843 ! Temperature tendency :
844 DO ij=iip2,ip1jm
845 ! divergence of horizontal heat fluxes
846 dt(ij,:)=fluxtz(ij-1,:)-fluxtz(ij,:) &
847 +fluxtm(ij,:)-fluxtm(ij-iip1,:)
848 ! + vertical heat flux (mass flux * T, upstream scheme)
849 IF (fluxv(ij).GT.0.) THEN
850 dt(ij,1)=dt(ij,1)+fluxv(ij)*ts(ij,2)
851 dt(ij,2)=dt(ij,2)-fluxv(ij)*ts(ij,2)
852 ELSE
853 dt(ij,1)=dt(ij,1)+fluxv(ij)*ts(ij,1)
854 dt(ij,2)=dt(ij,2)-fluxv(ij)*ts(ij,1)
855 ENDIF
856 ! divide by cell area
857 dt(ij,:)=dt(ij,:)/aire(ij)
858 END DO
859 DO ij=iip1,ip1jmi1,iip1
860 dt(ij+1,:)=dt(ij+iip1,:)
861 END DO
862 ! Poles
863 dt(1,:)=SUM(fluxtm(1:iim,:),dim=1)
864 IF (fluxv(1).GT.0.) THEN
865 dt(1,1)=dt(1,1)+fluxv(1)*ts(1,2)
866 dt(1,2)=dt(1,2)-fluxv(1)*ts(1,2)
867 ELSE
868 dt(1,1)=dt(1,1)+fluxv(1)*ts(1,1)
869 dt(1,2)=dt(1,2)-fluxv(1)*ts(1,1)
870 ENDIF
871 dt(1,:)=dt(1,:)/apoln
872 dt(ip1jmp1,:)=-SUM(fluxtm(ip1jm-iim:ip1jm-1,:),dim=1)
873 IF (fluxv(ip1jmp1).GT.0.) THEN
874 dt(ip1jmp1,1)=dt(ip1jmp1,1)+fluxv(ip1jmp1)*ts(ip1jmp1,2)
875 dt(ip1jmp1,2)=dt(ip1jmp1,2)-fluxv(ip1jmp1)*ts(ip1jmp1,2)
876 ELSE
877 dt(ip1jmp1,1)=dt(ip1jmp1,1)+fluxv(ip1jmp1)*ts(ip1jmp1,1)
878 dt(ip1jmp1,2)=dt(ip1jmp1,2)-fluxv(ip1jmp1)*ts(ip1jmp1,1)
879 ENDIF
880 dt(ip1jmp1,:)=dt(ip1jmp1,:)/apols
881 dt(2:iip1,1)=dt(1,1)
882 dt(2:iip1,2)=dt(1,2)
883 dt(ip1jm+1:ip1jmp1,1)=dt(ip1jmp1,1)
884 dt(ip1jm+1:ip1jmp1,2)=dt(ip1jmp1,2)
885
886 ! T tendency back to 1D grid...
887 CALL gr_dyn_fi(2,iip1,jjp1,dt,dt_phy)
888
889 RETURN
890 END SUBROUTINE slab_gmdiff
891
892 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
893
894 SUBROUTINE gr_fi_dyn(nfield,im,jm,pfi,pdyn)
895 ! Transfer a variable from 1D "physics" grid to 2D "dynamics" grid
896 IMPLICIT NONE
897
898 INTEGER,INTENT(IN) :: im,jm,nfield
899 REAL,INTENT(IN) :: pfi(klon_glo,nfield) ! on 1D grid
900 REAL,INTENT(OUT) :: pdyn(im,jm,nfield) ! on 2D grid
901
902 INTEGER :: i,j,ifield,ig
903
904 DO ifield=1,nfield
905 ! Handle poles
906 DO i=1,im
907 pdyn(i,1,ifield)=pfi(1,ifield)
908 pdyn(i,jm,ifield)=pfi(klon_glo,ifield)
909 ENDDO
910 ! Other points
911 DO j=2,jm-1
912 ig=2+(j-2)*(im-1)
913 CALL SCOPY(im-1,pfi(ig,ifield),1,pdyn(1,j,ifield),1)
914 pdyn(im,j,ifield)=pdyn(1,j,ifield)
915 ENDDO
916 ENDDO ! of DO ifield=1,nfield
917
918 END SUBROUTINE gr_fi_dyn
919
920 SUBROUTINE gr_dyn_fi(nfield,im,jm,pdyn,pfi)
921 ! Transfer a variable from 2D "dynamics" grid to 1D "physics" grid
922 IMPLICIT NONE
923
924 INTEGER,INTENT(IN) :: im,jm,nfield
925 REAL,INTENT(IN) :: pdyn(im,jm,nfield) ! on 2D grid
926 REAL,INTENT(OUT) :: pfi(klon_glo,nfield) ! on 1D grid
927
928 INTEGER j,ifield,ig
929
930 CHARACTER (len = 20) :: modname = 'slab_heat_transp'
931 CHARACTER (len = 80) :: abort_message
932
933 ! Sanity check:
934 IF(klon_glo.NE.2+(jm-2)*(im-1)) THEN
935 abort_message="gr_dyn_fi error, wrong sizes"
936 CALL abort_physic(modname,abort_message,1)
937 ENDIF
938
939 ! Handle poles
940 CALL SCOPY(nfield,pdyn,im*jm,pfi,klon_glo)
941 CALL SCOPY(nfield,pdyn(1,jm,1),im*jm,pfi(klon_glo,1),klon_glo)
942 ! Other points
943 DO ifield=1,nfield
944 DO j=2,jm-1
945 ig=2+(j-2)*(im-1)
946 CALL SCOPY(im-1,pdyn(1,j,ifield),1,pfi(ig,ifield),1)
947 ENDDO
948 ENDDO
949
950 END SUBROUTINE gr_dyn_fi
951
952 SUBROUTINE grad(klevel,pg,pgx,pgy)
953 ! compute the covariant components pgx,pgy of the gradient of pg
954 ! pgx = d(pg)/dx * delta(x) = delta(pg)
955 IMPLICIT NONE
956
957 INTEGER,INTENT(IN) :: klevel
958 REAL,INTENT(IN) :: pg((nbp_lon+1)*nbp_lat,klevel)
959 REAL,INTENT(OUT) :: pgx((nbp_lon+1)*nbp_lat,klevel)
960 REAL,INTENT(OUT) :: pgy((nbp_lon+1)*(nbp_lat-1),klevel)
961
962 INTEGER :: l,ij
963 INTEGER :: iim,iip1,ip1jm,ip1jmp1
964
965 iim=nbp_lon
966 iip1=nbp_lon+1
967 ip1jm=(nbp_lon+1)*(nbp_lat-1) ! = iip1*jjm
968 ip1jmp1=(nbp_lon+1)*nbp_lat ! = iip1*jjp1
969
970 DO l=1,klevel
971 DO ij=1,ip1jmp1-1
972 pgx(ij,l)=pg(ij+1,l)-pg(ij,l)
973 ENDDO
974 ! correction for pgx(ip1,j,l) ...
975 ! ... pgx(iip1,j,l)=pgx(1,j,l) ...
976 DO ij=iip1,ip1jmp1,iip1
977 pgx(ij,l)=pgx(ij-iim,l)
978 ENDDO
979 DO ij=1,ip1jm
980 pgy(ij,l)=pg(ij,l)-pg(ij+iip1,l)
981 ENDDO
982 ENDDO
983
984 END SUBROUTINE grad
985
986 SUBROUTINE diverg(klevel,x,y,div)
987 ! computes the divergence of a vector field of components
988 ! x,y. x and y being covariant components
989 IMPLICIT NONE
990
991 INTEGER,INTENT(IN) :: klevel
992 REAL,INTENT(IN) :: x((nbp_lon+1)*nbp_lat,klevel)
993 REAL,INTENT(IN) :: y((nbp_lon+1)*(nbp_lat-1),klevel)
994 REAL,INTENT(OUT) :: div((nbp_lon+1)*nbp_lat,klevel)
995
996 INTEGER :: l,ij
997 INTEGER :: iim,iip1,iip2,ip1jm,ip1jmp1,ip1jmi1
998
999 REAL :: aiy1(nbp_lon+1),aiy2(nbp_lon+1)
1000 REAL :: sumypn,sumyps
1001 REAL,EXTERNAL :: SSUM
1002
1003 iim=nbp_lon
1004 iip1=nbp_lon+1
1005 iip2=nbp_lon+2
1006 ip1jm=(nbp_lon+1)*(nbp_lat-1) ! = iip1*jjm
1007 ip1jmp1=(nbp_lon+1)*nbp_lat ! = iip1*jjp1
1008 ip1jmi1=(nbp_lon+1)*(nbp_lat-1)-(nbp_lon+1) ! = ip1jm - iip1
1009
1010 DO l=1,klevel
1011 DO ij=iip2,ip1jm-1
1012 div(ij+1,l)= &
1013 cvusurcu(ij+1)*x(ij+1,l)-cvusurcu(ij)*x(ij,l)+ &
1014 cuvsurcv(ij-iim)*y(ij-iim,l)-cuvsurcv(ij+1)*y(ij+1,l)
1015 ENDDO
1016 ! correction for div(1,j,l) ...
1017 ! ... div(1,j,l)= div(iip1,j,l) ...
1018 DO ij=iip2,ip1jm,iip1
1019 div(ij,l)=div(ij+iim,l)
1020 ENDDO
1021 ! at the poles
1022 DO ij=1,iim
1023 aiy1(ij)=cuvsurcv(ij)*y(ij,l)
1024 aiy2(ij)=cuvsurcv(ij+ip1jmi1)*y(ij+ip1jmi1,l)
1025 ENDDO
1026 sumypn=SSUM(iim,aiy1,1)/apoln
1027 sumyps=SSUM(iim,aiy2,1)/apols
1028 DO ij=1,iip1
1029 div(ij,l)=-sumypn
1030 div(ij+ip1jm,l)=sumyps
1031 ENDDO
1032 ! End (poles)
1033 ENDDO ! of DO l=1,klevel
1034
1035 !!! CALL filtreg( div, jjp1, klevel, 2, 2, .TRUE., 1 )
1036 DO l=1,klevel
1037 DO ij=iip2,ip1jm
1038 div(ij,l)=div(ij,l)*unsaire(ij)
1039 ENDDO
1040 ENDDO
1041
1042 END SUBROUTINE diverg
1043
1044 SUBROUTINE gr_v_scal(nx,x_v,x_scal)
1045 ! convert values from v points to scalar points on C-grid
1046 ! used to compute unsfu, unseu (u points, but depends only on latitude)
1047 IMPLICIT NONE
1048
1049 INTEGER,INTENT(IN) :: nx ! number of levels or fields
1050 REAL,INTENT(IN) :: x_v((nbp_lon+1)*(nbp_lat-1),nx)
1051 REAL,INTENT(OUT) :: x_scal((nbp_lon+1)*nbp_lat,nx)
1052
1053 INTEGER :: l,ij
1054 INTEGER :: iip1,iip2,ip1jm,ip1jmp1
1055
1056 iip1=nbp_lon+1
1057 iip2=nbp_lon+2
1058 ip1jm=(nbp_lon+1)*(nbp_lat-1) ! = iip1*jjm
1059 ip1jmp1=(nbp_lon+1)*nbp_lat ! = iip1*jjp1
1060
1061 DO l=1,nx
1062 DO ij=iip2,ip1jm
1063 x_scal(ij,l)= &
1064 (airev(ij-iip1)*x_v(ij-iip1,l)+airev(ij)*x_v(ij,l)) &
1065 /(airev(ij-iip1)+airev(ij))
1066 ENDDO
1067 DO ij=1,iip1
1068 x_scal(ij,l)=0.
1069 ENDDO
1070 DO ij=ip1jm+1,ip1jmp1
1071 x_scal(ij,l)=0.
1072 ENDDO
1073 ENDDO
1074
1075 END SUBROUTINE gr_v_scal
1076
1077 SUBROUTINE gr_scal_v(nx,x_scal,x_v)
1078 ! convert values from scalar points to v points on C-grid
1079 ! used to compute wind stress at V points
1080 IMPLICIT NONE
1081
1082 INTEGER,INTENT(IN) :: nx ! number of levels or fields
1083 REAL,INTENT(OUT) :: x_v((nbp_lon+1)*(nbp_lat-1),nx)
1084 REAL,INTENT(IN) :: x_scal((nbp_lon+1)*nbp_lat,nx)
1085
1086 INTEGER :: l,ij
1087 INTEGER :: iip1,ip1jm
1088
1089 iip1=nbp_lon+1
1090 ip1jm=(nbp_lon+1)*(nbp_lat-1) ! = iip1*jjm
1091
1092 DO l=1,nx
1093 DO ij=1,ip1jm
1094 x_v(ij,l)= &
1095 (cu(ij)*cvusurcu(ij)*x_scal(ij,l)+ &
1096 cu(ij+iip1)*cvusurcu(ij+iip1)*x_scal(ij+iip1,l)) &
1097 /(cu(ij)*cvusurcu(ij)+cu(ij+iip1)*cvusurcu(ij+iip1))
1098 ENDDO
1099 ENDDO
1100
1101 END SUBROUTINE gr_scal_v
1102
1103 SUBROUTINE gr_scal_u(nx,x_scal,x_u)
1104 ! convert values from scalar points to U points on C-grid
1105 ! used to compute wind stress at U points
1106 IMPLICIT NONE
1107
1108 INTEGER,INTENT(IN) :: nx
1109 REAL,INTENT(OUT) :: x_u((nbp_lon+1)*nbp_lat,nx)
1110 REAL,INTENT(IN) :: x_scal((nbp_lon+1)*nbp_lat,nx)
1111
1112 INTEGER :: l,ij
1113 INTEGER :: iip1,jjp1,ip1jmp1
1114
1115 iip1=nbp_lon+1
1116 jjp1=nbp_lat
1117 ip1jmp1=(nbp_lon+1)*nbp_lat ! = iip1*jjp1
1118
1119 DO l=1,nx
1120 DO ij=1,ip1jmp1-1
1121 x_u(ij,l)= &
1122 (aire(ij)*x_scal(ij,l)+aire(ij+1)*x_scal(ij+1,l)) &
1123 /(aire(ij)+aire(ij+1))
1124 ENDDO
1125 ENDDO
1126
1127 CALL SCOPY(nx*jjp1,x_u(1,1),iip1,x_u(iip1,1),iip1)
1128
1129 END SUBROUTINE gr_scal_u
1130
1131 END MODULE slab_heat_transp_mod
1132