toolbox.F90 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480
  1. !
  2. #define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr
  3. #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
  4. #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
  5. !
  6. #include "tm5.inc"
  7. !
  8. !-------------------------------------------------------------------------
  9. ! TM5 !
  10. !-------------------------------------------------------------------------
  11. !BOP
  12. !
  13. ! !MODULE: TOOLBOX
  14. !
  15. ! !DESCRIPTION: General tools for chemistry/emission treatment.
  16. !\\
  17. !\\
  18. ! !INTERFACE:
  19. !
  20. MODULE TOOLBOX
  21. !
  22. ! !USES:
  23. !
  24. use GO, only : gol, goErr, goPr, goLabel, goBug
  25. use dims, only : okdebug
  26. IMPLICIT NONE
  27. PRIVATE
  28. !
  29. ! !PUBLIC MEMBER FUNCTIONS:
  30. !
  31. public :: zfarr ! calculation of Arrhenius expression for rate constants
  32. public :: ltropo ! find tropopause level from T gradient
  33. public :: lvlpress ! return index of highest level below a pressure value
  34. public :: dumpfield ! write 4D field (real) to file (debug tool)
  35. public :: dumpfieldi ! write 4D field (real) to file (debug tool)
  36. public :: coarsen_emission ! convert GLOBAL field to each region
  37. public :: escape_tm ! error handler
  38. public :: distribute_emis2D ! distribute vertically 2D field [work on MPI tiles]
  39. public :: distribute1x1 ! distribute vertically GLOBAL 1x1 2D field
  40. public :: distribute1x1b ! alternate distribute1x1
  41. public :: tropospheric_columns ! integrate tropospheric ozone
  42. !
  43. ! !PRIVATE DATA MEMBERS:
  44. !
  45. character(len=*), parameter :: mname = 'toolbox'
  46. !
  47. ! !INTERFACE:
  48. !
  49. interface coarsen_emission
  50. module procedure coarsen_emission_1d
  51. module procedure coarsen_emission_2d
  52. module procedure coarsen_emission_3d
  53. module procedure coarsen_emission_d23
  54. end interface
  55. !
  56. ! !REVISION HISTORY:
  57. ! 16 Jul 2010 - Achim Strunk - optional input to distribute_emis2D; protex
  58. ! 24 Jan 2012 - P. Le Sager - fixed coarsen_emission_2d and 3d for lon-lat MPI domain decomposition
  59. !
  60. ! !REMARKS:
  61. !
  62. !EOP
  63. !-----------------------------------------------------------------------
  64. CONTAINS
  65. !-----------------------------------------------------------------------
  66. ! TM5 !
  67. !-----------------------------------------------------------------------
  68. !BOP
  69. !
  70. ! !FUNCTION: ltropo
  71. !
  72. ! !DESCRIPTION: determine tropopause level from temperature gradient
  73. ! reference: WMO /Bram Bregman
  74. !\\
  75. !\\
  76. ! !INTERFACE:
  77. !
  78. integer function ltropo(region,tx,gphx,lmx)
  79. !
  80. ! !INPUT PARAMETERS:
  81. !
  82. integer,intent(in) :: region
  83. integer,intent(in) :: lmx
  84. real,dimension(lmx),intent(in) :: tx
  85. real,dimension(lmx+1),intent(in) :: gphx
  86. !
  87. ! !REVISION HISTORY:
  88. ! programmed by fd 01-11-1996
  89. ! changed to function fd 12-07-2002
  90. ! 16 Jul 2010 - Achim Strunk -
  91. !
  92. ! !REMARKS:
  93. !
  94. !EOP
  95. !------------------------------------------------------------------------
  96. !BOC
  97. integer :: ltmin,ltmax,l
  98. real :: dz,dt
  99. ! ltropo is highest tropospheric level
  100. ! above is defined as stratosphere
  101. ! min tropopause level 450 hPa (ca. 8 km)
  102. ltmin=lvlpress(region,45000.,98400.)
  103. ! max tropopause level 70 hPa (ca. 20 km)
  104. ltmax=lvlpress(region,7000.,98400.)
  105. ltropo=ltmin
  106. do l=ltmin,ltmax
  107. dz=(gphx(l)-gphx(l-2))/2.
  108. dt=(tx(l)-tx(l-1))/dz
  109. if ( dt < -0.002) ltropo=l !wmo 85 criterium for stratosphere
  110. ! increase upper tropospheric level
  111. end do !l
  112. end function ltropo
  113. !EOC
  114. !---------------------------------------------------------------------------
  115. ! TM5 !
  116. !---------------------------------------------------------------------------
  117. !BOP
  118. !
  119. ! !FUNCTION: lvlpress
  120. !
  121. ! !DESCRIPTION: lvlpress determines the index of the level with a pressure
  122. ! greater than press i.e. in height below press
  123. ! determines level independent of vertical resolution lm
  124. ! uses hybrid level coefficients to determine lvlpress
  125. !\\
  126. !\\
  127. ! !INTERFACE:
  128. !
  129. integer function lvlpress(region,press,press0)
  130. !
  131. ! !USES:
  132. !
  133. use dims, only: at, bt, lm
  134. !
  135. ! !INPUT PARAMETERS:
  136. !
  137. integer, intent(in) :: region
  138. real, intent(in) :: press
  139. real, intent(in) :: press0
  140. !
  141. ! !REVISION HISTORY:
  142. ! programmed by Peter van Velthoven, 6-november-2000
  143. ! 16 Jul 2010 - Achim Strunk -
  144. !
  145. ! !REMARKS:
  146. !
  147. !EOP
  148. !------------------------------------------------------------------------
  149. !BOC
  150. real :: zpress0, zpress
  151. integer :: l,lvl
  152. if ( press0 == 0.0 ) then
  153. zpress0 = 98400.
  154. else
  155. zpress0 = press0
  156. endif
  157. lvl = 1
  158. ! l increases from bottom (l=1) to top (l=lm)
  159. do l = 1, lm(region)
  160. zpress = (at(l)+at(l+1) + (bt(l)+bt(l+1))*zpress0)*0.5
  161. if ( press < zpress ) then
  162. lvl = l
  163. endif
  164. end do
  165. lvlpress = lvl
  166. end function lvlpress
  167. !EOC
  168. !--------------------------------------------------------------------------
  169. ! TM5 !
  170. !--------------------------------------------------------------------------
  171. !BOP
  172. !
  173. ! !FUNCTION: zfarr
  174. !
  175. ! !DESCRIPTION: ZFARR calculation of Arrhenius expression for rate constants
  176. !\\
  177. !\\
  178. ! !INTERFACE:
  179. !
  180. real function zfarr(rx1,er,ztrec)
  181. !
  182. ! !INPUT PARAMETERS:
  183. !
  184. real,intent(in) :: rx1,er,ztrec
  185. !
  186. ! !REVISION HISTORY:
  187. ! 16 Jul 2010 - Achim Strunk -
  188. !
  189. !EOP
  190. !------------------------------------------------------------------------
  191. !BOC
  192. zfarr=rx1*exp(er*ztrec)
  193. end function zfarr
  194. !EOC
  195. !--------------------------------------------------------------------------
  196. ! TM5 !
  197. !--------------------------------------------------------------------------
  198. !BOP
  199. !
  200. ! !IROUTINE: DumpField
  201. !
  202. ! !DESCRIPTION: Write 4D field (type real) to HDF file
  203. !\\
  204. !\\
  205. ! !INTERFACE:
  206. !
  207. subroutine dumpfield(flag,fname,im,jm,lm,nt,field,namfield)
  208. !
  209. ! !USES:
  210. !
  211. use io_hdf, only : DFACC_CREATE, DFACC_WRITE, io_write
  212. !
  213. ! !INPUT PARAMETERS:
  214. !
  215. integer, intent(in) :: im, jm, lm, nt
  216. integer, intent(in) :: flag
  217. real, dimension(im,jm,lm,nt), intent(in) :: field ! 4D field
  218. character(len=*), intent(in) :: fname ! file name
  219. character(len=*), intent(in) :: namfield ! field name
  220. !
  221. ! !REVISION HISTORY:
  222. ! 16 Jul 2010 - Achim Strunk - protex
  223. !
  224. !EOP
  225. !------------------------------------------------------------------------
  226. !BOC
  227. integer :: sfstart, io, sfend
  228. if ( flag==0 ) then
  229. io = sfstart(fname,DFACC_CREATE)
  230. else
  231. io = sfstart(fname,DFACC_WRITE)
  232. if ( io == -1 ) io = sfstart(fname,DFACC_CREATE)
  233. end if
  234. call io_write(io,im,'X',jm,'Y',lm,'Z',nt,'N',field,namfield)
  235. io = sfend(io)
  236. end subroutine dumpfield
  237. !EOC
  238. !--------------------------------------------------------------------------
  239. ! TM5 !
  240. !--------------------------------------------------------------------------
  241. !BOP
  242. !
  243. ! !IROUTINE: dumpfieldi
  244. !
  245. ! !DESCRIPTION: Write 4D field (type integer) to HDF file
  246. !\\
  247. !\\
  248. ! !INTERFACE:
  249. !
  250. subroutine dumpfieldi(flag,fname,im,jm,lm,nt,field,namfield)
  251. !
  252. ! !USES:
  253. !
  254. use io_hdf, only : DFACC_CREATE, DFACC_WRITE, io_write
  255. !
  256. ! !INPUT PARAMETERS:
  257. !
  258. integer,intent(in) :: im, jm, lm, nt
  259. integer,intent(in) :: flag
  260. integer,dimension(im,jm,lm,nt),intent(in) :: field ! 4D field
  261. character(len=*),intent(in) :: fname ! file name
  262. character(len=*),intent(in) :: namfield ! field name
  263. !
  264. ! !REVISION HISTORY:
  265. ! 16 Jul 2010 - Achim Strunk - protex
  266. !
  267. !EOP
  268. !------------------------------------------------------------------------
  269. !BOC
  270. integer :: sfstart,io,sfend
  271. if ( flag == 0 ) then
  272. io = sfstart(fname,DFACC_CREATE)
  273. else
  274. io = sfstart(fname,DFACC_WRITE)
  275. if (io==-1) io = sfstart(fname,DFACC_CREATE)
  276. end if
  277. call io_write(io,im,'X',jm,'Y',lm,'Z',nt,'N',field,namfield)
  278. io = sfend(io)
  279. end subroutine dumpfieldi
  280. !EOC
  281. !--------------------------------------------------------------------------
  282. ! TM5 !
  283. !--------------------------------------------------------------------------
  284. !BOP
  285. !
  286. ! !IROUTINE: coarsen_emission_1d
  287. !
  288. ! !DESCRIPTION: Transform the 1D field available on e.g. 1 degree resolution
  289. ! to the desired zoom geometry
  290. !\\
  291. !\\
  292. ! !INTERFACE:
  293. !
  294. subroutine coarsen_emission_1d( name_field, jm_emis, field_in, field, avg, status)
  295. !
  296. ! name_field : name, only for printing reasons
  297. ! jm_emis : the dimension of the input field
  298. ! field_in : the input field
  299. ! field : type d2_data (defined in chem_param)
  300. ! avg : flags the mode: avg = 1 means that a surface area
  301. ! weighted area is calulated (e.g. land fraction)
  302. ! avg = 0 means that the sum of the underlying field
  303. ! is taken (e.g. emissions in kg/month).
  304. !
  305. ! !USES:
  306. !
  307. use dims, only: nregions, dy, yref, ybeg, jm, dxy11, idate
  308. use global_types, only: d2_data
  309. implicit none
  310. !
  311. ! !INPUT PARAMETERS:
  312. !
  313. character(len=*), intent(in) :: name_field
  314. integer, intent(in) :: avg ! 0=no 1=yes
  315. integer, intent(in) :: jm_emis
  316. real, dimension(jm_emis), intent(in) :: field_in
  317. !
  318. ! !INPUT/OUTPUT PARAMETERS:
  319. !
  320. type(d2_data), dimension(nregions), target :: field
  321. !
  322. ! !OUTPUT PARAMETERS:
  323. !
  324. integer, intent(out) :: status
  325. !
  326. ! !REVISION HISTORY:
  327. ! 19 Jun 2012 - P. Le Sager - got rid of escape_tm
  328. !
  329. ! !REMARKS:
  330. ! (1) FIXME : should work as is for lon-lat MPI domain decomposition, but
  331. ! not tested.
  332. ! (2) This is limited to a 1 degree zonal global input [-90,+90]
  333. !
  334. !EOP
  335. !------------------------------------------------------------------------
  336. !BOC
  337. character(len=*), parameter :: rname = mname//'/coarsen_emission_1d'
  338. real, dimension(:), pointer :: coarse_field
  339. integer :: region
  340. real :: scale,w,wtot
  341. integer :: ystart
  342. integer :: yres
  343. integer :: j,j_index,jj
  344. integer :: jm_start
  345. ! start
  346. do region=1,nregions ! main loop over regions
  347. yres=dy/yref(region)
  348. if ( yres < 1 ) then
  349. write (gol,'("1 degree minimum resolution in emissions")'); call goErr
  350. status=1
  351. IF_NOTOK_RETURN(status=1)
  352. end if
  353. if ( jm_emis /= 180 ) then
  354. write (gol,'("input resolution should be 1 degree")'); call goErr
  355. status=1
  356. IF_NOTOK_RETURN(status=1)
  357. end if
  358. !WP! find index of southmost gridpoint based on 1x1 degree
  359. jm_start=ybeg(region)+91
  360. if ( jm_start <= -1 ) then
  361. write (gol,'("requested emission fields outside valid region")'); call goErr
  362. status=1
  363. IF_NOTOK_RETURN(status=1)
  364. end if
  365. coarse_field => field(region)%d2
  366. do j=1,jm(region)
  367. !cycle through 1x1 grid with steps for this region
  368. j_index=jm_start+(j-1)*yres
  369. coarse_field(j) = 0.0
  370. wtot = 0.0
  371. do jj=0,yres-1
  372. if(avg==1) then
  373. w = dxy11(j_index+jj)
  374. wtot = wtot + w
  375. coarse_field(j)=coarse_field(j) + field_in(j_index+jj)*w
  376. else
  377. coarse_field(j)=coarse_field(j) + field_in(j_index+jj)
  378. end if
  379. end do
  380. if ( avg == 1 ) coarse_field(j) = coarse_field(j)/wtot
  381. end do
  382. !if ( avg == 0 ) then
  383. ! write(gol,'(a,i1,x,a12,a,i2,a,1pe14.3)') &
  384. ! ' coarsen_emission_1d: region ',region,name_field, &
  385. ! ' Field coarsened month :',idate(2),'total:',&
  386. ! sum(coarse_field) ; call goPr
  387. !else
  388. ! write(gol,'(a,i1,x,a12,a,i2,a,1pe14.3)') &
  389. ! ' coarsen_emission_1d: region:',region,name_field, &
  390. ! ' Field averaged month :',idate(2) ; call goPr
  391. !end if
  392. nullify(coarse_field)
  393. end do ! loop over regions....
  394. end subroutine coarsen_emission_1d
  395. !EOC
  396. !--------------------------------------------------------------------------
  397. ! TM5 !
  398. !--------------------------------------------------------------------------
  399. !BOP
  400. !
  401. ! !IROUTINE: COARSEN_EMISSION_2D
  402. !
  403. ! !DESCRIPTION: Transform a 2D *global* emissions, at a given resolution,
  404. ! to the geometry of all model regions.
  405. !\\
  406. !\\
  407. ! !INTERFACE:
  408. !
  409. SUBROUTINE COARSEN_EMISSION_2D(name_field, im_emis, jm_emis, field_in, field, avg, status)
  410. !
  411. ! !USES:
  412. !
  413. use GO, only : gol, goPr, goErr
  414. use Grid, only : TllGridInfo, Init, Done, FillGrid
  415. use dims, only : nregions
  416. use global_types, only : emis_data
  417. use meteodata, only : global_lli
  418. !
  419. ! !INPUT PARAMETERS:
  420. !
  421. character(len=*), intent(in) :: name_field ! name, only for printing reasons
  422. integer, intent(in) :: im_emis, jm_emis ! grid size of global input field
  423. real, intent(in) :: field_in(im_emis,jm_emis) ! input field
  424. integer, intent(in) :: avg ! avg = 1 means that a surface area
  425. ! weighted area is calulated (e.g. land fraction)
  426. ! avg = 0 means that the sum of the underlying field
  427. ! is taken (e.g. emissions in kg/month).
  428. !
  429. ! !INPUT/OUTPUT PARAMETERS:
  430. !
  431. type(emis_data), target :: field(nregions) ! per region, %surf(im,jm)
  432. !
  433. ! !OUTPUT PARAMETERS:
  434. !
  435. integer, intent(out) :: status
  436. !
  437. ! !REVISION HISTORY:
  438. ! 28 Mar 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  439. !
  440. !EOP
  441. !------------------------------------------------------------------------
  442. !BOC
  443. character(len=*), parameter :: rname = mname//'/coarsen_emission_2d'
  444. integer :: region
  445. type(TllGridInfo) :: lli_in
  446. character(len=32) :: combkey
  447. ! --- begin ---------------------------------------
  448. ! define input grid
  449. call Init( lli_in, -180.0+0.5*360.0/im_emis, 360.0/im_emis, im_emis, &
  450. -90.0+0.5*180.0/jm_emis, 180.0/jm_emis, jm_emis, status )
  451. IF_NOTOK_RETURN(status=1)
  452. ! sum or average
  453. status=0
  454. select case ( avg )
  455. case ( 0 ) ; combkey = 'sum'
  456. case ( 1 ) ; combkey = 'area-aver'
  457. case default
  458. write (gol,'("ERROR - unsupported avg = ",i6)') avg; call goErr
  459. status=1
  460. end select
  461. IF_NOTOK_RETURN(status=1)
  462. ! main loop over regions
  463. do region = 1, nregions
  464. ! convert grid:
  465. call FillGrid( global_lli(region), 'n', field(region)%surf, &
  466. lli_in, 'n', field_in, trim(combkey), status)
  467. IF_NOTOK_RETURN(status=1)
  468. end do
  469. ! done
  470. call Done( lli_in, status )
  471. IF_NOTOK_RETURN(status=1)
  472. END SUBROUTINE COARSEN_EMISSION_2D
  473. !EOC
  474. !--------------------------------------------------------------------------
  475. ! TM5 !
  476. !--------------------------------------------------------------------------
  477. !BOP
  478. !
  479. ! !IROUTINE: COARSEN_EMISSION_3D
  480. !
  481. ! !DESCRIPTION: Transform a 3D *global* emissions, at a given resolution,
  482. ! to the geometry of all model regions.
  483. !\\
  484. !\\
  485. ! !INTERFACE:
  486. !
  487. SUBROUTINE COARSEN_EMISSION_3D( name_field, im_emis, jm_emis, lm_emis, &
  488. field_in, field, avg, status )
  489. !
  490. ! !USES:
  491. !
  492. use GO, only : gol, goPr, goErr
  493. use Grid, only : TllGridInfo, Init, Done, FillGrid
  494. use dims, only : nregions
  495. use global_types, only : d3_data
  496. use meteodata, only : global_lli
  497. !
  498. ! !INPUT PARAMETERS:
  499. !
  500. character(len=*), intent(in) :: name_field
  501. integer, intent(in) :: avg
  502. integer, intent(in) :: im_emis, jm_emis, lm_emis
  503. real, intent(in) :: field_in(im_emis,jm_emis,lm_emis)
  504. !
  505. ! !INPUT/OUTPUT PARAMETERS:
  506. !
  507. type(d3_data), target :: field(nregions) ! contains, per region, 3d field %d3(im,jm,lm)
  508. !
  509. ! !OUTPUT PARAMETERS:
  510. !
  511. integer, intent(out) :: status
  512. !
  513. ! !REVISION HISTORY:
  514. ! 28 Mar 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  515. !
  516. !EOP
  517. !------------------------------------------------------------------------
  518. !BOC
  519. character(len=*), parameter :: rname = mname//'/coarsen_emission_3d'
  520. integer :: region
  521. integer :: l
  522. type(TllGridInfo) :: lli_in
  523. character(len=32) :: combkey
  524. ! --- begin ---------------------------------------
  525. ! define input grid
  526. call Init( lli_in, -180.0+0.5*360.0/im_emis, 360.0/im_emis, im_emis, &
  527. -90.0+0.5*180.0/jm_emis, 180.0/jm_emis, jm_emis, status )
  528. IF_NOTOK_RETURN(status=1)
  529. ! sum or average
  530. status=0
  531. select case ( avg )
  532. case ( 0 ) ; combkey = 'sum'
  533. case ( 1 ) ; combkey = 'area-aver'
  534. case default
  535. write (gol,'("ERROR - unsupported avg = ",i6)') avg; call goErr
  536. status=1
  537. end select
  538. IF_NOTOK_RETURN(status=1)
  539. ! main loop over regions
  540. do region = 1, nregions
  541. ! convert grid:
  542. do l = 1, lm_emis
  543. call FillGrid( global_lli(region), 'n', field(region)%d3(:,:,l), &
  544. lli_in, 'n', field_in(:,:,l), trim(combkey), status)
  545. IF_NOTOK_RETURN(status=1)
  546. end do
  547. !! info ...
  548. !select case ( combkey )
  549. ! case ( 'aver', 'area-aver' )
  550. ! write (gol,'("coarsen_emission : region ",i1," ",a," field averaged")') &
  551. ! region, trim(name_field); call goPr
  552. ! case ( 'sum' )
  553. ! write (gol,'("coarsen_emission : region ",i1," ",a," field coarsened/distr.; total ",es12.3)') &
  554. ! region, trim(name_field), sum(field(region)%d3); call goPr
  555. ! case default
  556. ! write (gol,'("coarsen_emission : region ",i1," ",a," field coarsened/distributed")') &
  557. ! region, trim(name_field); call goPr
  558. !end select
  559. end do ! regions
  560. ! done
  561. call Done( lli_in, status )
  562. IF_NOTOK_RETURN(status=1)
  563. ! ok
  564. status = 0
  565. END SUBROUTINE COARSEN_EMISSION_3D
  566. !EOC
  567. !--------------------------------------------------------------------------
  568. ! TM5 !
  569. !--------------------------------------------------------------------------
  570. !BOP
  571. !
  572. ! !IROUTINE: COARSEN_EMISSION_D23
  573. !
  574. ! !DESCRIPTION: Transform the 2D emissions available on lat-pressure resolution
  575. ! to the desired zoom geometry
  576. !\\
  577. !\\
  578. ! !INTERFACE:
  579. !
  580. subroutine coarsen_emission_d23( name_field, jm_emis, lm_emis, &
  581. field_in, field, avg, status )
  582. !
  583. ! name_field : name, only for printing reasons
  584. ! jm_emis : the y-dimension of the input field
  585. ! lm_emis : the z-dimension of the input field
  586. ! field_in : the input field
  587. ! field : type d23_data (defined in chem_param)
  588. ! avg : flags the mode: avg = 1 means that a surface area
  589. ! weighted area is calulated (e.g. land fraction)
  590. ! avg = 0 means that the sum of the underlying field
  591. ! is taken (e.g. emissions in kg/month).
  592. !
  593. ! !USES:
  594. !
  595. use dims, only : nregions, dy, yref, ybeg, jm, lm, dxy11, idate
  596. use global_types, only : d23_data
  597. !
  598. ! !INPUT PARAMETERS:
  599. !
  600. character(len=*),intent(in) :: name_field
  601. integer,intent(in) :: avg !0=no 1=yes
  602. integer,intent(in) :: jm_emis,lm_emis
  603. real,dimension(jm_emis,lm_emis),intent(in) :: field_in
  604. !
  605. ! !INPUT/OUTPUT PARAMETERS:
  606. !
  607. type(d23_data),dimension(nregions),target :: field ! contains, per region, field %d23(jm,lm)
  608. !
  609. ! !OUTPUT PARAMETERS:
  610. !
  611. integer, intent(out) :: status
  612. !
  613. ! !REVISION HISTORY:
  614. ! 19 Jun 2012 - P. Le Sager - got rid of escape_tm
  615. !
  616. ! !REMARKS:
  617. ! (1) FIXME : should work as is for lon-lat MPI domain decomposition, but
  618. ! not tested.
  619. ! (2) First dimension of input is limited to a 1 degree global [-90,+90]
  620. !
  621. !EOP
  622. !------------------------------------------------------------------------
  623. !BOC
  624. character(len=*), parameter :: rname = mname//'/coarsen_emission_d23'
  625. real, dimension(:,:), pointer :: coarse_field
  626. integer :: region
  627. real :: scale,w,wtot
  628. integer :: ystart
  629. integer :: yres
  630. integer :: j,j_index,jj,l
  631. integer :: jm_start
  632. ! start
  633. do region=1,nregions ! main loop over regions
  634. yres=dy/yref(region)
  635. if ( yres < 1 ) then
  636. write (gol,'("1 degree minimum resolution in emissions")'); call goErr
  637. status=1
  638. IF_NOTOK_RETURN(status=1)
  639. end if
  640. if ( jm_emis /= 180 ) then
  641. write (gol,'("input resolution should be 1 degree")'); call goErr
  642. status=1
  643. IF_NOTOK_RETURN(status=1)
  644. end if
  645. !WP! find index of southmost gridpoint based on 1x1 degree
  646. jm_start=ybeg(region)+91
  647. if ( jm_start <= -1 ) then
  648. write (gol,'("requested emission fields outside valid region")'); call goErr
  649. status=1
  650. IF_NOTOK_RETURN(status=1)
  651. end if
  652. coarse_field => field(region)%d23
  653. do l=1,lm(region)
  654. do j=1,jm(region)
  655. !cycle through 1x1 grid with steps for this region
  656. j_index=jm_start+(j-1)*yres
  657. coarse_field(j,l) = 0.0
  658. wtot = 0.0
  659. do jj=0,yres-1
  660. if(avg==1) then
  661. w = dxy11(j_index+jj)
  662. wtot = wtot + w
  663. coarse_field(j,l)=coarse_field(j,l) + &
  664. field_in(j_index+jj,l)*w
  665. else
  666. coarse_field(j,l)=coarse_field(j,l) + &
  667. field_in(j_index+jj,l)
  668. end if
  669. end do
  670. if ( avg == 1 ) coarse_field(j,l) = coarse_field(j,l)/wtot
  671. end do !j
  672. end do !l
  673. !if ( avg == 0 ) then
  674. !
  675. ! write(gol,'(a,i1,x,a12,a,i2,a,1pe14.3)') &
  676. ! ' coarsen_emission_d23: region ',region,name_field// &
  677. ! ' Field coarsened month ',idate(2),' total ',&
  678. ! sum(coarse_field); call goPr
  679. !else
  680. ! write(gol,'(a,i1,x,a12,a,i2,a,1pe14.3)') &
  681. ! ' coarsen_emission_d23: region ',region,name_field// &
  682. ! ' Field averaged month ',idate(2); call goPr
  683. !end if
  684. nullify(coarse_field)
  685. end do ! loop over regions....
  686. end subroutine coarsen_emission_d23
  687. !EOC
  688. !--------------------------------------------------------------------------
  689. ! TM5 !
  690. !--------------------------------------------------------------------------
  691. !BOP
  692. !
  693. ! !IROUTINE: ESCAPE_TM
  694. !
  695. ! !DESCRIPTION: abnormal termination of a model run
  696. !\\
  697. !\\
  698. ! !INTERFACE:
  699. !
  700. subroutine escape_tm( msg )
  701. !
  702. ! !USES:
  703. !
  704. use GO, only : GO_Print_Done
  705. use dims, only : okdebug, kmain, itau
  706. use datetime, only : wrtgol_tstamp
  707. use partools, only : Par_StopMPI
  708. #ifdef with_prism
  709. #ifdef oasis3
  710. use mod_oasis
  711. #endif
  712. use TM5_Prism, only : comp_id
  713. #endif
  714. !
  715. ! !INPUT PARAMETERS:
  716. !
  717. character(len=*), intent(in) :: msg ! character string to be printed on unit gol
  718. !
  719. ! !REVISION HISTORY:
  720. ! 19 Jun 2012 - P. Le Sager - use par_stopmpi instead of stop; protex
  721. !
  722. !EOP
  723. !------------------------------------------------------------------------
  724. !BOC
  725. character(len=*), parameter :: rname = mname//'/escape_tm'
  726. integer :: status
  727. ! --- begin ---------------------------
  728. write (gol,'(1x,39("--"))'); call goErr
  729. write (gol,'(1x,39("--"))'); call goErr
  730. call wrtgol_tstamp(itau,'ERROR - ESCAPE_TM'); call goErr
  731. write (gol,'(1x,a)') trim(msg); call goErr
  732. write (gol,'(1x,39("--"))'); call goErr
  733. write (gol,'(1x,39("--"))'); call goErr
  734. ! try to display at least the messages in a proper way ...
  735. call GO_Print_Done( status )
  736. if (status/=0) write (*,'("ERROR status from GO_Print_Done : ",i6)') status
  737. #ifdef with_prism
  738. #ifdef oasis3
  739. call oasis_abort( comp_id, rname, 'called prism_abort' )
  740. #endif
  741. #endif
  742. call Par_StopMPI
  743. end subroutine escape_tm
  744. !EOC
  745. !-----------------------------------------------------------------------
  746. ! TM5 !
  747. !-----------------------------------------------------------------------
  748. !BOP
  749. !
  750. ! !IROUTINE: DISTRIBUTE_EMIS2D
  751. !
  752. ! !DESCRIPTION: subroutine to distribute the emissions given as a TM5 2D field
  753. ! into a TM5 3D emission field. Hlow and Hhigh are the bounds of
  754. ! the 2D emission fields. They give the height RELATIVE to oro
  755. ! From that the distribution is calculated
  756. ! employing the geopotential height (relative to oro)
  757. !\\
  758. !\\
  759. ! !INTERFACE:
  760. !
  761. SUBROUTINE DISTRIBUTE_EMIS2D( region, emis2D, emis3D, hlow, hhigh, status, xfrac, lat_start, lat_end)
  762. !
  763. ! !USES:
  764. !
  765. use tm5_distgrid, only : Get_DistGrid, dgrid
  766. use dims, only : lm, im, jm, dy, yref, ybeg
  767. use meteodata, only : gph_dat
  768. use global_types, only : d3_data, emis_data
  769. !
  770. ! !INPUT PARAMETERS:
  771. !
  772. integer, intent(in) :: region
  773. type(emis_data), intent(in), target :: emis2D ! 2D emission field (kg/gridbox/month)
  774. type(d3_data), intent(inout), target :: emis3D ! 3D emission field (kg/gridbox/month)
  775. real, intent(in) :: hlow ! lowest level (m)
  776. real, intent(in) :: hhigh ! highest level (m)
  777. !
  778. ! !OUTPUT PARAMETERS:
  779. !
  780. integer, intent(out) :: status
  781. real, intent(in), optional :: xfrac ! fraction of emissions to put b/w HLOW and HHIGH (default=1)
  782. real, intent(in), optional :: lat_start ! lower limit (default=-90) of application domain
  783. real, intent(in), optional :: lat_end ! upper limit (default=+90) of application domain
  784. !
  785. ! !REVISION HISTORY:
  786. ! 16 Jul 2010 - Achim Strunk - Added Lat_start and lat_end optional inputs.
  787. ! 27 Mar 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  788. !
  789. !EOP
  790. !----------------------------------------------------------------------
  791. !BOC
  792. character(len=*), parameter :: rname = mname//'/distribute_emis2D'
  793. real, dimension(:,:,:),pointer :: gph ! geopotential height (m)
  794. real, dimension(:,:,:),pointer :: e3d ! 3D emissions
  795. real, dimension(:,:),pointer :: e2d ! 2D emissions
  796. integer :: i,j,l,j_st,j_end
  797. real, dimension(lm(1)+1) :: height
  798. real, dimension(lm(1)) :: dz
  799. real :: dy1,dze
  800. real :: totw, f, tot2d, tot3db, tot3da, fraction
  801. integer, dimension(3) :: ubound_e3d
  802. integer :: lmmax
  803. real :: hhighb
  804. real :: lat_low,lat_high
  805. integer :: i1, i2, j1, j2
  806. real :: l_status, g_status
  807. ! --- begin ---------------------------------------------
  808. status = 0
  809. if (present(xfrac)) then
  810. fraction = xfrac
  811. else
  812. fraction = 1.0
  813. endif
  814. if (fraction < spacing(fraction)) return ! degenerated cases
  815. if (present(lat_start)) then
  816. lat_low = lat_start
  817. else
  818. lat_low = -90.
  819. endif
  820. if (present(lat_end)) then
  821. lat_high = lat_end
  822. else
  823. lat_high = 90.
  824. endif
  825. CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  826. ! get indices of application-region
  827. dy1=dy/yref(region)
  828. j_st = floor((lat_low - ybeg(region))/dy1) + 1
  829. j_end = floor((lat_high - ybeg(region))/dy1) + 1
  830. ! is tile in appl. region?
  831. if ((j_end .lt. j1 ) .or. (j_st .gt. j2) ) then
  832. return
  833. end if
  834. ! limit range
  835. if (j_end .gt. j2 ) j_end = j2
  836. if (j_st .lt. j1 ) j_st = j1
  837. ! check inputs
  838. dze = hhigh - hlow
  839. if ( (hhigh <= 0.0) .or. (hlow < 0.0) .or. (dze < 0.0) ) then
  840. write (gol,'("found strange emission heights:")'); call goErr
  841. write (gol,'(" hhigh (> 0.0 ?) : ",es12.4)') hhigh; call goErr
  842. write (gol,'(" hlow (>= 0.0 ?) : ",es12.4)') hlow; call goErr
  843. write (gol,'(" hhigh-hlow (> 0.0 ?) : ",es12.4)') dze; call goErr
  844. TRACEBACK; status=1; return
  845. end if
  846. ! init
  847. nullify(gph)
  848. nullify(e2d)
  849. nullify(e3d)
  850. gph => gph_dat(region)%data
  851. e2d => emis2d%surf
  852. e3d => emis3d%d3
  853. ! get highest possible level
  854. ubound_e3d = ubound(e3d)
  855. lmmax = ubound_e3d(3)
  856. ! total of to-be-redistributed before redistribution
  857. tot2d = sum(e2d(:,j_st:j_end)*fraction)
  858. ! total of target array before adding redistributed data
  859. tot3db = sum(e3d(:,j_st:j_end,:))
  860. ! do work
  861. jlo: do j=j_st,j_end
  862. do i=i1, i2
  863. ! zero based height:
  864. height(1) = 0.0
  865. do l=1, lm(region)
  866. dz(l) = gph(i,j,l+1) - gph(i,j,l)
  867. height(l+1) = height(l) + dz(l)
  868. enddo
  869. totw = 0.0
  870. if( hhigh > height(lmmax+1) ) then
  871. write (gol,'("try to put emissions higher than array allows:")') ; call goErr
  872. write (gol,'(" hhigh : ",es12.4)') hhigh ; call goErr
  873. write (gol,'(" height(lmmax+1) : ",es12.4)') height(lmmax+1) ; call goErr
  874. write (gol,'(" at i/j=",i3,1x,i3)') i,j ; call goErr
  875. do l = 1, size(height)
  876. write (gol,*) 'height : ', l, height(l); call goErr
  877. end do
  878. do l = 1, size(gph,3)
  879. write (gol,*) 'gph : ', l, gph(i,j,l); call goErr
  880. end do
  881. TRACEBACK; status=1
  882. exit jlo
  883. endif
  884. zz: do l=1, lmmax
  885. if (hhigh > height(l+1)) then
  886. if ( hlow < height(l) ) then
  887. f = dz(l)/dze
  888. totw = totw + f
  889. e3d(i,j,l) = e3d(i,j,l) + f*fraction*e2d(i,j)
  890. else if( hlow < height(l+1)) then
  891. f = (height(l+1)-hlow)/dze
  892. totw = totw + f
  893. e3d(i,j,l) = e3d(i,j,l) + f*fraction*e2d(i,j)
  894. endif
  895. else
  896. if ( hlow < height(l)) then
  897. f = (hhigh - height(l))/dze
  898. totw = totw + f
  899. e3d(i,j,l) = e3d(i,j,l) + f*fraction*e2d(i,j)
  900. else
  901. totw = totw + 1.0
  902. e3d(i,j,l) = e3d(i,j,l) + fraction*e2d(i,j)
  903. endif
  904. exit zz
  905. endif
  906. enddo zz
  907. if ( abs(totw-1.0) > 1e-14 ) then
  908. write (gol,'("sum weight /= 1 : ",es12.4)') totw-1.0; call goErr
  909. TRACEBACK; status=1
  910. exit jlo
  911. end if
  912. enddo !i
  913. enddo jlo !j
  914. IF_NOTOK_RETURN(status=1)
  915. ! Total of target array after adding redistributed data, and check
  916. ! DO NOT FIXME ?? : the following test will fail if tot2d << tot3da (strictly: if
  917. ! tot2d is less than the last significant digit of tot3da). However this
  918. ! is good, since we actually expect that tot3da to be 0 (as used in
  919. ! chemistry): so we can catch some bad initialization.
  920. tot3da = sum(e3d(:,j_st:j_end,:))
  921. if (abs((tot3da-tot3db)-tot2d) > 1e-8*abs(tot2d) ) then
  922. write (gol,'("emissions have not been distributed mass-conserving")'); call goErr
  923. write(gol,*)"totals to add : ", tot2d, tot3db ; call goErr
  924. write(gol,*)"total after : ", tot3da ; call goErr
  925. write(gol,*)"with bounds : ", j1, j2, j_st, j_end; call goErr
  926. write(gol,*)"shapes e3d",shape(e3d) ; call goErr
  927. write(gol,*)"lbound e3d",lbound(e3d); call goErr
  928. write(gol,*)"ubound e3d",ubound(e3d); call goErr
  929. write(gol,*)"minmax e3d",minval(e3d), maxval(e3d); call goErr
  930. write(gol,*)"shapes e2d",shape(e2d) ; call goErr
  931. write(gol,*)"lbound e2d",lbound(e2d); call goErr
  932. write(gol,*)"ubound e2d",ubound(e2d); call goErr
  933. write(gol,*)"minmax e2d",minval(e2d), maxval(e2d); call goErr
  934. TRACEBACK; status=1; return
  935. end if
  936. ! done
  937. nullify(gph)
  938. nullify(e2d)
  939. nullify(e3d)
  940. END SUBROUTINE DISTRIBUTE_EMIS2D
  941. !EOC
  942. !---------------------------------------------------------------------------
  943. ! TM5 !
  944. !---------------------------------------------------------------------------
  945. !BOP
  946. !
  947. ! !IROUTINE: distribute1x1
  948. !
  949. ! !DESCRIPTION: subroutine to distribute 1x1 emissions linearly between
  950. ! hlow and hhigh. The vertical level is determined by
  951. ! the orography which is read from the surface file...
  952. ! A simple scale height vertical structure is assumed.
  953. !
  954. ! To be called by one processor, with a global 2D oro input
  955. !\\
  956. !\\
  957. ! !INTERFACE:
  958. !
  959. SUBROUTINE DISTRIBUTE1X1( emi1x1, hlow, hhigh, emis3d, oro, status, xfrac)
  960. !
  961. ! !USES:
  962. !
  963. use Binas, only : grav
  964. use dims, only : nlon360, nlat180, lm, itau, staggered, at, bt
  965. !
  966. ! !INPUT PARAMETERS:
  967. !
  968. real, dimension(nlon360,nlat180), intent(in) :: emi1x1 ! (kg/1x1 gridbox) 2D field of emissions
  969. real, dimension(nlon360,nlat180), intent(in) :: hlow ! (m) lower bound of emission
  970. real, dimension(nlon360,nlat180), intent(in) :: hhigh ! (m) higher bound of emission
  971. real, dimension(nlon360,nlat180), intent(in) :: oro ! (m m/s2)
  972. real, intent(in), optional :: xfrac ! fraction of emissions to put
  973. !
  974. ! !INPUT/OUTPUT PARAMETERS:
  975. !
  976. real, dimension(nlon360,nlat180,lm(1)), intent(inout) :: emis3d ! (kg/box) distributed in height
  977. integer, intent(out) :: status
  978. !
  979. ! !REVISION HISTORY:
  980. ! 8 May 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  981. !
  982. !EOP
  983. !------------------------------------------------------------------------
  984. !BOC
  985. character(len=*), parameter :: rname = mname//'/distribute1x1'
  986. real, parameter :: scalh = 8000.0
  987. real :: p0, pt
  988. real, dimension(lm(1)) :: height, dz
  989. integer :: i,j,l
  990. real :: hh,hl,dze,totw,f,e3da,e3db, fract
  991. ! --- begin -----------------------------------
  992. if (present(xfrac)) then
  993. fract = xfrac
  994. else
  995. fract = 1.0
  996. endif
  997. e3db = sum(emis3d)
  998. do j=1,nlat180
  999. do i=1,nlon360
  1000. if (fract*emi1x1(i,j) > 1e-14) then
  1001. height(1) = oro(i,j)/grav
  1002. p0 = 1e5*exp(-height(1)/scalh)
  1003. do l=1,lm(1)-1 ! bug reported by FD: alog(0) crashes!
  1004. pt = at(l+1) + bt(l+1)*p0
  1005. height(l+1) = height(1)-scalh*alog(pt/p0)
  1006. dz(l) = height(l+1)-height(l)
  1007. enddo
  1008. hl = max(height(1),hlow(i,j))
  1009. hh = max(hhigh(i,j),height(1))
  1010. dze = hh-hl
  1011. if(dze < 0.0) then
  1012. status=1
  1013. IF_NOTOK_RETURN(status=1)
  1014. else if ( dze == 0.0) then ! this somehow happens!
  1015. hh = height(1)+1.0
  1016. hl = height(1)
  1017. endif
  1018. totw = 0.0
  1019. zz: do l=1, lm(1)
  1020. if (hh > height(l+1)) then
  1021. if ( hl < height(l) ) then
  1022. f = dz(l)/dze
  1023. totw = totw + f
  1024. emis3d(i,j,l) = emis3d(i,j,l) + f*fract*emi1x1(i,j)
  1025. else if( hl < height(l+1)) then
  1026. f = (height(l+1)-hl)/dze
  1027. totw = totw + f
  1028. emis3d(i,j,l) = emis3d(i,j,l) + f*fract*emi1x1(i,j)
  1029. endif
  1030. else
  1031. if ( hl < height(l)) then
  1032. f = (hh - height(l))/dze
  1033. totw = totw + f
  1034. emis3d(i,j,l) = emis3d(i,j,l) + f*fract*emi1x1(i,j)
  1035. else
  1036. totw = totw + 1.0
  1037. emis3d(i,j,l) = emis3d(i,j,l) + fract*emi1x1(i,j)
  1038. endif
  1039. exit zz
  1040. endif
  1041. enddo zz
  1042. if ( abs(totw-1.0) > 1e-14 ) then
  1043. status=1
  1044. IF_NOTOK_RETURN(status=1)
  1045. end if
  1046. endif
  1047. enddo
  1048. enddo
  1049. e3da = sum(emis3d)
  1050. if (abs(e3da-e3db-sum(fract*emi1x1)) > e3da*1e-8 ) then
  1051. status=1
  1052. IF_NOTOK_RETURN(status=1)
  1053. end if
  1054. status=0
  1055. END SUBROUTINE DISTRIBUTE1X1
  1056. !EOC
  1057. !--------------------------------------------------------------------------
  1058. ! TM5 !
  1059. !--------------------------------------------------------------------------
  1060. !BOP
  1061. !
  1062. ! !IROUTINE: DISTRIBUTE1X1B
  1063. !
  1064. ! !DESCRIPTION: same as DISTRIBUTE1X1, but with scalar for HLOW and HHIGH
  1065. !
  1066. ! Is it still used ????
  1067. !
  1068. ! subroutine to distribute 1x1 emissions linearly between
  1069. ! hlow and hhigh. The vertical level is determined by
  1070. ! the orography which is read from the surface file...
  1071. ! A simple scale height vertical structure is assumed.
  1072. ! same as distribute1x1 but hlow, hhigh now scalar
  1073. ! ALSO: the height is now defined relative to the orography!
  1074. !\\
  1075. !\\
  1076. ! !INTERFACE:
  1077. !
  1078. SUBROUTINE DISTRIBUTE1X1B( emi1x1, hlow, hhigh, emis3d, oro, status, xfrac)
  1079. !
  1080. ! !USES:
  1081. !
  1082. use Binas, only : grav
  1083. use dims, only : nlon360, nlat180, lm, itau, staggered, at, bt
  1084. !
  1085. ! !INPUT PARAMETERS:
  1086. !
  1087. real, dimension(nlon360,nlat180), intent(in) :: emi1x1 ! (kg/1x1 gridbox) 2D field of emissions
  1088. real, intent(in) :: hlow ! (m) lower bound of emission
  1089. real, intent(in) :: hhigh ! (m) higher bound of emission
  1090. real, dimension(nlon360,nlat180), intent(in) :: oro ! (m m/s2)
  1091. real, intent(in), optional :: xfrac ! fraction of emissions to put
  1092. !
  1093. ! !INPUT/OUTPUT PARAMETERS:
  1094. !
  1095. real, dimension(nlon360,nlat180,lm(1)), intent(inout) :: emis3d ! (kg/box) distributed in height
  1096. integer, intent(out) :: status
  1097. !
  1098. ! !REVISION HISTORY:
  1099. ! 8 May 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  1100. !
  1101. !EOP
  1102. !------------------------------------------------------------------------
  1103. !BOC
  1104. character(len=*), parameter :: rname = mname//'/distribute1x1b'
  1105. real, parameter :: scalh = 8000.0
  1106. real :: p0, pt
  1107. real, dimension(lm(1)) :: height, dz
  1108. integer :: i,j,l
  1109. real :: hh,hl,dze,totw,f,e3da,e3db, fract, hlow_oro, hhigh_oro
  1110. ! --- begin -----------------------------------
  1111. if (present(xfrac)) then
  1112. fract = xfrac
  1113. else
  1114. fract = 1.0
  1115. endif
  1116. e3db = sum(emis3d)
  1117. do j=1,nlat180
  1118. do i=1,nlon360
  1119. if (fract*emi1x1(i,j) > 1e-14) then
  1120. height(1) = oro(i,j)/grav
  1121. hlow_oro = hlow + height(1)
  1122. hhigh_oro = hhigh + height(1)
  1123. p0 = 1e5*exp(-height(1)/scalh)
  1124. do l=1,lm(1)-1 ! bug reported by FD: alog(0) crashes!
  1125. pt = at(l+1) + bt(l+1)*p0
  1126. height(l+1) = height(1)-scalh*alog(pt/p0)
  1127. dz(l) = height(l+1)-height(l)
  1128. enddo
  1129. hl = max(height(1),hlow_oro)
  1130. hh = max(hhigh_oro,height(1))
  1131. dze = hh-hl
  1132. if(dze < 0.0) then
  1133. status=1
  1134. IF_NOTOK_RETURN(status=1)
  1135. else if ( dze == 0.0) then ! this somehow happens!
  1136. hh = height(1)+1.0
  1137. hl = height(1)
  1138. endif
  1139. totw = 0.0
  1140. zz: do l=1, lm(1)
  1141. if (hh > height(l+1)) then
  1142. if ( hl < height(l) ) then
  1143. f = dz(l)/dze
  1144. totw = totw + f
  1145. emis3d(i,j,l) = emis3d(i,j,l) + f*fract*emi1x1(i,j)
  1146. else if( hl < height(l+1)) then
  1147. f = (height(l+1)-hl)/dze
  1148. totw = totw + f
  1149. emis3d(i,j,l) = emis3d(i,j,l) + f*fract*emi1x1(i,j)
  1150. endif
  1151. else
  1152. if ( hl < height(l)) then
  1153. f = (hh - height(l))/dze
  1154. totw = totw + f
  1155. emis3d(i,j,l) = emis3d(i,j,l) + f*fract*emi1x1(i,j)
  1156. else
  1157. totw = totw + 1.0
  1158. emis3d(i,j,l) = emis3d(i,j,l) + fract*emi1x1(i,j)
  1159. endif
  1160. exit zz
  1161. endif
  1162. enddo zz
  1163. if ( abs(totw-1.0) > 1e-14 ) then
  1164. status=1
  1165. IF_NOTOK_RETURN(status=1)
  1166. end if
  1167. endif
  1168. enddo
  1169. enddo
  1170. e3da = sum(emis3d)
  1171. if (abs(e3da-e3db-sum(fract*emi1x1)) > e3da*1e-8 ) then
  1172. status=1
  1173. IF_NOTOK_RETURN(status=1)
  1174. end if
  1175. status=0
  1176. END SUBROUTINE DISTRIBUTE1X1B
  1177. !EOC
  1178. !--------------------------------------------------------------------------
  1179. ! TM5 !
  1180. !--------------------------------------------------------------------------
  1181. !BOP
  1182. !
  1183. ! !IROUTINE: TROPOSPHERIC_COLUMNS
  1184. !
  1185. ! !DESCRIPTION: Routine to integrate tropospheric (ozone)
  1186. ! note: routine is now written for Ozone, but may be changed
  1187. ! to be more general. The definition of tropopause is critical for ozone.
  1188. ! here, the slope is used in the interpolation.
  1189. ! multiple tropopause values are ignored, but are known to
  1190. ! occur. The lowest crossing of thres is used.
  1191. ! In the lower atmosphere > 600 hPa, values > thres are ignored.
  1192. !\\
  1193. !\\
  1194. ! !INTERFACE:
  1195. !
  1196. subroutine tropospheric_columns(region, field, slope, column, thres, xmo3, status)
  1197. !
  1198. ! !USES:
  1199. !
  1200. use binas, only : Dobs, xmair, Avog
  1201. use global_data, only : region_dat
  1202. use meteodata, only : phlb_dat, m_dat
  1203. use Dims, only : lm, isr, ier, jsr, jer, CheckShape, im, jm
  1204. !
  1205. ! !INPUT PARAMETERS:
  1206. !
  1207. integer, intent(in) :: region ! region in the TM5 zoom definition
  1208. real, dimension(:,:,:), intent(in) :: field ! 3D field of tracer (O3)
  1209. real, dimension(:,:,:), intent(in) :: slope ! 3D field of tracer z -slope (O3)
  1210. !
  1211. ! !OUTPUT PARAMETERS:
  1212. !
  1213. real, dimension(:,:),intent(out) :: column ! output: tropospheric column in DU
  1214. real, intent(in) :: thres ! ppb threshold for tropospheric column
  1215. real, intent(in) :: xmo3 ! mol mass tracer
  1216. integer, intent(out) :: status
  1217. !
  1218. ! !REVISION HISTORY:
  1219. ! 19 Jun 2012 - P. Le Sager - fix calls to CheckShape
  1220. !
  1221. ! !REMARKS:
  1222. ! (1) FIXME : must be adapted for lon-lat MPI domain decomposition
  1223. !
  1224. !EOP
  1225. !------------------------------------------------------------------------
  1226. !BOC
  1227. character(len=*), parameter :: rname = mname//'/tropospheric_columns'
  1228. #ifdef with_zoom
  1229. integer,dimension(:,:),pointer :: zoomed
  1230. #endif
  1231. real,dimension(:,:,:),pointer :: m
  1232. real,dimension(:,:,:),pointer :: phlb
  1233. real,dimension(:),pointer :: dxyp
  1234. real, dimension(2*lm(1)+1) :: o3a
  1235. real :: o3mm, o3mmu, o3mml, o3trop, o3ml, o3mu, frac
  1236. integer :: i,j,l,ip
  1237. ! FIXME
  1238. write (gol,'("ERROR - routine not converted to TM5-MP")') ; call goErr
  1239. status=1
  1240. IF_NOTOK_RETURN(status=1)
  1241. ! start
  1242. call CheckShape( (/im(region),jm(region)/), shape(column), status )
  1243. call CheckShape( (/im(region),jm(region), lm(region)/), shape(field), status )
  1244. call CheckShape( (/im(region),jm(region), lm(region)/), shape(slope), status )
  1245. dxyp=> region_dat(region)%dxyp
  1246. #ifdef with_zoom
  1247. zoomed => region_dat(region)%zoomed
  1248. #endif
  1249. phlb => phlb_dat(region)%data
  1250. m => m_dat(region)%data
  1251. ! collect ozone on mid levels and at boundaries
  1252. ! average the estimates from upper/lower gridboxes
  1253. ! except for bottom and top.
  1254. !
  1255. column(:,:) = 0.0
  1256. do j=jsr(region), jer(region)
  1257. do i=isr(region), ier(region)
  1258. #ifdef with_zoom
  1259. if(zoomed(i,j)/=region) cycle
  1260. #endif
  1261. do l=1,lm (region)
  1262. ip = 2*l-1
  1263. o3mm = xmair/xmo3*1e9*field(i,j,l)/m(i,j,l) ! level
  1264. o3mmu = xmair/xmo3*1e9*(field(i,j,l)+slope(i,j,l))/m(i,j,l) ! top
  1265. o3mml = xmair/xmo3*1e9*(field(i,j,l)-slope(i,j,l))/m(i,j,l) ! bottom
  1266. if(l == 1) then
  1267. o3a(ip) = o3mml
  1268. else
  1269. o3a(ip) = o3a(ip) + 0.5*o3mml
  1270. endif
  1271. o3a(ip+1) = o3mm
  1272. if(l == lm(region)) then
  1273. o3a(ip+2) = o3mmu
  1274. else
  1275. o3a(ip+2) = 0.5*o3mmu
  1276. endif
  1277. enddo
  1278. o3trop = 0.0
  1279. height: do l=1,lm (region)
  1280. ip = 2*l-1
  1281. ! split gridbox in upper and lower part
  1282. ! for more accurate interpolation
  1283. o3ml = 0.5*field(i,j,l) - 0.25*slope(i,j,l)
  1284. o3mu = 0.5*field(i,j,l) + 0.25*slope(i,j,l)
  1285. if (phlb(i,j,l) > 60000.0) then ! avoid surface o3>150ppb
  1286. o3trop = o3trop + field(i,j,l)
  1287. cycle height
  1288. endif
  1289. if (phlb(i,j,l+1) < 7000.0) exit height ! now about time 70 hPa at top
  1290. if(o3a(ip) < thres) then ! bottom value less than thres
  1291. if(o3a(ip+1) >= thres) then ! but central value is not
  1292. frac = (thres - o3a(ip))/(o3a(ip+1)-o3a(ip))
  1293. o3trop = o3trop + frac*o3ml
  1294. exit height
  1295. else if (o3a(ip+2) >= thres) then ! but upper is not
  1296. frac = (thres - o3a(ip+1))/(o3a(ip+2)-o3a(ip+1))
  1297. o3trop = o3trop + o3ml + frac*o3mu
  1298. exit height
  1299. else ! entire layer is not
  1300. o3trop = o3trop + field(i,j,l)
  1301. endif
  1302. else
  1303. exit height
  1304. endif
  1305. enddo height
  1306. column(i,j) = o3trop*1e3/xmo3*Avog*1e-4/dxyp(j)/Dobs ! kg ->dobs
  1307. enddo ! i
  1308. enddo !j
  1309. call dumpfield(0,'dump.hdf', im(region), jm(region), lm(region), 1, field, 'o3')
  1310. call dumpfield(1,'dump.hdf', im(region), jm(region), lm(region), 1, slope, 'o3slope')
  1311. call dumpfield(1,'dump.hdf', im(region), jm(region), 1, 1, column, 'o3column')
  1312. call dumpfield(1,'dump.hdf', im(region), jm(region), lm(region)+1, 1, phlb, 'phlb')
  1313. call dumpfield(1,'dump.hdf', im(region), jm(region), lm(region), 1, m, 'm')
  1314. call dumpfield(1,'dump.hdf', jm(region),1, 1, 1, dxyp, 'dxyp')
  1315. nullify(dxyp)
  1316. #ifdef with_zoom
  1317. nullify(zoomed)
  1318. #endif
  1319. nullify(phlb)
  1320. nullify(m)
  1321. end subroutine tropospheric_columns
  1322. !EOC
  1323. END MODULE TOOLBOX