source: codes/icosagcm/devel/src/dynamics/caldyn_kernels_base.F90 @ 562

Last change on this file since 562 was 562, checked in by dubos, 7 years ago

devel : per-kernel activation of macro-generated code

File size: 13.3 KB
Line 
1MODULE caldyn_kernels_base_mod
2  USE icosa
3  USE transfert_mod
4  USE disvert_mod
5  USE omp_para
6  USE trace
7  IMPLICIT NONE
8  PRIVATE
9
10  INTEGER, PARAMETER,PUBLIC :: energy=1, enstrophy=2
11  TYPE(t_field),POINTER,PUBLIC :: f_out_u(:), f_qu(:), f_qv(:)
12  REAL(rstd),SAVE,POINTER :: out_u(:,:), p(:,:), qu(:,:)
13  !$OMP THREADPRIVATE(out_u, p, qu)
14
15  ! temporary shared variables for caldyn
16  TYPE(t_field),POINTER,PUBLIC :: f_pk(:),f_wwuu(:),f_planetvel(:), &
17                                  f_Fel(:), f_gradPhi2(:), f_wil(:), f_Wetadot(:)
18
19  INTEGER, PUBLIC :: caldyn_conserv
20  !$OMP THREADPRIVATE(caldyn_conserv)
21
22  TYPE(t_message),PUBLIC :: req_ps, req_mass, req_theta_rhodz, req_u, req_qu, req_geopot, req_w
23
24  PUBLIC :: compute_geopot, compute_caldyn_vert, compute_caldyn_vert_nh
25
26CONTAINS
27
28  !**************************** Geopotential *****************************
29
30  SUBROUTINE compute_geopot(rhodz,theta, ps,pk,geopot) 
31    REAL(rstd),INTENT(IN)    :: rhodz(iim*jjm,llm)
32    REAL(rstd),INTENT(IN)    :: theta(iim*jjm,llm,nqdyn) ! active scalars : theta/entropy, moisture, ...
33    REAL(rstd),INTENT(INOUT) :: ps(iim*jjm)
34    REAL(rstd),INTENT(OUT)   :: pk(iim*jjm,llm)       ! Exner function (compressible) /Lagrange multiplier (Boussinesq)
35    REAL(rstd),INTENT(INOUT) :: geopot(iim*jjm,llm+1) ! geopotential
36
37    INTEGER :: i,j,ij,l
38    REAL(rstd) :: Rd, p_ik, exner_ik, temp_ik, qv, chi, Rmix, gv
39    INTEGER    :: ij_omp_begin_ext, ij_omp_end_ext
40
41    CALL trace_start("compute_geopot")
42
43!$OMP BARRIER
44
45    CALL distrib_level(ij_end_ext-ij_begin_ext+1,ij_omp_begin_ext,ij_omp_end_ext)
46    ij_omp_begin_ext=ij_omp_begin_ext+ij_begin_ext-1
47    ij_omp_end_ext=ij_omp_end_ext+ij_begin_ext-1
48
49    Rd = kappa*cpp
50
51    IF(dysl_geopot) THEN
52#ifdef CPP_DYSL
53#include "../kernels/compute_geopot.k90"
54#else
55    STOP 'dysl_geopot=.TRUE. but DYNAMICO has been compiled without the -dysl option'
56#endif
57    ELSE
58    ! Pressure is computed first top-down (temporarily stored in pk)
59    ! Then Exner pressure and geopotential are computed bottom-up
60    ! Works also when caldyn_eta=eta_mass         
61
62    IF(boussinesq) THEN ! compute geopotential and pk=Lagrange multiplier
63       ! specific volume 1 = dphi/g/rhodz
64       !         IF (is_omp_level_master) THEN ! no openMP on vertical due to dependency
65       DO l = 1,llm
66          !DIR$ SIMD
67          DO ij=ij_omp_begin_ext,ij_omp_end_ext         
68             geopot(ij,l+1) = geopot(ij,l) + g*rhodz(ij,l)
69          ENDDO
70       ENDDO
71       ! use hydrostatic balance with theta*rhodz to find pk (Lagrange multiplier=pressure)
72       ! uppermost layer
73       !DIR$ SIMD
74       DO ij=ij_begin_ext,ij_end_ext         
75          pk(ij,llm) = ptop + (.5*g)*theta(ij,llm,1)*rhodz(ij,llm)
76       END DO
77       ! other layers
78       DO l = llm-1, 1, -1
79          !          !$OMP DO SCHEDULE(STATIC)
80          !DIR$ SIMD
81          DO ij=ij_begin_ext,ij_end_ext         
82             pk(ij,l) = pk(ij,l+1) + (.5*g)*(theta(ij,l,1)*rhodz(ij,l)+theta(ij,l+1,1)*rhodz(ij,l+1))
83          END DO
84       END DO
85       ! now pk contains the Lagrange multiplier (pressure)
86    ELSE ! non-Boussinesq, compute pressure, Exner pressure or temperature, then geopotential
87       ! uppermost layer
88       
89       SELECT CASE(caldyn_thermo)
90          CASE(thermo_theta, thermo_entropy)
91             !DIR$ SIMD
92             DO ij=ij_omp_begin_ext,ij_omp_end_ext
93                pk(ij,llm) = ptop + (.5*g)*rhodz(ij,llm)
94             END DO
95             ! other layers
96             DO l = llm-1, 1, -1
97                !DIR$ SIMD
98                DO ij=ij_omp_begin_ext,ij_omp_end_ext         
99                   pk(ij,l) = pk(ij,l+1) + (.5*g)*(rhodz(ij,l)+rhodz(ij,l+1))
100                END DO
101             END DO
102             ! surface pressure (for diagnostics)
103             IF(caldyn_eta==eta_lag) THEN
104                DO ij=ij_omp_begin_ext,ij_omp_end_ext         
105                   ps(ij) = pk(ij,1) + (.5*g)*rhodz(ij,1)
106                END DO
107             END IF
108          CASE(thermo_moist) ! theta(ij,l,2) = qv = mv/md
109             !DIR$ SIMD
110             DO ij=ij_omp_begin_ext,ij_omp_end_ext
111                pk(ij,llm) = ptop + (.5*g)*rhodz(ij,llm)*(1.+theta(ij,l,2))
112             END DO
113             ! other layers
114             DO l = llm-1, 1, -1
115                !DIR$ SIMD
116                DO ij=ij_omp_begin_ext,ij_omp_end_ext         
117                   pk(ij,l) = pk(ij,l+1) + (.5*g)*(          &
118                        rhodz(ij,l)  *(1.+theta(ij,l,2)) +   &
119                        rhodz(ij,l+1)*(1.+theta(ij,l+1,2)) )
120                END DO
121             END DO
122             ! surface pressure (for diagnostics)
123             IF(caldyn_eta==eta_lag) THEN
124                DO ij=ij_omp_begin_ext,ij_omp_end_ext         
125                   ps(ij) = pk(ij,1) + (.5*g)*rhodz(ij,1)*(1.+theta(ij,l,2))
126                END DO
127             END IF
128          END SELECT
129
130       DO l = 1,llm
131          SELECT CASE(caldyn_thermo)
132          CASE(thermo_theta)
133             !DIR$ SIMD
134             DO ij=ij_omp_begin_ext,ij_omp_end_ext
135                p_ik = pk(ij,l)
136                exner_ik = cpp * (p_ik/preff) ** kappa
137                pk(ij,l) = exner_ik
138                ! specific volume v = kappa*theta*pi/p = dphi/g/rhodz
139                geopot(ij,l+1) = geopot(ij,l) + (g*kappa)*rhodz(ij,l)*theta(ij,l,1)*exner_ik/p_ik
140             ENDDO
141          CASE(thermo_entropy) ! theta is in fact entropy = cpp*log(theta/Treff) = cpp*log(T/Treff) - Rd*log(p/preff)
142             !DIR$ SIMD
143             DO ij=ij_omp_begin_ext,ij_omp_end_ext
144                p_ik = pk(ij,l)
145                temp_ik = Treff*exp((theta(ij,l,1) + Rd*log(p_ik/preff))/cpp)
146                pk(ij,l) = temp_ik
147                ! specific volume v = Rd*T/p = dphi/g/rhodz
148                geopot(ij,l+1) = geopot(ij,l) + (g*Rd)*rhodz(ij,l)*temp_ik/p_ik
149             ENDDO
150          CASE(thermo_moist) ! theta is moist pseudo-entropy per dry air mass
151             DO ij=ij_omp_begin_ext,ij_omp_end_ext
152                p_ik = pk(ij,l)
153                qv = theta(ij,l,2) ! water vaper mixing ratio = mv/md
154                Rmix = Rd+qv*Rv
155                chi = ( theta(ij,l,1) + Rmix*log(p_ik/preff) ) / (cpp + qv*cppv) ! log(T/Treff)
156                temp_ik = Treff*exp(chi)
157                pk(ij,l) = temp_ik
158                ! specific volume v = R*T/p = dphi/g/rhodz
159                ! R = (Rd + qv.Rv)/(1+qv)
160                geopot(ij,l+1) = geopot(ij,l) + g*Rmix*rhodz(ij,l)*temp_ik/(p_ik*(1+qv))
161             ENDDO
162          CASE DEFAULT
163             STOP
164          END SELECT
165       ENDDO
166    END IF
167
168    END IF ! dysl
169
170    !ym flush geopot
171    !$OMP BARRIER
172
173    CALL trace_end("compute_geopot")
174
175  END SUBROUTINE compute_geopot
176
177  SUBROUTINE compute_caldyn_vert(u,theta,rhodz,convm, wflux,wwuu, dps,dtheta_rhodz,du)
178    REAL(rstd),INTENT(IN)  :: u(iim*3*jjm,llm)
179    REAL(rstd),INTENT(IN)  :: theta(iim*jjm,llm,nqdyn)
180    REAL(rstd),INTENT(IN)  :: rhodz(iim*jjm,llm)
181    REAL(rstd),INTENT(INOUT)  :: convm(iim*jjm,llm)  ! mass flux convergence
182
183    REAL(rstd),INTENT(INOUT) :: wflux(iim*jjm,llm+1) ! vertical mass flux (kg/m2/s)
184    REAL(rstd),INTENT(INOUT) :: wwuu(iim*3*jjm,llm+1)
185    REAL(rstd),INTENT(INOUT) :: du(iim*3*jjm,llm)
186    REAL(rstd),INTENT(INOUT) :: dtheta_rhodz(iim*jjm,llm,nqdyn)
187    REAL(rstd),INTENT(OUT) :: dps(iim*jjm)
188
189    ! temporary variable   
190    INTEGER :: i,j,ij,l,iq
191    REAL(rstd) :: p_ik, exner_ik
192    INTEGER    :: ij_omp_begin, ij_omp_end
193
194    CALL trace_start("compute_caldyn_vert")
195
196    CALL distrib_level(ij_end-ij_begin+1,ij_omp_begin,ij_omp_end)
197    ij_omp_begin=ij_omp_begin+ij_begin-1
198    ij_omp_end=ij_omp_end+ij_begin-1
199
200    !    REAL(rstd) :: wwuu(iim*3*jjm,llm+1) ! tmp var, don't know why but gain 30% on the whole code in opemp
201    ! need to be understood
202
203    !    wwuu=wwuu_out
204    CALL trace_start("compute_caldyn_vert")
205
206    !$OMP BARRIER   
207!!! cumulate mass flux convergence from top to bottom
208    !  IF (is_omp_level_master) THEN
209    DO  l = llm-1, 1, -1
210       !    IF (caldyn_conserv==energy) CALL test_message(req_qu)
211
212!!$OMP DO SCHEDULE(STATIC)
213       !DIR$ SIMD
214       DO ij=ij_omp_begin,ij_omp_end         
215          convm(ij,l) = convm(ij,l) + convm(ij,l+1)
216       ENDDO
217    ENDDO
218    !  ENDIF
219
220    !$OMP BARRIER
221    ! FLUSH on convm
222!!!!!!!!!!!!!!!!!!!!!!!!!
223
224    ! compute dps
225    IF (is_omp_first_level) THEN
226       !DIR$ SIMD
227       DO ij=ij_begin,ij_end         
228          ! dps/dt = -int(div flux)dz
229          dps(ij) = convm(ij,1)
230       ENDDO
231    ENDIF
232
233!!! Compute vertical mass flux (l=1,llm+1 done by caldyn_BC)
234    DO l=ll_beginp1,ll_end
235       !    IF (caldyn_conserv==energy) CALL test_message(req_qu)
236       !DIR$ SIMD
237       DO ij=ij_begin,ij_end         
238          ! w = int(z,ztop,div(flux)dz) + B(eta)dps/dt
239          ! => w>0 for upward transport
240          wflux( ij, l ) = bp(l) * convm( ij, 1 ) - convm( ij, l ) 
241       ENDDO
242    ENDDO
243
244    !--> flush wflux 
245    !$OMP BARRIER
246
247    DO iq=1,nqdyn
248       DO l=ll_begin,ll_endm1
249       !DIR$ SIMD
250          DO ij=ij_begin,ij_end         
251             dtheta_rhodz(ij, l, iq) = dtheta_rhodz(ij, l, iq)  -   0.5 * &
252                  ( wflux(ij,l+1) * (theta(ij,l,iq) + theta(ij,l+1,iq)))
253          END DO
254       END DO
255       DO l=ll_beginp1,ll_end
256          !DIR$ SIMD
257          DO ij=ij_begin,ij_end         
258             dtheta_rhodz(ij, l, iq) = dtheta_rhodz(ij, l, iq)  +   0.5 * &
259                  ( wflux(ij,l) * (theta(ij,l-1,iq) + theta(ij,l,iq) ) )
260          END DO
261       END DO
262    END DO
263
264    ! Compute vertical transport
265    DO l=ll_beginp1,ll_end
266       !DIR$ SIMD
267       DO ij=ij_begin,ij_end         
268          wwuu(ij+u_right,l) = 0.5*( wflux(ij,l) + wflux(ij+t_right,l)) * (u(ij+u_right,l) - u(ij+u_right,l-1))
269          wwuu(ij+u_lup,l) = 0.5* ( wflux(ij,l) + wflux(ij+t_lup,l)) * (u(ij+u_lup,l) - u(ij+u_lup,l-1))
270          wwuu(ij+u_ldown,l) = 0.5*( wflux(ij,l) + wflux(ij+t_ldown,l)) * (u(ij+u_ldown,l) - u(ij+u_ldown,l-1))
271       ENDDO
272    ENDDO
273
274    !--> flush wwuu 
275    !$OMP BARRIER
276
277    ! Add vertical transport to du
278    DO l=ll_begin,ll_end
279       !DIR$ SIMD
280       DO ij=ij_begin,ij_end         
281          du(ij+u_right, l )   = du(ij+u_right,l)  - (wwuu(ij+u_right,l+1)+ wwuu(ij+u_right,l)) / (rhodz(ij,l)+rhodz(ij+t_right,l))
282          du(ij+u_lup, l )     = du(ij+u_lup,l)    - (wwuu(ij+u_lup,l+1)  + wwuu(ij+u_lup,l))   / (rhodz(ij,l)+rhodz(ij+t_lup,l))
283          du(ij+u_ldown, l )   = du(ij+u_ldown,l)  - (wwuu(ij+u_ldown,l+1)+ wwuu(ij+u_ldown,l)) / (rhodz(ij,l)+rhodz(ij+t_ldown,l))
284       ENDDO
285    ENDDO
286
287    !  DO l=ll_beginp1,ll_end
288    !!DIR$ SIMD
289    !      DO ij=ij_begin,ij_end         
290    !        wwuu_out(ij+u_right,l) = wwuu(ij+u_right,l)
291    !        wwuu_out(ij+u_lup,l)   = wwuu(ij+u_lup,l)
292    !        wwuu_out(ij+u_ldown,l) = wwuu(ij+u_ldown,l)
293    !     ENDDO
294    !   ENDDO
295
296    CALL trace_end("compute_caldyn_vert")
297
298  END SUBROUTINE compute_caldyn_vert
299
300  SUBROUTINE compute_caldyn_vert_NH(mass,geopot,W,wflux, W_etadot, du,dPhi,dW)
301    REAL(rstd),INTENT(IN) :: mass(iim*jjm,llm)
302    REAL(rstd),INTENT(IN) :: geopot(iim*jjm,llm+1)
303    REAL(rstd),INTENT(IN) :: W(iim*jjm,llm+1)
304    REAL(rstd),INTENT(IN) :: wflux(iim*jjm,llm+1)
305    REAL(rstd),INTENT(INOUT) :: du(iim*3*jjm,llm)
306    REAL(rstd),INTENT(INOUT) :: dPhi(iim*jjm,llm+1)
307    REAL(rstd),INTENT(INOUT) :: dW(iim*jjm,llm+1)
308    REAL(rstd) :: W_etadot(iim*jjm,llm) ! vertical flux of vertical momentum
309    ! local arrays
310    REAL(rstd) :: eta_dot(iim*jjm, llm) ! eta_dot in full layers
311    REAL(rstd) :: wcov(iim*jjm,llm) ! covariant vertical momentum in full layers
312    ! indices and temporary values
313    INTEGER    :: ij, l
314    REAL(rstd) :: wflux_ij, w_ij
315
316    CALL trace_start("compute_caldyn_vert_nh")
317
318#ifdef CPP_DYSL
319!$OMP BARRIER
320#include "../kernels/caldyn_vert_NH.k90"
321!$OMP BARRIER
322#else
323#define ETA_DOT(ij) eta_dot(ij,1)
324#define WCOV(ij) wcov(ij,1)
325
326    DO l=ll_begin,ll_end
327       ! compute the local arrays
328       !DIR$ SIMD
329       DO ij=ij_begin_ext,ij_end_ext
330          wflux_ij = .5*(wflux(ij,l)+wflux(ij,l+1))
331          w_ij = .5*(W(ij,l)+W(ij,l+1))/mass(ij,l)
332          W_etadot(ij,l) = wflux_ij*w_ij
333          ETA_DOT(ij) = wflux_ij / mass(ij,l)
334          WCOV(ij) = w_ij*(geopot(ij,l+1)-geopot(ij,l))
335       ENDDO
336       ! add NH term to du
337      !DIR$ SIMD
338      DO ij=ij_begin,ij_end
339          du(ij+u_right,l) = du(ij+u_right,l) &
340               - .5*(WCOV(ij+t_right)+WCOV(ij)) &
341               *ne_right*(ETA_DOT(ij+t_right)-ETA_DOT(ij))
342          du(ij+u_lup,l) = du(ij+u_lup,l) &
343               - .5*(WCOV(ij+t_lup)+WCOV(ij)) &
344               *ne_lup*(ETA_DOT(ij+t_lup)-ETA_DOT(ij))
345          du(ij+u_ldown,l) = du(ij+u_ldown,l) &
346               - .5*(WCOV(ij+t_ldown)+WCOV(ij)) &
347               *ne_ldown*(ETA_DOT(ij+t_ldown)-ETA_DOT(ij))
348       END DO
349    ENDDO
350    ! add NH terms to dW, dPhi
351    ! FIXME : TODO top and bottom
352    DO l=ll_beginp1,ll_end ! inner interfaces only
353       !DIR$ SIMD
354       DO ij=ij_begin,ij_end
355          dPhi(ij,l) = dPhi(ij,l) - wflux(ij,l) &
356               * (geopot(ij,l+1)-geopot(ij,l-1))/(mass(ij,l-1)+mass(ij,l))
357       END DO
358    END DO
359    DO l=ll_begin,ll_end
360       !DIR$ SIMD
361       DO ij=ij_begin,ij_end
362          dW(ij,l+1) = dW(ij,l+1) + W_etadot(ij,l) ! update inner+top interfaces
363          dW(ij,l)   = dW(ij,l)   - W_etadot(ij,l) ! update bottom+inner interfaces
364       END DO
365    END DO
366
367#undef ETA_DOT
368#undef WCOV
369#endif
370
371    CALL trace_end("compute_caldyn_vert_nh")
372
373  END SUBROUTINE compute_caldyn_vert_NH
374END MODULE caldyn_kernels_base_mod
Note: See TracBrowser for help on using the repository browser.