toolbox.F90 52 KB

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