source: codes/icosagcm/trunk/src/caldyn_kernels_base.f90 @ 519

Last change on this file since 519 was 479, checked in by ymipsl, 8 years ago

Missing synchronisation for OpenMP on vertical level

YM

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