source: codes/icosagcm/trunk/src/transport/advect_tracer.f90 @ 548

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

trunk : reorganize source tree

File size: 10.1 KB
Line 
1MODULE advect_tracer_mod
2  USE icosa
3  IMPLICIT NONE
4  PRIVATE
5
6  TYPE(t_field),SAVE,POINTER :: f_normal(:)
7  TYPE(t_field),SAVE,POINTER :: f_tangent(:)
8  TYPE(t_field),SAVE,POINTER :: f_gradq3d(:)
9  TYPE(t_field),SAVE,POINTER :: f_cc(:)  ! starting point of backward-trajectory (Miura approach)
10  TYPE(t_field),SAVE,POINTER :: f_sqrt_leng(:)
11
12  TYPE(t_message),SAVE :: req_u, req_cc, req_wfluxt, req_q, req_rhodz, req_gradq3d
13
14  REAL(rstd), PARAMETER :: pente_max=2.0 ! for vlz
15
16! temporary shared variable for vlz
17  TYPE(t_field),SAVE,POINTER :: f_dzqw(:)   ! vertical finite difference of q
18  TYPE(t_field),SAVE,POINTER :: f_adzqw(:)  ! abs(dzqw)
19  TYPE(t_field),SAVE,POINTER :: f_dzq(:)    ! limited slope of q
20  TYPE(t_field),SAVE,POINTER :: f_wq(:)     ! time-integrated flux of q
21
22  PUBLIC init_advect_tracer, advect_tracer
23
24CONTAINS
25
26  SUBROUTINE init_advect_tracer
27    USE advect_mod
28    USE omp_para
29    REAL(rstd),POINTER :: tangent(:,:)
30    REAL(rstd),POINTER :: normal(:,:)
31    REAL(rstd),POINTER :: sqrt_leng(:)
32    INTEGER :: ind
33
34    CALL allocate_field(f_normal,field_u,type_real,3, name='normal')
35    CALL allocate_field(f_tangent,field_u,type_real,3, name='tangent')
36    CALL allocate_field(f_gradq3d,field_t,type_real,llm,3, name='gradq3d')
37    CALL allocate_field(f_cc,field_u,type_real,llm,3, name='cc')
38    CALL allocate_field(f_sqrt_leng,field_t,type_real, name='sqrt_leng')
39    CALL allocate_field(f_dzqw, field_t, type_real, llm, name='dzqw')
40    CALL allocate_field(f_adzqw, field_t, type_real, llm, name='adzqw')
41    CALL allocate_field(f_dzq, field_t, type_real, llm, name='dzq')
42    CALL allocate_field(f_wq, field_t, type_real, llm+1, name='wq')
43   
44    DO ind=1,ndomain
45       IF (.NOT. assigned_domain(ind)) CYCLE
46       CALL swap_dimensions(ind)
47       CALL swap_geometry(ind)
48       normal=f_normal(ind)
49       tangent=f_tangent(ind)
50       sqrt_leng=f_sqrt_leng(ind)
51       IF (is_omp_level_master) CALL init_advect(normal,tangent,sqrt_leng)
52    END DO
53
54  END SUBROUTINE init_advect_tracer
55
56  SUBROUTINE advect_tracer(f_hfluxt, f_wfluxt,f_u, f_q,f_rhodz)
57    USE advect_mod
58    USE mpipara
59    USE trace
60    USE write_field_mod
61    USE tracer_mod
62    IMPLICIT NONE
63   
64    TYPE(t_field),POINTER :: f_hfluxt(:)   ! time-integrated horizontal mass flux
65    TYPE(t_field),POINTER :: f_wfluxt(:)   ! time-integrated vertical mass flux
66    TYPE(t_field),POINTER :: f_u(:)        ! velocity (for back-trajectories)
67    TYPE(t_field),POINTER :: f_q(:)        ! tracer
68    TYPE(t_field),POINTER :: f_rhodz(:)    ! mass field at beginning of macro time step
69
70    REAL(rstd),POINTER :: q(:,:,:), normal(:,:), tangent(:,:), sqrt_leng(:), gradq3d(:,:,:), cc(:,:,:)
71    REAL(rstd),POINTER :: hfluxt(:,:), wfluxt(:,:)
72    REAL(rstd),POINTER :: rhodz(:,:), u(:,:) 
73! temporary shared variable for vlz
74    REAL(rstd),POINTER ::  dzqw(:,:)         ! vertical finite difference of q
75    REAL(rstd),POINTER ::  adzqw(:,:)        ! abs(dzqw)
76    REAL(rstd),POINTER ::  dzq(:,:)          ! limited slope of q
77    REAL(rstd),POINTER ::  wq(:,:)           ! time-integrated flux of q
78   
79     INTEGER :: ind,k, nq_last
80    LOGICAL,SAVE :: first=.TRUE.
81!$OMP THREADPRIVATE(first)
82
83    IF (first) THEN
84      first=.FALSE.
85      CALL init_message(f_u,req_e1_vect,req_u, 'req_u')
86      CALL init_message(f_cc,req_e1_scal,req_cc, 'req_cc')
87      CALL init_message(f_wfluxt,req_i1,req_wfluxt, 'req_wfluxt')
88      CALL init_message(f_q,req_i1,req_q, 'req_q')
89      CALL init_message(f_rhodz,req_i1,req_rhodz, 'req_rhodz')
90      CALL init_message(f_gradq3d,req_i1,req_gradq3d, 'req_gradq3d')
91    ENDIF
92   
93!!$OMP BARRIER
94
95    IF(nqtot<1) RETURN
96    nq_last=-1
97   
98    DO k = 1, nqtot
99      IF (advection_scheme(k)==advect_vanleer) nq_last=k
100    ENDDO
101     
102    IF(nq_last<0) RETURN
103     
104    CALL trace_start("advect_tracer") 
105
106    CALL send_message(f_u,req_u)
107    CALL send_message(f_wfluxt,req_wfluxt)
108    CALL send_message(f_q,req_q)
109    CALL send_message(f_rhodz,req_rhodz)
110
111    CALL wait_message(req_u)
112    CALL wait_message(req_wfluxt)
113    CALL wait_message(req_q)
114    CALL wait_message(req_rhodz)
115   
116    ! 1/2 vertical transport + back-trajectories
117    DO ind=1,ndomain
118       IF (.NOT. assigned_domain(ind)) CYCLE
119       CALL swap_dimensions(ind)
120       CALL swap_geometry(ind)
121       normal  = f_normal(ind)
122       tangent = f_tangent(ind)
123       cc      = f_cc(ind)
124       u       = f_u(ind)
125       q       = f_q(ind)
126       rhodz   = f_rhodz(ind)
127       wfluxt  = f_wfluxt(ind) 
128       dzqw    = f_dzqw(ind)
129       adzqw   = f_adzqw(ind)
130       dzq     = f_dzq(ind)
131       wq      = f_wq(ind) 
132
133       DO k = 1, nqtot
134          IF (advection_scheme(k)==advect_vanleer) CALL vlz(k==nq_last,0.5, wfluxt,rhodz,q(:,:,k),1,dzqw, adzqw, dzq, wq)
135       END DO
136
137       CALL compute_backward_traj(tangent,normal,u,0.5*dt*itau_adv, cc) 
138
139    END DO
140
141    CALL send_message(f_cc,req_cc)
142
143
144    ! horizontal transport - split in two to place transfer of gradq3d
145    DO k = 1, nqtot
146      IF (advection_scheme(k)==advect_vanleer) THEN
147       
148        DO ind=1,ndomain
149          IF (.NOT. assigned_domain(ind)) CYCLE
150          CALL swap_dimensions(ind)
151          CALL swap_geometry(ind)
152          q       = f_q(ind)
153          gradq3d = f_gradq3d(ind)
154          sqrt_leng=f_sqrt_leng(ind)
155          CALL compute_gradq3d(q(:,:,k),sqrt_leng,gradq3d,xyz_i,xyz_v)
156
157        END DO
158
159        CALL send_message(f_gradq3d,req_gradq3d)
160        CALL wait_message(req_cc)
161        CALL wait_message(req_gradq3d)
162
163
164        DO ind=1,ndomain
165          IF (.NOT. assigned_domain(ind)) CYCLE
166          CALL swap_dimensions(ind)
167          CALL swap_geometry(ind)
168          cc      = f_cc(ind)
169          q       = f_q(ind)
170          rhodz   = f_rhodz(ind)
171          hfluxt  = f_hfluxt(ind) 
172          gradq3d = f_gradq3d(ind)
173          CALL compute_advect_horiz(k==nq_last,hfluxt,cc,gradq3d, rhodz,q(:,:,k))
174        END DO
175      ENDIF
176    END DO 
177   
178    ! 1/2 vertical transport
179!!$OMP BARRIER
180
181    DO ind=1,ndomain
182       IF (.NOT. assigned_domain(ind)) CYCLE
183       CALL swap_dimensions(ind)
184       CALL swap_geometry(ind)
185       q       = f_q(ind)
186       rhodz   = f_rhodz(ind)
187       wfluxt  = f_wfluxt(ind) 
188       dzqw    = f_dzqw(ind)
189       adzqw   = f_adzqw(ind)
190       dzq     = f_dzq(ind)
191       wq      = f_wq(ind) 
192
193       DO k = 1,nqtot
194         IF (advection_scheme(k)==advect_vanleer) CALL vlz(k==nq_last, 0.5,wfluxt,rhodz, q(:,:,k),0, dzqw, adzqw, dzq, wq)
195       END DO
196
197    END DO
198
199    CALL trace_end("advect_tracer")
200
201!!$OMP BARRIER
202
203  END SUBROUTINE advect_tracer
204
205  SUBROUTINE vlz(update_mass, fac,wfluxt,mass, q, halo, dzqw, adzqw, dzq, wq)
206    !
207    !     Auteurs:   P.Le Van, F.Hourdin, F.Forget, T. Dubos
208    !
209    !    ********************************************************************
210    !     Update tracers using vertical mass flux only
211    !     Van Leer scheme with minmod limiter
212    !     wfluxt >0 for upward transport
213    !    ********************************************************************
214    USE trace
215    USE omp_para
216    IMPLICIT NONE
217    LOGICAL, INTENT(IN)       :: update_mass
218    REAL(rstd), INTENT(IN)    :: fac, wfluxt(iim*jjm,llm+1) ! vertical mass flux
219    REAL(rstd), INTENT(INOUT) :: mass(iim*jjm,llm)
220    REAL(rstd), INTENT(INOUT) :: q(iim*jjm,llm)
221    INTEGER, INTENT(IN) :: halo
222
223! temporary shared variable
224    REAL(rstd),INTENT(INOUT) :: dzqw(iim*jjm,llm),        & ! vertical finite difference of q
225                                adzqw(iim*jjm,llm),       & ! abs(dzqw)
226                                dzq(iim*jjm,llm),         & ! limited slope of q
227                                wq(iim*jjm,llm+1)           ! time-integrated flux of q
228
229
230    REAL(rstd) :: dzqmax, newmass, sigw, qq, w
231    INTEGER :: i,ij,l,j,ijb,ije
232
233    CALL trace_start("vlz")
234     
235     ijb=((jj_begin-halo)-1)*iim+ii_begin-halo
236     ije = ((jj_end+halo)-1)*iim+ii_end+halo
237
238    ! finite difference of q
239
240     DO l=ll_beginp1,ll_end
241!DIR$ SIMD
242       DO ij=ijb,ije
243         dzqw(ij,l)=q(ij,l)-q(ij,l-1)
244         adzqw(ij,l)=abs(dzqw(ij,l))
245       ENDDO
246    ENDDO
247
248!--> flush dzqw, adzqw
249!$OMP BARRIER
250
251    ! minmod-limited slope of q
252    ! dzq = slope*dz, i.e. the reconstructed q varies by dzq inside level l
253
254     DO l=ll_beginp1,ll_endm1
255!DIR$ SIMD
256       DO ij=ijb,ije 
257         IF(dzqw(ij,l)*dzqw(ij,l+1).gt.0.) THEN
258             dzq(ij,l) = 0.5*( dzqw(ij,l)+dzqw(ij,l+1) )
259             dzqmax    = pente_max * min( adzqw(ij,l),adzqw(ij,l+1) )
260             dzq(ij,l) = sign( min(abs(dzq(ij,l)),dzqmax) , dzq(ij,l) )  ! NB : sign(a,b)=a*sign(b)
261          ELSE
262             dzq(ij,l)=0.
263          ENDIF
264       ENDDO
265    ENDDO
266
267
268    ! 0 slope in top and bottom layers
269    IF (is_omp_first_level) THEN
270      DO ij=ijb,ije
271           dzq(ij,1)=0.
272      ENDDO
273    ENDIF
274     
275    IF (is_omp_last_level) THEN
276      DO ij=ijb,ije
277          dzq(ij,llm)=0.
278      ENDDO
279    ENDIF
280
281!---> flush dzq
282!$OMP BARRIER 
283
284    ! sigw = fraction of mass that leaves level l/l+1
285    ! then amount of q leaving level l/l+1 = wq = w * qq
286     DO l=ll_beginp1,ll_end
287!DIR$ SIMD
288       DO ij=ijb,ije
289             w = fac*wfluxt(ij,l)
290             IF(w>0.) THEN  ! upward transport, upwind side is at level l
291                sigw       = w/mass(ij,l-1)
292                qq         = q(ij,l-1)+0.5*(1.-sigw)*dzq(ij,l-1) ! qq = q if sigw=1 , qq = q+dzq/2 if sigw=0
293             ELSE           ! downward transport, upwind side is at level l+1
294                sigw       = w/mass(ij,l)
295                qq         = q(ij,l)-0.5*(1.+sigw)*dzq(ij,l) ! qq = q if sigw=-1 , qq = q-dzq/2 if sigw=0               
296             ENDIF
297             wq(ij,l) = w*qq
298       ENDDO
299    END DO
300    ! wq = 0 at top and bottom
301    IF (is_omp_first_level) THEN
302       DO ij=ijb,ije
303            wq(ij,1)=0.
304      END DO
305    ENDIF
306   
307    IF (is_omp_last_level) THEN
308      DO ij=ijb,ije
309            wq(ij,llm+1)=0.
310      END DO
311    ENDIF
312
313! --> flush wq
314!$OMP BARRIER
315
316
317    ! update q, mass is updated only after all q's have been updated
318    DO l=ll_begin,ll_end
319!DIR$ SIMD
320       DO ij=ijb,ije
321             newmass = mass(ij,l) + fac*(wfluxt(ij,l)-wfluxt(ij,l+1))
322             q(ij,l) = ( q(ij,l)*mass(ij,l) + wq(ij,l)-wq(ij,l+1) ) / newmass
323             IF(update_mass) mass(ij,l)=newmass
324       ENDDO
325    END DO
326
327    CALL trace_end("vlz")
328
329  END SUBROUTINE vlz
330
331END MODULE advect_tracer_mod
Note: See TracBrowser for help on using the repository browser.