advectz__slopes.F90 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. !### macro's #####################################################
  2. !
  3. #define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr
  4. #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
  5. #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
  6. #define IF_NOTOK_MPI(action) if (ierr/=MPI_SUCCESS) then; TRACEBACK; action; return; end if
  7. !
  8. #include "tm5.inc"
  9. !
  10. !-----------------------------------------------------------------------------
  11. ! TM5 !
  12. !-----------------------------------------------------------------------------
  13. !BOP
  14. !
  15. ! !MODULE: ADVECTZ
  16. !
  17. ! !DESCRIPTION:
  18. !\\
  19. !\\
  20. ! !INTERFACE:
  21. !
  22. MODULE ADVECTZ
  23. !
  24. ! !USES:
  25. !
  26. USE GO, ONLY : gol, goPr, goErr
  27. USE TM5_DISTGRID, ONLY : DGRID, GET_DISTGRID, UPDATE_HALO, REDUCE
  28. IMPLICIT NONE
  29. PRIVATE
  30. !
  31. ! !PUBLIC MEMBER FUNCTIONS:
  32. !
  33. PUBLIC :: DYNAMW
  34. !
  35. ! !REVISION HISTORY:
  36. ! 3 Feb 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  37. !
  38. !EOP
  39. !------------------------------------------------------------------------
  40. CONTAINS
  41. !--------------------------------------------------------------------------
  42. ! TM5 !
  43. !--------------------------------------------------------------------------
  44. !BOP
  45. !
  46. ! !IROUTINE: DYNAMW
  47. !
  48. ! !DESCRIPTION: Calculate amount of tracer moved in a vertical advection substep.
  49. !
  50. ! method : slopes scheme
  51. ! reference : Russel and Lerner, 1979
  52. !\\
  53. !\\
  54. ! !INTERFACE:
  55. !
  56. SUBROUTINE DYNAMW
  57. !
  58. ! !USES:
  59. !
  60. use dims, only : lm
  61. use dims, only : zbeg, zend, epsz, nloop_max, zero, one
  62. use dims, only : okdebug, limits, xi, nxi
  63. use global_data, only : wind_dat, mass_dat
  64. use meteodata , only : m_dat
  65. use chem_param, only : ntracet, ra
  66. use toolbox, only : escape_tm
  67. #ifdef with_budgets
  68. use budget_global, only : budget_flux, lflux1, lflux2, apply_budget_global_flux
  69. #endif
  70. use ParTools, only : isRoot, par_reduce
  71. !
  72. ! !REVISION HISTORY:
  73. !
  74. ! - programmed by mh, mpi HH, 1994-1995
  75. ! - zoom version written by mike botchev, march-june 1999
  76. ! - 3 Feb 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  77. !
  78. ! !REMARKS:
  79. ! - commented method #2, which may be an option if there is CFL violation. If not, it just
  80. ! adds extra communication.
  81. !EOP
  82. !------------------------------------------------------------------------
  83. !BOC
  84. real, dimension(:,:,:,:), pointer :: rm, rxm, rym, rzm
  85. real, dimension(:,:,:), pointer :: m, cm
  86. real, dimension(:,:,:), allocatable :: mnew, f, pf, fx, fy, cmold, mold
  87. integer :: i,j,l,le,lee,ls,lss,n,lmr,i1,i2,j1,j2, is, ie, js, je
  88. integer :: halo
  89. real :: max_one
  90. real :: gam, gamma, my_gamma
  91. integer,parameter :: iter_limit=15
  92. integer :: n_advz, iter, nglob, status
  93. real :: l_xi, g_xi, l_nxi, g_nxi, g_nl
  94. !METHOD#2 #ifdef MPI
  95. !METHOD#2 integer :: request, stat(MPI_STATUS_SIZE)
  96. !METHOD#2 logical :: done
  97. !METHOD#2 #endif
  98. !----------- START
  99. ! Indices & work arrays
  100. CALL GET_DISTGRID( dgrid(1), I_STRT=i1, I_STOP=i2,J_STRT=j1, J_STOP=j2)
  101. lmr=lm(1)
  102. is=i1 ; ie=i2 ; js=j1 ; je=j2
  103. halo = wind_dat(1)%halo
  104. allocate(cmold( i1-halo:i2+halo, j1-halo:j2+halo, 0:lmr+1) ) ! same halo as wind_dat)
  105. halo = m_dat(1)%halo
  106. allocate( mold( i1-halo:i2+halo, j1-halo:j2+halo, lmr ) ) ! same halo as m_dat)
  107. rm => mass_dat(1)%rm
  108. rxm => mass_dat(1)%rxm
  109. rym => mass_dat(1)%rym
  110. rzm => mass_dat(1)%rzm
  111. m => m_dat(1)%data
  112. cm => wind_dat(1)%cm
  113. ls=1
  114. le=lmr
  115. if(abs(zbeg(1)-zbeg(1))<epsz) ls = 1 ! bottom
  116. if(abs(zend(1)-zend(1))<epsz) le = lmr ! top
  117. !
  118. ! if requested limit vertical slopes such that no non-negative
  119. ! tracer masses should occur
  120. if (limits) then
  121. do n = 1, ntracet
  122. do l = ls, le
  123. do j = js, je
  124. do i = is, ie
  125. rzm(i,j,l,n) = max (min (rzm(i,j,l,n), rm(i,j,l,n)), -rm(i,j,l,n))
  126. end do
  127. end do
  128. end do
  129. end do
  130. end if
  131. !
  132. !==== loop to determine number of needed iterations
  133. !
  134. lss = ls; lee = le
  135. if (abs (zbeg(1) - zbeg(1)) < epsz) lss = 2
  136. if (abs (zend(1) - zend(1)) < epsz) lee = lmr - 1
  137. cmold = cm
  138. mold = m
  139. n_advz = 1
  140. l_xi = 0.0
  141. l_nxi = 0.0
  142. cfl: do
  143. ! calculate new air mass distribution
  144. cm = cmold / float (n_advz)
  145. m = mold
  146. ! do the iteration
  147. advz: do iter=1,n_advz
  148. ! reset gamma
  149. gam = 0.
  150. !METHOD #2 #ifdef MPI
  151. !METHOD #2 call MPI_IRECV(gam, 1, my_real, MPI_ANY_SOURCE, iter, localComm, request, ierr)
  152. !METHOD #2 done = .false.
  153. !METHOD #2 #endif
  154. ! compute f, pf, fx and fy
  155. ijl: do l=lss-1,lee ! 1,lmm1
  156. do j=j1,j2
  157. do i=i1,i2
  158. if(cm(i,j,l)>=zero) then
  159. my_gamma=cm(i,j,l)/m(i,j,l)
  160. else
  161. my_gamma=cm(i,j,l)/m(i,j,l+1)
  162. end if
  163. !aMETHOD-1
  164. l_xi=max(l_xi,abs(my_gamma))
  165. if ( abs(my_gamma) >= one ) exit ijl
  166. !eMETHOD-1
  167. !aMETHOD-2
  168. ! gam = abs(my_gamma)
  169. ! l_xi = max(l_xi, gam)
  170. ! if ( gam >= one ) then
  171. ! do n=0,npes-1
  172. ! call MPI_SEND(gam, 1, my_real, n, iter, localComm, stat, ierr)
  173. ! end do
  174. ! end if
  175. ! call MPI_TEST(request, done, stat, ierr)
  176. ! if (done) exit ijl
  177. !eMETHOD-2
  178. end do
  179. end do
  180. end do ijl
  181. !aMETHOD-1
  182. my_gamma=abs(my_gamma)
  183. call Par_REDUCE( my_gamma, 'MAX', gamma, status, all=.true.)
  184. if (gamma>=one) then
  185. l_nxi=l_nxi+1
  186. gam=gamma
  187. exit advz
  188. end if
  189. !eMETHOD-1
  190. !aMETHOD #2
  191. ! call Par_REDUCE( gam, 'MAX', gam, status, all=.true.)
  192. ! call MPI_TEST(request, done, stat, ierr)
  193. ! if (.not.done) then
  194. ! ! print*, "cancel ", iter, request, gam
  195. ! call MPI_CANCEL(request, ierr)
  196. ! call MPI_REQUEST_FREE(request, ierr)
  197. ! end if
  198. ! if (gam>=one) then
  199. ! l_nxi=l_nxi+1
  200. ! exit advz
  201. ! end if
  202. !eMETHOD-2
  203. ! no CFLs upto now.....possibly in next?
  204. if (abs(zbeg(1)-zbeg(1))<epsz) then
  205. ! bottom: one-sided update of the mass
  206. m(is:ie,js:je,1) = m(is:ie,js:je,1) - cm(is:ie,js:je,1)
  207. end if
  208. if (abs(zend(1)-zend(1))<epsz) then
  209. ! top: one-sided update of the mass
  210. m(is:ie,js:je,lmr) = m(is:ie,js:je,lmr) + cm(is:ie,js:je,lmr-1)
  211. end if
  212. m(is:ie,js:je,lss:lee) = m(is:ie,js:je,lss:lee) + &
  213. cm(is:ie,js:je,lss-1:lee-1) - &
  214. cm(is:ie,js:je,lss:lee)
  215. end do advz
  216. ! if still CFL violation increase iteration counter and re-start cfl loop
  217. ! escape is called when the number of iterations becomes too large
  218. if(abs(gam)>=one) then
  219. if(okdebug)then
  220. if ( my_gamma >= one) then
  221. write(gol,*)'dynamw: CFL violation: gamma,m,cm=', gam,m(i,j,l), m(i,j,l+1),cm(i,j,l), &
  222. ' in region,i,j,l,n: ',1,i,j,l,n ; call goPr
  223. write(gol,*)'dynamw: iterations:',n_advz ; call goPr
  224. endif
  225. endif
  226. n_advz = n_advz + 1
  227. if ( n_advz > iter_limit ) &
  228. call escape_tm('dynamw: too many CFL violations!')
  229. cycle cfl
  230. else
  231. exit cfl
  232. end if
  233. end do cfl
  234. ! n_advz is now determined : gather and store information
  235. CALL PAR_REDUCE( float(n_advz), 'max', g_nl, status, .true.)
  236. CALL PAR_REDUCE( l_xi, 'max', g_xi, status, .true.)
  237. CALL PAR_REDUCE( l_nxi, 'sum', g_nxi, status, .true.)
  238. nloop_max(1,3) = max(nloop_max(1,3), nint (g_nl))
  239. xi(1,3) = max (xi(1,3), g_xi)
  240. nxi(1,3) = nxi(1,3) + nint (g_nxi)
  241. ! reset m and cm to original values:
  242. cm = cmold/float(n_advz)
  243. m = mold
  244. !
  245. !==== Apply number of iterations to calculate new air mass distribution
  246. !
  247. allocate (mnew( is:ie, js:je, 1:lm(1) ))
  248. allocate ( f( is:ie, js:je, 0:lm(1) ))
  249. allocate ( pf( is:ie, js:je, 0:lm(1) ))
  250. allocate ( fx( is:ie, js:je, 0:lm(1) ))
  251. allocate ( fy( is:ie, js:je, 0:lm(1) ))
  252. ! do the iteration
  253. ITERA: do iter=1,n_advz
  254. if (abs(zbeg(1)-zbeg(1))<epsz) then
  255. ! bottom: one-sided update of the mass
  256. mnew(is:ie,js:je,1) = m(is:ie,js:je,1) - cm(is:ie,js:je,1)
  257. end if
  258. if (abs(zend(1)-zend(1))<epsz) then
  259. ! top: one-sided update of the mass
  260. mnew(is:ie,js:je,lmr) = m(is:ie,js:je,lmr) + cm(is:ie,js:je,lmr-1)
  261. end if
  262. mnew(is:ie,js:je,lss:lee) = m(is:ie,js:je,lss:lee) &
  263. + cm(is:ie,js:je,lss-1:lee-1) &
  264. - cm(is:ie,js:je,lss:lee)
  265. ! loop over tracers
  266. TRAC : do n=1,ntracet
  267. ! compute f, pf, fx and fy
  268. do l=lss-1,lee ! 1,lmm1
  269. do j=js,je
  270. do i=is,ie
  271. if(cm(i,j,l)>=zero) then
  272. gamma=cm(i,j,l)/m(i,j,l)
  273. f(i,j,l)=gamma*(rm(i,j,l,n)+(one-gamma)* rzm(i,j,l,n) )
  274. pf(i,j,l)=cm(i,j,l)*(gamma*gamma* rzm(i,j,l,n)-3.*f(i,j,l))
  275. fx(i,j,l)=gamma*rxm(i,j,l,n)
  276. fy(i,j,l)=gamma*rym(i,j,l,n)
  277. else
  278. gamma=cm(i,j,l)/m(i,j,l+1)
  279. f(i,j,l)=gamma*(rm(i,j,l+1,n)-(one+gamma)* rzm(i,j,l+1,n))
  280. pf(i,j,l)=cm(i,j,l)*(gamma*gamma* rzm(i,j,l+1,n)-3.*f(i,j,l))
  281. fx(i,j,l)=gamma*rxm(i,j,l+1,n)
  282. fy(i,j,l)=gamma*rym(i,j,l+1,n)
  283. end if
  284. end do
  285. end do
  286. end do
  287. ! calculate new tracer mass, and tracer mass slopes
  288. ! update rm, rzm, rxm and rym in interior layers of the column
  289. #ifdef with_budgets
  290. ! calculate flux flowing in from below:
  291. if (apply_budget_global_flux) then
  292. do j=js,je
  293. do i=is,ie
  294. budget_flux(1)%flux_z1(i,j,n) = budget_flux(1)%flux_z1(i,j,n) + &
  295. f(i,j,lflux1(1)-1)*1e3/ra(n) ! moles
  296. budget_flux(1)%flux_z2(i,j,n) = budget_flux(1)%flux_z2(i,j,n) + &
  297. f(i,j,lflux2(1)-1)*1e3/ra(n) ! moles
  298. enddo
  299. enddo
  300. endif
  301. #endif
  302. do l=lss,lee !2,lmm1
  303. rm(is:ie,js:je,l,n) = rm(is:ie,js:je,l,n) + f(is:ie,js:je,l-1)-f(is:ie,js:je,l)
  304. rzm(is:ie,js:je,l,n) = rzm(is:ie,js:je,l,n) + &
  305. ( pf(is:ie,js:je,l-1) - pf(is:ie,js:je,l) - (cm(is:ie,js:je,l-1)-cm(is:ie,js:je,l))* rzm(is:ie,js:je,l,n) &
  306. + 3.0*( (cm(is:ie,js:je,l-1)+cm(is:ie,js:je,l))* rm(is:ie,js:je,l,n) &
  307. - (f(is:ie,js:je,l-1)+f(is:ie,js:je,l))* m(is:ie,js:je,l) ) ) / mnew(is:ie,js:je,l)
  308. if ( limits ) then !CMK added
  309. rzm(is:ie,js:je,l,n) = max(min(rzm(is:ie,js:je,l,n), rm(is:ie,js:je,l,n)), -rm(is:ie,js:je,l,n))
  310. end if
  311. rxm(is:ie,js:je,l,n) = rxm(is:ie,js:je,l,n) + (fx(is:ie,js:je,l-1)-fx(is:ie,js:je,l))
  312. rym(is:ie,js:je,l,n) = rym(is:ie,js:je,l,n) + (fy(is:ie,js:je,l-1)-fy(is:ie,js:je,l))
  313. end do
  314. if ( abs(zbeg(1)-zbeg(1)) < epsz ) then ! bottom
  315. ! update rm, rzm, rxm and rym near the ground surface
  316. rm(is:ie,js:je,1,n)=(rm(is:ie,js:je,1,n)-f(is:ie,js:je,1))
  317. rzm(is:ie,js:je,1,n)=rzm(is:ie,js:je,1,n)+(-pf(is:ie,js:je,1) &
  318. +cm(is:ie,js:je,1)*rzm(is:ie,js:je,1,n) &
  319. +3.*(cm(is:ie,js:je,1)*rm(is:ie,js:je,1,n) &
  320. -f(is:ie,js:je,1)*m(is:ie,js:je,1)))/mnew(is:ie,js:je,1)
  321. if ( limits ) then !CMK added
  322. rzm(is:ie,js:je,1,n) = max(min(rzm(is:ie,js:je,1,n), &
  323. rm(is:ie,js:je,1,n)), &
  324. -rm(is:ie,js:je,1,n))
  325. end if
  326. rxm(is:ie,js:je,1,n)=rxm(is:ie,js:je,1,n)-fx(is:ie,js:je,1)
  327. rym(is:ie,js:je,1,n)=rym(is:ie,js:je,1,n)-fy(is:ie,js:je,1)
  328. end if
  329. if (abs(zend(1)-zend(1))<epsz) then ! top
  330. ! update rm, rzm, rxm and rym at the top of the atmosphere
  331. rm(is:ie,js:je,lmr,n)=rm(is:ie,js:je,lmr,n)+f(is:ie,js:je,lmr-1)
  332. rzm(is:ie,js:je,lmr,n)=rzm(is:ie,js:je,lmr,n)+&
  333. (pf(is:ie,js:je,lmr-1) &
  334. -cm(is:ie,js:je,lmr-1)*rzm(is:ie,js:je,lmr,n) &
  335. +3.*(cm(is:ie,js:je,lmr-1)*rm(is:ie,js:je,lmr,n) &
  336. -f(is:ie,js:je,lmr-1)*m(is:ie,js:je,lmr))) / &
  337. mnew(is:ie,js:je,lmr)
  338. if ( limits ) then !CMK added
  339. rzm(is:ie,js:je,lmr,n) = max(min(rzm(is:ie,js:je,lmr,n), &
  340. rm(is:ie,js:je,lmr,n)), &
  341. -rm(is:ie,js:je,lmr,n))
  342. end if
  343. rxm(is:ie,js:je,lmr,n) = rxm(is:ie,js:je,lmr,n) + &
  344. fx(is:ie,js:je,lmr-1)
  345. rym(is:ie,js:je,lmr,n) = rym(is:ie,js:je,lmr,n) + &
  346. fy(is:ie,js:je,lmr-1)
  347. end if
  348. end do TRAC ! loop over tracers
  349. ! store new air mass in m array
  350. m(is:ie,js:je,ls:le)=mnew(is:ie,js:je,ls:le)
  351. end do ITERA !iter
  352. ! restore cm wind
  353. cm = cmold
  354. deallocate (f)
  355. deallocate (pf)
  356. deallocate (fx)
  357. deallocate (fy)
  358. deallocate(mnew)
  359. deallocate(cmold)
  360. if ( okdebug ) then
  361. mold(is:ie,js:je,ls:le)=rm(is:ie,js:je,ls:le,1)/m(is:ie,js:je,ls:le)
  362. call REDUCE( dgrid(1), mold, 2, 'MAX', max_one, status)
  363. if (isRoot) then
  364. write(gol,*) 'dynamw: z Maximum value mixing ratio',max_one; call goPr
  365. end if
  366. end if
  367. deallocate(mold)
  368. nullify(rm)
  369. nullify(rxm)
  370. nullify(rym)
  371. nullify(rzm)
  372. nullify(m)
  373. nullify(cm)
  374. END SUBROUTINE DYNAMW
  375. !EOC
  376. END MODULE ADVECTZ