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

Last change on this file since 404 was 404, checked in by dubos, 8 years ago

Towards moist dynamics - tested with DCMIP41

File size: 11.1 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
40    INTEGER    :: ij_omp_begin_ext, ij_omp_end_ext
41
42    CALL trace_start("compute_geopot")
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       !DIR$ SIMD
82       DO ij=ij_omp_begin_ext,ij_omp_end_ext
83          pk(ij,llm) = ptop + (.5*g)*rhodz(ij,llm)
84       END DO
85       ! other layers
86       DO l = llm-1, 1, -1
87          !DIR$ SIMD
88          DO ij=ij_omp_begin_ext,ij_omp_end_ext         
89             pk(ij,l) = pk(ij,l+1) + (.5*g)*(rhodz(ij,l)+rhodz(ij,l+1))
90          END DO
91       END DO
92       ! surface pressure (for diagnostics)
93       IF(caldyn_eta==eta_lag) THEN
94          DO ij=ij_omp_begin_ext,ij_omp_end_ext         
95             ps(ij) = pk(ij,1) + (.5*g)*rhodz(ij,1)
96          END DO
97       END IF
98       
99       DO l = 1,llm
100          SELECT CASE(caldyn_thermo)
101          CASE(thermo_theta)
102             !DIR$ SIMD
103             DO ij=ij_omp_begin_ext,ij_omp_end_ext
104                p_ik = pk(ij,l)
105                exner_ik = cpp * (p_ik/preff) ** kappa
106                pk(ij,l) = exner_ik
107                ! specific volume v = kappa*theta*pi/p = dphi/g/rhodz
108                geopot(ij,l+1) = geopot(ij,l) + (g*kappa)*rhodz(ij,l)*theta(ij,l,1)*exner_ik/p_ik
109             ENDDO
110          CASE(thermo_entropy) ! theta is in fact entropy = cpp*log(theta/Treff) = cpp*log(T/Treff) - Rd*log(p/preff)
111             !DIR$ SIMD
112             DO ij=ij_omp_begin_ext,ij_omp_end_ext
113                p_ik = pk(ij,l)
114                temp_ik = Treff*exp((theta(ij,l,1) + Rd*log(p_ik/preff))/cpp)
115                pk(ij,l) = temp_ik
116                ! specific volume v = Rd*T/p = dphi/g/rhodz
117                geopot(ij,l+1) = geopot(ij,l) + (g*Rd)*rhodz(ij,l)*temp_ik/p_ik
118             ENDDO
119          CASE DEFAULT
120             STOP
121          END SELECT
122       ENDDO
123    END IF
124
125    !ym flush geopot
126    !$OMP BARRIER
127
128    CALL trace_end("compute_geopot")
129
130  END SUBROUTINE compute_geopot
131
132  SUBROUTINE compute_caldyn_vert(u,theta,rhodz,convm, wflux,wwuu, dps,dtheta_rhodz,du)
133    REAL(rstd),INTENT(IN)  :: u(iim*3*jjm,llm)
134    REAL(rstd),INTENT(IN)  :: theta(iim*jjm,llm)
135    REAL(rstd),INTENT(IN)  :: rhodz(iim*jjm,llm)
136    REAL(rstd),INTENT(INOUT)  :: convm(iim*jjm,llm)  ! mass flux convergence
137
138    REAL(rstd),INTENT(INOUT) :: wflux(iim*jjm,llm+1) ! vertical mass flux (kg/m2/s)
139    REAL(rstd),INTENT(INOUT) :: wwuu(iim*3*jjm,llm+1)
140    REAL(rstd),INTENT(INOUT) :: du(iim*3*jjm,llm)
141    REAL(rstd),INTENT(INOUT) :: dtheta_rhodz(iim*jjm,llm)
142    REAL(rstd),INTENT(OUT) :: dps(iim*jjm)
143
144    ! temporary variable   
145    INTEGER :: i,j,ij,l
146    REAL(rstd) :: p_ik, exner_ik
147    INTEGER    :: ij_omp_begin, ij_omp_end
148
149    CALL trace_start("compute_caldyn_vert")
150
151    CALL distrib_level(ij_end-ij_begin+1,ij_omp_begin,ij_omp_end)
152    ij_omp_begin=ij_omp_begin+ij_begin-1
153    ij_omp_end=ij_omp_end+ij_begin-1
154
155    !    REAL(rstd) :: wwuu(iim*3*jjm,llm+1) ! tmp var, don't know why but gain 30% on the whole code in opemp
156    ! need to be understood
157
158    !    wwuu=wwuu_out
159    CALL trace_start("compute_caldyn_vert")
160
161    !$OMP BARRIER   
162!!! cumulate mass flux convergence from top to bottom
163    !  IF (is_omp_level_master) THEN
164    DO  l = llm-1, 1, -1
165       !    IF (caldyn_conserv==energy) CALL test_message(req_qu)
166
167!!$OMP DO SCHEDULE(STATIC)
168       !DIR$ SIMD
169       DO ij=ij_omp_begin,ij_omp_end         
170          convm(ij,l) = convm(ij,l) + convm(ij,l+1)
171       ENDDO
172    ENDDO
173    !  ENDIF
174
175    !$OMP BARRIER
176    ! FLUSH on convm
177!!!!!!!!!!!!!!!!!!!!!!!!!
178
179    ! compute dps
180    IF (is_omp_first_level) THEN
181       !DIR$ SIMD
182       DO ij=ij_begin,ij_end         
183          ! dps/dt = -int(div flux)dz
184          IF(DEC) THEN
185             dps(ij) = convm(ij,1)
186          ELSE
187             dps(ij) = convm(ij,1) * g 
188          END IF
189       ENDDO
190    ENDIF
191
192!!! Compute vertical mass flux (l=1,llm+1 done by caldyn_BC)
193    DO l=ll_beginp1,ll_end
194       !    IF (caldyn_conserv==energy) CALL test_message(req_qu)
195       !DIR$ SIMD
196       DO ij=ij_begin,ij_end         
197          ! w = int(z,ztop,div(flux)dz) + B(eta)dps/dt
198          ! => w>0 for upward transport
199          wflux( ij, l ) = bp(l) * convm( ij, 1 ) - convm( ij, l ) 
200       ENDDO
201    ENDDO
202
203    !--> flush wflux 
204    !$OMP BARRIER
205
206    DO l=ll_begin,ll_endm1
207       !DIR$ SIMD
208       DO ij=ij_begin,ij_end         
209          dtheta_rhodz(ij, l ) = dtheta_rhodz(ij, l )  -   0.5 * (  wflux(ij,l+1) * (theta(ij,l) + theta(ij,l+1)))
210       ENDDO
211    ENDDO
212
213    DO l=ll_beginp1,ll_end
214       !DIR$ SIMD
215       DO ij=ij_begin,ij_end         
216          dtheta_rhodz(ij, l ) = dtheta_rhodz(ij, l )  +   0.5 * ( wflux(ij,l  ) * (theta(ij,l-1) + theta(ij,l) ) )
217       ENDDO
218    ENDDO
219
220
221    ! Compute vertical transport
222    DO l=ll_beginp1,ll_end
223       !DIR$ SIMD
224       DO ij=ij_begin,ij_end         
225          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))
226          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))
227          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))
228       ENDDO
229    ENDDO
230
231    !--> flush wwuu 
232    !$OMP BARRIER
233
234    ! Add vertical transport to du
235    DO l=ll_begin,ll_end
236       !DIR$ SIMD
237       DO ij=ij_begin,ij_end         
238          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))
239          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))
240          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))
241       ENDDO
242    ENDDO
243
244    !  DO l=ll_beginp1,ll_end
245    !!DIR$ SIMD
246    !      DO ij=ij_begin,ij_end         
247    !        wwuu_out(ij+u_right,l) = wwuu(ij+u_right,l)
248    !        wwuu_out(ij+u_lup,l)   = wwuu(ij+u_lup,l)
249    !        wwuu_out(ij+u_ldown,l) = wwuu(ij+u_ldown,l)
250    !     ENDDO
251    !   ENDDO
252
253    CALL trace_end("compute_caldyn_vert")
254
255  END SUBROUTINE compute_caldyn_vert
256
257  SUBROUTINE compute_caldyn_vert_NH(mass,geopot,W,wflux, du,dPhi,dW)
258    REAL(rstd),INTENT(IN) :: mass(iim*jjm,llm)
259    REAL(rstd),INTENT(IN) :: geopot(iim*jjm,llm+1)
260    REAL(rstd),INTENT(IN) :: W(iim*jjm,llm+1)
261    REAL(rstd),INTENT(IN) :: wflux(iim*jjm,llm+1)
262    REAL(rstd),INTENT(INOUT) :: du(iim*3*jjm,llm)
263    REAL(rstd),INTENT(INOUT) :: dPhi(iim*jjm,llm+1)
264    REAL(rstd),INTENT(INOUT) :: dW(iim*jjm,llm+1)
265    ! local arrays
266    REAL(rstd) :: eta_dot(iim*jjm) ! eta_dot in full layers
267    REAL(rstd) :: wcov(iim*jjm) ! covariant vertical momentum in full layers
268    REAL(rstd) :: W_etadot(iim*jjm,llm) ! vertical flux of vertical momentum
269    ! indices and temporary values
270    INTEGER    :: ij, l
271    REAL(rstd) :: wflux_ij, w_ij
272
273    CALL trace_start("compute_caldyn_vert_nh")
274
275    DO l=ll_begin,ll_end
276       ! compute the local arrays
277       !DIR$ SIMD
278       DO ij=ij_begin_ext,ij_end_ext
279          wflux_ij = .5*(wflux(ij,l)+wflux(ij,l+1))
280          w_ij = .5*(W(ij,l)+W(ij,l+1))/mass(ij,l)
281          W_etadot(ij,l) = wflux_ij*w_ij
282          eta_dot(ij) = wflux_ij / mass(ij,l)
283          wcov(ij) = w_ij*(geopot(ij,l+1)-geopot(ij,l))
284       ENDDO
285       ! add NH term to du
286      !DIR$ SIMD
287      DO ij=ij_begin,ij_end
288          du(ij+u_right,l) = du(ij+u_right,l) &
289               - .5*(wcov(ij+t_right)+wcov(ij)) &
290               *ne_right*(eta_dot(ij+t_right)-eta_dot(ij))
291          du(ij+u_lup,l) = du(ij+u_lup,l) &
292               - .5*(wcov(ij+t_lup)+wcov(ij)) &
293               *ne_lup*(eta_dot(ij+t_lup)-eta_dot(ij))
294          du(ij+u_ldown,l) = du(ij+u_ldown,l) &
295               - .5*(wcov(ij+t_ldown)+wcov(ij)) &
296               *ne_ldown*(eta_dot(ij+t_ldown)-eta_dot(ij))
297       END DO
298    ENDDO
299    ! add NH terms to dW, dPhi
300    ! FIXME : TODO top and bottom
301    DO l=ll_beginp1,ll_end ! inner interfaces only
302       !DIR$ SIMD
303       DO ij=ij_begin,ij_end
304          dPhi(ij,l) = dPhi(ij,l) - wflux(ij,l) &
305               * (geopot(ij,l+1)-geopot(ij,l-1))/(mass(ij,l-1)+mass(ij,l))
306       END DO
307    END DO
308    DO l=ll_begin,ll_end
309       !DIR$ SIMD
310       DO ij=ij_begin,ij_end
311          dW(ij,l+1) = dW(ij,l+1) + W_etadot(ij,l) ! update inner+top interfaces
312          dW(ij,l)   = dW(ij,l)   - W_etadot(ij,l) ! update bottom+inner interfaces
313       END DO
314    END DO
315    CALL trace_end("compute_caldyn_vert_nh")
316
317  END SUBROUTINE compute_caldyn_vert_NH
318END MODULE caldyn_kernels_base_mod
Note: See TracBrowser for help on using the repository browser.