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

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

Cleanup after fixing RK2.5

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