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

Last change on this file since 731 was 731, checked in by dubos, 6 years ago

devel : cleanup and reorganization in dynamics/

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