tm5_tracer_data.F90 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. !#################################################################
  2. !
  3. ! tracer mass
  4. !
  5. !### macro's #####################################################
  6. !
  7. #define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr
  8. #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
  9. #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
  10. !
  11. #include "tm5.inc"
  12. !
  13. !#################################################################
  14. !
  15. ! Declare non-transported tracers : chem_data (type), chem_dat (var)
  16. ! Declare transported tracers : mass_data (type), mass_dat (var)
  17. ! Allocate both transported and non-transported tracers : tracer_init
  18. ! Free allocated tracers : tracer_done
  19. !
  20. MODULE TRACER_DATA
  21. use GO, only : gol, goErr, goPr
  22. use dims, only : nregions
  23. use tm5_distgrid, only : dgrid, Get_DistGrid
  24. IMPLICIT NONE
  25. PRIVATE
  26. public :: mass_data, mass_dat ! type and array for transported tracers
  27. public :: chem_data, chem_dat ! type and array for non-transported tracers
  28. public :: tracer_init ! allocate tracers arrays
  29. public :: tracer_done ! deallocate tracers arrays
  30. public :: AdjustTracer
  31. public :: tracer_print ! tracer and air masses in one box (location hardwire)
  32. public :: par_check_mass ! print min/max/total of Air, All-tracers, and one tracer
  33. public :: init_short ! init non-transported tracers (used when istart=4 or 5)
  34. #ifndef __GFORTRAN__
  35. public :: init_non_zero ! init tracer to small non-zero (used when istart=2)
  36. #endif
  37. #ifdef with_feedback
  38. public :: Tracer_Fill_Slabs
  39. #endif
  40. ! --- const --------------------------------------
  41. character(len=*), parameter :: mname = 'tracer_data'
  42. TYPE MASS_DATA ! --- TRANSPORTED TRACERS
  43. !
  44. ! All to be allocated with halo=2
  45. !
  46. ! rm tracer masses (kg)
  47. ! rxm tracer slopes in kg/(halfgridsize)
  48. ! rym tracer slopes in kg/(halfgridsize)
  49. ! rzm tracer slopes in kg/(halfgridsize)
  50. !
  51. real,dimension(:,:,:,:),pointer :: rm
  52. #ifdef slopes
  53. real,dimension(:,:,:,:),pointer :: rxm
  54. real,dimension(:,:,:,:),pointer :: rym
  55. real,dimension(:,:,:,:),pointer :: rzm
  56. #ifdef secmom
  57. real,dimension(:,:,:,:),pointer :: rxxm
  58. real,dimension(:,:,:,:),pointer :: rxym
  59. real,dimension(:,:,:,:),pointer :: rxzm
  60. real,dimension(:,:,:,:),pointer :: ryym
  61. real,dimension(:,:,:,:),pointer :: ryzm
  62. real,dimension(:,:,:,:),pointer :: rzzm
  63. #endif
  64. #endif
  65. integer :: halo
  66. END TYPE MASS_DATA
  67. TYPE CHEM_DATA ! --- NON-TRANSPORTED TRACERS
  68. real,dimension(:,:,:,:),pointer :: rm
  69. integer :: halo
  70. END TYPE CHEM_DATA
  71. ! --- VAR ------------------------------
  72. ! transported tracer masses
  73. type(mass_data), target :: mass_dat(nregions)
  74. ! non-transported tracer masses
  75. ! Note expected 4th dim : (:,:,:,ntracet+1:ntracet+ntrace_chem)
  76. type(chem_data), target :: chem_dat(nregions)
  77. CONTAINS
  78. !
  79. ! ======================================================================
  80. !
  81. SUBROUTINE TRACER_INIT
  82. use dims, only : lm
  83. use chem_param, only : ntracet, ntrace_chem
  84. integer :: i1, i2, j1, j2
  85. integer :: n, l_halo
  86. l_halo = 2 ! to adapt accordingly
  87. ! allocate transported tracers
  88. do n=1, nregions
  89. call Get_DistGrid( dgrid(n), I_STRT=i1, I_STOP=i2, &
  90. J_STRT=j1, J_STOP=j2 )
  91. mass_dat(n)%halo = l_halo
  92. allocate( mass_dat(n)%rm( i1-l_halo:i2+l_halo, j1-l_halo:j2+l_halo, lm(n), ntracet) )
  93. #ifdef slopes
  94. allocate( mass_dat(n)%rxm( i1-l_halo:i2+l_halo, j1-l_halo:j2+l_halo, lm(n), ntracet) )
  95. allocate( mass_dat(n)%rym( i1-l_halo:i2+l_halo, j1-l_halo:j2+l_halo, lm(n), ntracet) )
  96. allocate( mass_dat(n)%rzm( i1-l_halo:i2+l_halo, j1-l_halo:j2+l_halo, lm(n), ntracet) )
  97. #ifdef secmom
  98. allocate( mass_dat(n)%rxxm( i1-l_halo:i2+l_halo, j1-l_halo:j2+l_halo, lm(n), ntracet) )
  99. allocate( mass_dat(n)%rxym( i1-l_halo:i2+l_halo, j1-l_halo:j2+l_halo, lm(n), ntracet) )
  100. allocate( mass_dat(n)%rxzm( i1-l_halo:i2+l_halo, j1-l_halo:j2+l_halo, lm(n), ntracet) )
  101. allocate( mass_dat(n)%ryym( i1-l_halo:i2+l_halo, j1-l_halo:j2+l_halo, lm(n), ntracet) )
  102. allocate( mass_dat(n)%ryzm( i1-l_halo:i2+l_halo, j1-l_halo:j2+l_halo, lm(n), ntracet) )
  103. allocate( mass_dat(n)%rzzm( i1-l_halo:i2+l_halo, j1-l_halo:j2+l_halo, lm(n), ntracet) )
  104. #endif
  105. #endif
  106. mass_dat(n)%rm =0.0
  107. #ifdef slopes
  108. mass_dat(n)%rxm=0.0
  109. mass_dat(n)%rym=0.0
  110. mass_dat(n)%rzm=0.0
  111. #ifdef secmom
  112. mass_dat(n)%rxxm=0.0
  113. mass_dat(n)%rxym=0.0
  114. mass_dat(n)%rxzm=0.0
  115. mass_dat(n)%ryym=0.0
  116. mass_dat(n)%ryzm=0.0
  117. mass_dat(n)%rzzm=0.0
  118. #endif
  119. #endif
  120. ! allocate non-transported tracers, if any
  121. if ( ntrace_chem > 0 ) then
  122. chem_dat(n)%halo = 0
  123. allocate( chem_dat(n)%rm(i1:i2, j1:j2, lm(n), ntracet+1:ntracet+ntrace_chem) )
  124. chem_dat(n)%rm = 0.0
  125. else
  126. nullify( chem_dat(n)%rm )
  127. end if
  128. end do
  129. END SUBROUTINE TRACER_INIT
  130. !
  131. ! ======================================================================
  132. !
  133. SUBROUTINE TRACER_DONE
  134. USE CHEM_PARAM, ONLY : NTRACE_CHEM
  135. integer :: n
  136. ! allocate transported tracers
  137. do n=1, nregions
  138. ! deallocate transported tracers
  139. if(associated( mass_dat(n)%rm)) nullify( mass_dat(n)%rm)
  140. #ifdef slopes
  141. if(associated( mass_dat(n)%rxm)) nullify( mass_dat(n)%rxm)
  142. if(associated( mass_dat(n)%rym)) nullify( mass_dat(n)%rym)
  143. if(associated( mass_dat(n)%rzm)) nullify( mass_dat(n)%rzm)
  144. #ifdef secmom
  145. if(associated( mass_dat(n)%rxxm)) nullify( mass_dat(n)%rxxm)
  146. if(associated( mass_dat(n)%rxym)) nullify( mass_dat(n)%rxym)
  147. if(associated( mass_dat(n)%rxzm)) nullify( mass_dat(n)%rxzm)
  148. if(associated( mass_dat(n)%ryym)) nullify( mass_dat(n)%ryym)
  149. if(associated( mass_dat(n)%ryzm)) nullify( mass_dat(n)%ryzm)
  150. if(associated( mass_dat(n)%rzzm)) nullify( mass_dat(n)%rzzm)
  151. #endif
  152. #endif
  153. ! deallocate non-transported tracers, if any
  154. if ( ntrace_chem > 0 ) then
  155. if(associated( chem_dat(n)%rm)) nullify( chem_dat(n)%rm)
  156. end if
  157. end do
  158. END SUBROUTINE TRACER_DONE
  159. !------------------------------------------------------------------------------
  160. ! TM5 !
  161. !------------------------------------------------------------------------------
  162. !BOP
  163. !
  164. ! !IROUTINE: INIT_SHORT
  165. !
  166. ! !DESCRIPTION: Initialise short lived chemical compounds to a reasonable
  167. ! value e.g NO2 = NOX. It is called from initexit/start when istart=4 or 5.
  168. !\\
  169. !\\
  170. ! !INTERFACE:
  171. !
  172. SUBROUTINE INIT_SHORT( region )
  173. !
  174. ! !USES:
  175. !
  176. use tm5_distgrid, only : dgrid, Get_DistGrid
  177. use chem_param, only : ino2, inox
  178. !
  179. ! !INPUT PARAMETERS:
  180. !
  181. integer, intent(in) :: region
  182. !
  183. ! !REVISION HISTORY:
  184. ! 7 May 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  185. !
  186. !EOP
  187. !------------------------------------------------------------------------------
  188. !BOC
  189. integer :: i1,j1,j2,i2
  190. call Get_DistGrid( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  191. if ( (ino2 > 0) .and. (inox > 0)) then
  192. chem_dat(region)%rm(i1:i2, j1:j2, :, ino2) = mass_dat(region)%rm(i1:i2, j1:j2, :, inox)
  193. endif
  194. END SUBROUTINE INIT_SHORT
  195. !EOC
  196. #ifndef __GFORTRAN__
  197. !------------------------------------------------------------------------------
  198. ! TM5 !
  199. !------------------------------------------------------------------------------
  200. !BOP
  201. !
  202. ! !IROUTINE: INIT_NON_ZERO
  203. !
  204. ! !DESCRIPTION: Set tracer initial values to some small value.
  205. ! It is called from initexit/start when ISTART = 2.
  206. !\\
  207. !\\
  208. SUBROUTINE INIT_NON_ZERO
  209. !
  210. ! !USES:
  211. !
  212. use chem_param, only : fscale, ntracet, ntrace, ntrace_chem, ino2, inox
  213. use meteodata, only : m_dat
  214. !
  215. ! !REVISION HISTORY:
  216. ! 2 Apr 2010 - P. Le Sager -
  217. !
  218. ! !REMARKS:
  219. ! - A remnant from old debugging/benchmark. Has one advantage: can be
  220. ! used to set to non-zero start values, which is important for chemistry.
  221. ! - Could be set to values based on process number for debugging. See commented code.
  222. !EOP
  223. !------------------------------------------------------------------------------
  224. !BOC
  225. real, dimension(:,:,:,:), pointer :: rm
  226. #ifdef slopes
  227. real, dimension(:,:,:,:), pointer :: rxm, rym, rzm
  228. #ifdef secmom
  229. real, dimension(:,:,:,:), pointer :: rxxm, rxym, rxzm, ryym, ryzm, rzzm
  230. #endif
  231. #endif
  232. integer :: rank, i0, i1, j0, j1, n, region
  233. real, dimension(:,:,:), pointer :: m
  234. ! --- begin --------------------------------
  235. do region=1,nregions
  236. call Get_DistGrid( dgrid(region), I_STRT=i0, I_STOP=i1, J_STRT=j0, J_STOP=j1 )
  237. ! pseudo-random number ( for now just retrieve rank )
  238. rank = ( i1 / (i1-i0) ) * ( j1 / (j1-j0) ) - 1
  239. m => m_dat(region)%data
  240. do n=1,ntracet
  241. mass_dat(region)%rm(:,:,:,n) = 1e-30 * m / fscale(n)
  242. !--for something not totally uniform and processor dependant
  243. ! ! fill transported tracers
  244. ! do n=1,ntracet
  245. ! mass_dat(region)%rm( i0:i1, j0:j1,:,n) = (rank+1)*1e-9*m/fscale(n)
  246. ! enddo
  247. enddo
  248. ! non-transported tracers
  249. if ( ntrace_chem > 0 ) then
  250. do n=ntracet+1,ntrace
  251. chem_dat(region)%rm(:,:,:,n) = 1e-30 * m/fscale(n)
  252. end do
  253. endif
  254. if ( (ino2 > 0) .and. (inox > 0)) then
  255. chem_dat(region)%rm(:,:,:,ino2) = mass_dat(region)%rm(:,:,:,inox)
  256. endif
  257. #ifdef slopes
  258. mass_dat(region)%rxm = 0.0
  259. mass_dat(region)%rym = 0.0
  260. mass_dat(region)%rzm = 0.0
  261. #ifdef secmom
  262. mass_dat(region)%rxxm = 0.0
  263. mass_dat(region)%rxym = 0.0
  264. mass_dat(region)%rxzm = 0.0
  265. mass_dat(region)%ryym = 0.0
  266. mass_dat(region)%ryzm = 0.0
  267. mass_dat(region)%rzzm = 0.0
  268. #endif
  269. #endif
  270. nullify(m)
  271. enddo
  272. !write(gol,*) ' rm initialized at mixing ratio of 1e-30' ; call goPr
  273. END SUBROUTINE INIT_NON_ZERO
  274. !EOC
  275. #endif
  276. !
  277. ! Tracer slopes (kg/half cell) and second moments (kg/(half cell)^2)
  278. ! are adjusted with the same factor as applied to the total mass
  279. ! (background: if the concentration 'in the middle' is decreased
  280. ! by a factor 0.5, then the concentrations at the boundaries are
  281. ! also changed with a factor 0.5 :
  282. !
  283. ! ^ | | | |
  284. ! tracer| 6 | o | |
  285. ! mass | | - | | |
  286. ! (kg) 4 | o | -> | |
  287. ! | - | 3 | _ o
  288. ! 2 o | 2 | _ o |
  289. ! | | 1 o |
  290. ! --------------- ---------------
  291. !
  292. ! 15 Nov 2011 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  293. !
  294. subroutine AdjustTracer( drm, region, i, j, l, k, status )
  295. use GO , only : gol, goErr
  296. ! --- in/out -----------------------------
  297. real, intent(in) :: drm ! tracer mass change (kg)
  298. integer, intent(in) :: region
  299. integer, intent(in) :: i, j ! cell indices
  300. integer, intent(in) :: l ! local level
  301. integer, intent(in) :: k ! tracer index
  302. integer, intent(out) :: status
  303. ! --- const -------------------------------
  304. character(len=*), parameter :: rname = mname//'/AdjustTracer'
  305. ! --- local -------------------------------
  306. real, dimension(:,:,:,:), pointer :: rm
  307. #ifdef slopes
  308. real, dimension(:,:,:,:), pointer :: rxm, rym, rzm
  309. #ifdef secmom
  310. real, dimension(:,:,:,:), pointer :: rxxm, rxym, rxzm, ryym, ryzm, rzzm
  311. #endif
  312. #endif
  313. real :: rm_old
  314. real :: skf
  315. ! --- begin -----------------------------
  316. ! set pointers
  317. rm => mass_dat(region)%rm
  318. #ifdef slopes
  319. rxm => mass_dat(region)%rxm
  320. rym => mass_dat(region)%rym
  321. rzm => mass_dat(region)%rzm
  322. #ifdef secmom
  323. rxxm => mass_dat(region)%rxxm
  324. rxym => mass_dat(region)%rxym
  325. rxzm => mass_dat(region)%rxzm
  326. ryym => mass_dat(region)%ryym
  327. ryzm => mass_dat(region)%ryzm
  328. rzzm => mass_dat(region)%rzzm
  329. #endif
  330. #endif
  331. ! store old tracer mass:
  332. rm_old = rm(i,j,l,k)
  333. ! store new tracer mass:
  334. rm(i,j,l,k) = rm_old + drm
  335. #ifdef slopes
  336. ! adjust concentration gradients
  337. ! scale factor to be applied; trap devision by zero:
  338. if ( (rm(i,j,l,k) > tiny(1.0)) .and. (rm_old > tiny(0.0)) ) then
  339. skf = rm(i,j,l,k) / rm_old
  340. else
  341. skf = 0.0
  342. end if
  343. ! adjust slopes:
  344. rxm(i,j,l,k) = rxm(i,j,l,k) * skf
  345. rym(i,j,l,k) = rym(i,j,l,k) * skf
  346. rzm(i,j,l,k) = rzm(i,j,l,k) * skf
  347. #ifdef secmom
  348. ! adjust second moments:
  349. rxxm(i,j,l,k) = rxxm(i,j,l,k) * skf
  350. rxym(i,j,l,k) = rxym(i,j,l,k) * skf
  351. rxzm(i,j,l,k) = rxzm(i,j,l,k) * skf
  352. ryym(i,j,l,k) = ryym(i,j,l,k) * skf
  353. ryzm(i,j,l,k) = ryzm(i,j,l,k) * skf
  354. rzzm(i,j,l,k) = rzzm(i,j,l,k) * skf
  355. #endif
  356. #endif
  357. ! ok
  358. status = 0
  359. end subroutine AdjustTracer
  360. !--------------------------------------------------------------------------
  361. ! TM5 !
  362. !--------------------------------------------------------------------------
  363. !BOP
  364. !
  365. ! !IROUTINE: TRACER_PRINT
  366. !
  367. ! !DESCRIPTION: Debug tool. Print value of tracer mass and air mass in one
  368. ! box, with message at the begining
  369. !\\
  370. !\\
  371. ! !INTERFACE:
  372. !
  373. SUBROUTINE TRACER_PRINT( region, message, status )
  374. !
  375. ! !USES:
  376. !
  377. use GO
  378. use dims, only : im, jm, lm
  379. use chem_param, only : ntrace, ntracet, names
  380. use meteodata, only : m_dat, phlb_dat
  381. !
  382. ! !INPUT PARAMETERS:
  383. !
  384. character(len=*), intent(in) :: message
  385. integer, intent(in) :: region
  386. !
  387. ! !OUTPUT PARAMETERS:
  388. !
  389. integer, intent(out) :: status
  390. !
  391. ! !REVISION HISTORY:
  392. ! 15 Feb 2012 - P. Le Sager
  393. !
  394. !EOP
  395. !------------------------------------------------------------------------
  396. !BOC
  397. character(len=*), parameter :: rname = mname//'/tracer_print'
  398. integer :: ii, jj, ll, kk, i1, j1, i2, j2
  399. real :: pat, patx, paty, patz, patm, patp
  400. ! set those for the box/tracer used to debug, revert to (1,1,1,1) when you are done
  401. ii=1
  402. jj=1
  403. ll=1
  404. kk=1
  405. call Get_DistGrid( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2)
  406. if((ii<i1).or.(ii>i2).or.(jj<j1).or.(jj>j2)) then
  407. status=0
  408. return
  409. endif
  410. if (kk <= ntracet) then
  411. pat = mass_dat(region)%rm (ii,jj,ll,kk)
  412. #ifdef slopes
  413. patx = mass_dat(region)%rxm(ii,jj,ll,kk)
  414. paty = mass_dat(region)%rym(ii,jj,ll,kk)
  415. patz = mass_dat(region)%rzm(ii,jj,ll,kk)
  416. #endif
  417. else if (kk <= ntrace) then
  418. pat = chem_dat(region)%rm(ii,jj,ll,kk)
  419. #ifdef slopes
  420. patx = 0.
  421. paty = 0.
  422. patz = 0.
  423. #endif
  424. else
  425. write(gol,*) "out of range tracer index"; call goErr
  426. status=1
  427. IF_NOTOK_RETURN(status=1)
  428. end if
  429. patm = m_dat(region)%data(ii,jj,ll)
  430. patp = phlb_dat(region)%data(ii,jj,ll)
  431. ! Decide what to write:
  432. #ifdef slopes
  433. write (gol,*) message//" "//names(kk), pat, patx, paty, patz, patm ; call goBug
  434. #else
  435. write (gol,*) message//" "//names(kk), pat, patm ; call goBug
  436. #endif
  437. ! ok
  438. status = 0
  439. END SUBROUTINE TRACER_PRINT
  440. !EOC
  441. !--------------------------------------------------------------------------
  442. ! TM5 !
  443. !--------------------------------------------------------------------------
  444. !BOP
  445. !
  446. ! !IROUTINE: PAR_CHECK_MASS
  447. !
  448. ! !DESCRIPTION: Debug tool. Print min, max, and sum of air mass and tracer
  449. ! mass.
  450. !\\
  451. !\\
  452. ! !INTERFACE:
  453. !
  454. SUBROUTINE PAR_CHECK_MASS( region, text, tr_id, debug )
  455. !
  456. ! !USES:
  457. !
  458. use meteodata, only : m_dat
  459. use tm5_distgrid, only : reduce
  460. use partools, only : isRoot
  461. !
  462. ! !INPUT PARAMETERS:
  463. !
  464. integer, intent(in) :: region
  465. character(len=*), intent(in) :: text
  466. integer, optional, intent(in) :: tr_id
  467. logical, optional, intent(in) :: debug ! if true, REDUCE prints min/maxloc
  468. !
  469. ! !REVISION HISTORY:
  470. ! 15 Feb 2012 - P. Le Sager - v0
  471. !
  472. !EOP
  473. !------------------------------------------------------------------------
  474. !BOC
  475. real, dimension(:,:,:), pointer :: m
  476. real, dimension(:,:,:,:), pointer :: rm
  477. real :: min_one, max_one, tot_one
  478. integer :: status, trid
  479. logical :: dbg_
  480. ! check input
  481. trid=1
  482. if(present(tr_id)) trid=tr_id
  483. dbg_=.false.
  484. if(present(debug)) dbg_=debug
  485. rm => mass_dat(region)%rm
  486. m => m_dat(region)%data
  487. ! air mass
  488. call REDUCE( dgrid(region), m, m_dat(region)%halo, 'MAX', max_one, status, debug=dbg_)
  489. call REDUCE( dgrid(region), m, m_dat(region)%halo, 'MIN', min_one, status, debug=dbg_)
  490. call REDUCE( dgrid(region), m, m_dat(region)%halo, 'SUM', tot_one, status, debug=dbg_)
  491. if ( isRoot ) then
  492. write(gol,*) text//' [par_check_mass] AIR min, max, sum: ', min_one, max_one, tot_one ; call goPr
  493. endif
  494. ! all transported tracers
  495. call REDUCE( dgrid(region), rm, mass_dat(region)%halo, 'MAX', max_one, status, debug=dbg_)
  496. call REDUCE( dgrid(region), rm, mass_dat(region)%halo, 'MIN', min_one, status, debug=dbg_)
  497. call REDUCE( dgrid(region), rm, mass_dat(region)%halo, 'SUM', tot_one, status, debug=dbg_)
  498. if ( isRoot ) then
  499. write(gol,*) text//' [par_check_mass] RM min, max, sum: ', min_one, max_one, tot_one ; call goPr
  500. endif
  501. nullify(m)
  502. ! one selected tracer
  503. m => mass_dat(region)%rm(:,:,:,trid) ! no need for temp arr since slice is in last dimension
  504. call REDUCE( dgrid(region), m, mass_dat(region)%halo, 'MAX', max_one, status, debug=dbg_)
  505. call REDUCE( dgrid(region), m, mass_dat(region)%halo, 'MIN', min_one, status, debug=dbg_)
  506. call REDUCE( dgrid(region), m, mass_dat(region)%halo, 'SUM', tot_one, status, debug=dbg_)
  507. if ( isRoot ) then
  508. write(gol,*) text//' [par_check_mass] ID, min, max, sum: ', trid, min_one, max_one, tot_one ; call goPr
  509. endif
  510. nullify(m)
  511. END SUBROUTINE PAR_CHECK_MASS
  512. !EOC
  513. !
  514. ! Convert and put a slab of tracer mass (with given unit and tracer id)
  515. ! into tracer mass array (in kg); adust slopes too.
  516. !
  517. #ifdef with_feedback
  518. subroutine Tracer_Fill_Slabs( region, itr, unit, rm_k, status )
  519. use dims , only : im, jm, lm
  520. use chem_param , only : ntrace, ntracet, fscale
  521. use partools , only : myid, root
  522. use partools , only : previous_par, tracer_loc, tracer_id, tracer_active
  523. use partools , only : lmloc, lmar, offsetl
  524. use partools , only : Par_Gather_From_Levels
  525. use meteodata , only : m_dat
  526. ! --- in/out -------------------------------------
  527. integer, intent(in) :: region
  528. integer, intent(in) :: itr
  529. character(len=*), intent(in) :: unit
  530. real, intent(in) :: rm_k(:,:,:)
  531. integer, intent(out) :: status
  532. ! --- const ------------------------------
  533. character(len=*), parameter :: rname = mname//'/Tracer_Fill_Slabs'
  534. ! --- local ---------------------------------
  535. integer :: i, j, l, lmr
  536. integer :: i01, i02, j01, j02, lmr
  537. ! --- begin ----------------------------------
  538. ! local grid size
  539. lmr = lm(region)
  540. call Get_DistGrid( dgrid(region), I_STRT=i01, I_STOP=i02, &
  541. J_STRT=j01, J_STOP=j02 )
  542. ! check input:
  543. if ( any(shape(rm_k)/=(/i02-i01+1,j02-j01+1,lmr/)) ) then
  544. write (gol,'("shape of output grid not ok:")'); call goErr
  545. write (gol,'(" shape(rm_k) : ",3i4)') shape(rm_k); call goErr
  546. write (gol,'(" i02-i01+1,j02-j01+1,lmr : ",3i4)') i02-i01+1,j02-j01+1,lmr; call goErr
  547. TRACEBACK; status=1; return
  548. end if
  549. ! transported or short lived tracer ?
  550. if ( (itr >= 1) .and. (itr <= ntracet) ) then
  551. ! rm_k was in given unit; convert x_t to kg :
  552. select case ( unit )
  553. case ( 'kg' )
  554. ! x_t already in kg
  555. ! apply unit conversion from (kg plc tracer) to (kg tm tracer)
  556. rm_k = rm_k / plc_kg_from_tm(itr)
  557. case ( 'mass-mixing-ratio' )
  558. ! mass mixing ratio
  559. ! apply unit conversion from (kg plc tracer) to (kg tm tracer)
  560. rm_k = rm_k / plc_kg_from_tm(itr)
  561. rm_k = rm_k * m_dat(region)%data(i01:i02,j01:j02,:)
  562. case ( 'volume-mixing-ratio' )
  563. ! volume mixing ratio = mass mixing ratio * fscale
  564. ! apply unit conversion from (kg plc tracer) to (kg tm tracer)
  565. rm_k = rm_k / plc_kg_from_tm(itr)
  566. rm_k = rm_k * m_dat(region)%data(i01:i02,j01:j02,:) / fscale(itr)
  567. case default
  568. write (gol,'("unsupported unit for par tracer : ",a)') unit; call goErr
  569. TRACEBACK; status=1; return
  570. end select
  571. ! replace new mass rm_k by difference with rm :
  572. rm_k = rm_k - mass_dat(region)%rm_t(i01:i02,j01:j02,:,itr) ! kg
  573. ! add change in kg to tracer arrays, adjust slopes:
  574. do l = 1, lmr
  575. do j = j01, j02
  576. do i = i01, i02
  577. ! adjust tracer arrays for local indices:
  578. call AdjustTracer( rm_k(i,j,l), region, i, j, l, itr, status )
  579. IF_NOTOK_RETURN(status=1)
  580. end do
  581. end do
  582. end do
  583. else if ( (itr > ntracet) .and. (itr <= ntrace) ) then
  584. ! rm_k was in given unit; convert x_k to kg :
  585. select case ( unit )
  586. case ( 'kg' )
  587. ! x_k already in kg
  588. case ( 'mass-mixing-ratio' )
  589. ! mass mixing ratio to tracer mass:
  590. x_k = x_k * m_dat(region)%data(i01:i02,j01:j02,:)
  591. case ( 'volume-mixing-ratio' )
  592. ! volume mixing ratio = mass mixing ratio * fscale
  593. x_k = x_k * m_dat(region)%data(i01:i02,j01:j02,:) / fscale(itr)
  594. case default
  595. write (gol,'("unsupported unit for non-transported tracer slab : ",a)') unit; call goErr
  596. TRACEBACK; status=1; return
  597. end select
  598. ! replace short-lived tracer:
  599. chem_dat(region)%rm(:,:,:,itr) = rm_k ! kg
  600. else
  601. write (gol,'("unsupported tracer index : ",i4)') itr; call goErr
  602. write (gol,'(" ntrace, ntracet : ",2i4)') ntrace, ntracet; call goErr
  603. TRACEBACK; status=1; return
  604. end if ! transported or chem-only
  605. ! ok
  606. status = 0
  607. end subroutine Tracer_Fill_Slabs
  608. #endif
  609. END MODULE TRACER_DATA